log level & syslog

Co-Authored-By: Alireza Ahmadi <alireza7@gmail.com>
This commit is contained in:
MHSanaei 2023-07-31 20:11:47 +03:30
parent c46ced0c4c
commit bf971911d5
5 changed files with 103 additions and 85 deletions

View file

@ -1,98 +1,118 @@
package logger package logger
import ( import (
"fmt"
"os" "os"
"sync" "time"
"github.com/op/go-logging" "github.com/op/go-logging"
) )
var ( var logger *logging.Logger
logger *logging.Logger var logBuffer []struct {
mu sync.Mutex time string
) level logging.Level
log string
}
func init() { func init() {
InitLogger(logging.INFO) InitLogger(logging.INFO)
} }
func InitLogger(level logging.Level) { func InitLogger(level logging.Level) {
mu.Lock() newLogger := logging.MustGetLogger("x-ui")
defer mu.Unlock() var err error
var backend logging.Backend
var format logging.Formatter
ppid := os.Getppid()
if logger != nil { if ppid == 1 {
return backend, err = logging.NewSyslogBackend("")
format = logging.MustStringFormatter(
`%{level} - %{message}`,
)
} }
if err != nil || ppid != 1 {
format := logging.MustStringFormatter( backend = logging.NewLogBackend(os.Stderr, "", 0)
format = logging.MustStringFormatter(
`%{time:2006/01/02 15:04:05} %{level} - %{message}`, `%{time:2006/01/02 15:04:05} %{level} - %{message}`,
) )
newLogger := logging.MustGetLogger("x-ui") }
backend := logging.NewLogBackend(os.Stderr, "", 0)
backendFormatter := logging.NewBackendFormatter(backend, format) backendFormatter := logging.NewBackendFormatter(backend, format)
backendLeveled := logging.AddModuleLevel(backendFormatter) backendLeveled := logging.AddModuleLevel(backendFormatter)
backendLeveled.SetLevel(level, "") backendLeveled.SetLevel(level, "x-ui")
newLogger.SetBackend(logging.MultiLogger(backendLeveled)) newLogger.SetBackend(backendLeveled)
logger = newLogger logger = newLogger
} }
func Debug(args ...interface{}) { func Debug(args ...interface{}) {
if logger != nil {
logger.Debug(args...) logger.Debug(args...)
} addToBuffer("DEBUG", fmt.Sprint(args...))
} }
func Debugf(format string, args ...interface{}) { func Debugf(format string, args ...interface{}) {
if logger != nil {
logger.Debugf(format, args...) logger.Debugf(format, args...)
} addToBuffer("DEBUG", fmt.Sprintf(format, args...))
} }
func Info(args ...interface{}) { func Info(args ...interface{}) {
if logger != nil {
logger.Info(args...) logger.Info(args...)
} addToBuffer("INFO", fmt.Sprint(args...))
} }
func Infof(format string, args ...interface{}) { func Infof(format string, args ...interface{}) {
if logger != nil {
logger.Infof(format, args...) logger.Infof(format, args...)
} addToBuffer("INFO", fmt.Sprintf(format, args...))
} }
func Warning(args ...interface{}) { func Warning(args ...interface{}) {
if logger != nil {
logger.Warning(args...) logger.Warning(args...)
} addToBuffer("WARNING", fmt.Sprint(args...))
} }
func Warningf(format string, args ...interface{}) { func Warningf(format string, args ...interface{}) {
if logger != nil {
logger.Warningf(format, args...) logger.Warningf(format, args...)
} addToBuffer("WARNING", fmt.Sprintf(format, args...))
} }
func Error(args ...interface{}) { func Error(args ...interface{}) {
if logger != nil {
logger.Error(args...) logger.Error(args...)
} addToBuffer("ERROR", fmt.Sprint(args...))
} }
func Errorf(format string, args ...interface{}) { func Errorf(format string, args ...interface{}) {
if logger != nil {
logger.Errorf(format, args...) logger.Errorf(format, args...)
} addToBuffer("ERROR", fmt.Sprintf(format, args...))
} }
func Notice(args ...interface{}) { func addToBuffer(level string, newLog string) {
if logger != nil { t := time.Now()
logger.Notice(args...) if len(logBuffer) >= 10240 {
} logBuffer = logBuffer[1:]
} }
func Noticef(format string, args ...interface{}) { logLevel, _ := logging.LogLevel(level)
if logger != nil { logBuffer = append(logBuffer, struct {
logger.Noticef(format, args...) time string
level logging.Level
log string
}{
time: t.Format("2006/01/02 15:04:05"),
level: logLevel,
log: newLog,
})
}
func GetLogs(c int, level string) []string {
var output []string
logLevel, _ := logging.LogLevel(level)
for i := len(logBuffer) - 1; i >= 0 && len(output) <= c; i-- {
if logBuffer[i].level <= logLevel {
output = append(output, fmt.Sprintf("%s %s - %s", logBuffer[i].time, logBuffer[i].level, logBuffer[i].log))
} }
} }
return output
}

View file

@ -402,7 +402,7 @@ class HttpStreamSettings extends XrayCommonClass {
} }
static fromJson(json={}) { static fromJson(json={}) {
return new HttpStreamSettings(json.path, json.host, json.sockopt); return new HttpStreamSettings(json.path, json.host);
} }
toJson() { toJson() {
@ -461,8 +461,7 @@ class GrpcStreamSettings extends XrayCommonClass {
static fromJson(json={}) { static fromJson(json={}) {
return new GrpcStreamSettings( return new GrpcStreamSettings(
json.serviceName, json.serviceName,
json.multiMode, json.multiMode
json.sockopt
); );
} }

View file

@ -118,12 +118,9 @@ func (a *ServerController) restartXrayService(c *gin.Context) {
func (a *ServerController) getLogs(c *gin.Context) { func (a *ServerController) getLogs(c *gin.Context) {
count := c.Param("count") count := c.Param("count")
logLevel := c.PostForm("logLevel") level := c.PostForm("level")
logs, err := a.serverService.GetLogs(count, logLevel) syslog := c.PostForm("syslog")
if err != nil { logs := a.serverService.GetLogs(count, level, syslog)
jsonMsg(c, "getLogs", err)
return
}
jsonObj(c, logs, nil) jsonObj(c, logs, nil)
} }

View file

@ -86,7 +86,7 @@
<a-col :sm="24" :md="12"> <a-col :sm="24" :md="12">
<a-card hoverable :class="themeSwitcher.darkCardClass"> <a-card hoverable :class="themeSwitcher.darkCardClass">
{{ i18n "menu.link" }}: {{ i18n "menu.link" }}:
<a-tag color="blue" style="cursor: pointer;" @click="openLogs(logModal.rows, logModal.logLevel)">{{ i18n "pages.index.logs" }}</a-tag> <a-tag color="blue" style="cursor: pointer;" @click="openLogs()">{{ i18n "pages.index.logs" }}</a-tag>
<a-tag color="blue" style="cursor: pointer;" @click="openConfig">{{ i18n "pages.index.config" }}</a-tag> <a-tag color="blue" style="cursor: pointer;" @click="openConfig">{{ i18n "pages.index.config" }}</a-tag>
<a-tag color="blue" style="cursor: pointer;" @click="openBackup">{{ i18n "pages.index.backup" }}</a-tag> <a-tag color="blue" style="cursor: pointer;" @click="openBackup">{{ i18n "pages.index.backup" }}</a-tag>
</a-card> </a-card>
@ -253,7 +253,7 @@
<a-form-item label="Count"> <a-form-item label="Count">
<a-select v-model="logModal.rows" <a-select v-model="logModal.rows"
style="width: 80px" style="width: 80px"
@change="openLogs(logModal.rows, logModal.logLevel)" @change="openLogs()"
:dropdown-class-name="themeSwitcher.darkCardClass"> :dropdown-class-name="themeSwitcher.darkCardClass">
<a-select-option value="10">10</a-select-option> <a-select-option value="10">10</a-select-option>
<a-select-option value="20">20</a-select-option> <a-select-option value="20">20</a-select-option>
@ -262,9 +262,9 @@
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item label="Log Level"> <a-form-item label="Log Level">
<a-select v-model="logModal.logLevel" <a-select v-model="logModal.level"
style="width: 120px" style="width: 120px"
@change="openLogs(logModal.rows, logModal.logLevel)" @change="openLogs()"
:dropdown-class-name="themeSwitcher.darkCardClass"> :dropdown-class-name="themeSwitcher.darkCardClass">
<a-select-option value="debug">Debug</a-select-option> <a-select-option value="debug">Debug</a-select-option>
<a-select-option value="info">Info</a-select-option> <a-select-option value="info">Info</a-select-option>
@ -273,8 +273,11 @@
<a-select-option value="err">Error</a-select-option> <a-select-option value="err">Error</a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item label="SysLog">
<a-checkbox v-model="logModal.syslog" @change="openLogs()"></a-checkbox>
</a-form-item>
<a-form-item> <a-form-item>
<button class="ant-btn ant-btn-primary" @click="openLogs(logModal.rows, logModal.logLevel)"><a-icon type="sync"></a-icon> Reload</button> <button class="ant-btn ant-btn-primary" @click="openLogs()"><a-icon type="sync"></a-icon> Reload</button>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<a-button type="primary" style="margin-bottom: 10px;" <a-button type="primary" style="margin-bottom: 10px;"
@ -409,11 +412,11 @@
visible: false, visible: false,
logs: '', logs: '',
rows: 20, rows: 20,
logLevel: 'info', level: 'info',
show(logs, rows) { syslog: false,
show(logs) {
this.visible = true; this.visible = true;
this.rows = rows; this.logs = logs? logs.join("\n"): "No Record...";
this.logs = logs.join("\n");
}, },
hide() { hide() {
this.visible = false; this.visible = false;
@ -514,14 +517,14 @@
return; return;
} }
}, },
async openLogs(rows, logLevel) { async openLogs(){
this.loading(true); this.loading(true);
const msg = await HttpUtil.post('server/logs/' + rows, { logLevel: `${logLevel}` }); const msg = await HttpUtil.post('server/logs/'+logModal.rows,{level: logModal.level, syslog: logModal.syslog});
this.loading(false); this.loading(false);
if (!msg.success) { if (!msg.success) {
return; return;
} }
logModal.show(msg.obj, rows); logModal.show(msg.obj);
}, },
async openConfig() { async openConfig() {
this.loading(true); this.loading(true);

View file

@ -12,6 +12,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"runtime" "runtime"
"strconv"
"strings" "strings"
"time" "time"
@ -378,28 +379,26 @@ func (s *ServerService) UpdateXray(version string) error {
return nil return nil
} }
func (s *ServerService) GetLogs(count string, logLevel string) ([]string, error) { func (s *ServerService) GetLogs(count string, level string, syslog string) []string {
var cmdArgs []string c, _ := strconv.Atoi(count)
if runtime.GOOS == "linux" { var lines []string
cmdArgs = []string{"journalctl", "-u", "x-ui", "--no-pager", "-n", count}
if logLevel != "" {
cmdArgs = append(cmdArgs, "-p", logLevel)
}
} else {
return []string{"Unsupported operating system"}, nil
}
if syslog == "true" {
cmdArgs := []string{"journalctl", "-u", "x-ui", "--no-pager", "-n", count, "-p", level}
// Run the command
cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
var out bytes.Buffer var out bytes.Buffer
cmd.Stdout = &out cmd.Stdout = &out
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
return nil, err return []string{"Failed to run journalctl command!"}
}
lines = strings.Split(out.String(), "\n")
} else {
lines = logger.GetLogs(c, level)
} }
lines := strings.Split(out.String(), "\n") return lines
return lines, nil
} }
func (s *ServerService) GetConfigJson() (interface{}, error) { func (s *ServerService) GetConfigJson() (interface{}, error) {