From 419ea63dd0f7f2a693dbf674e411782301e06dc6 Mon Sep 17 00:00:00 2001 From: fgsfds <4870330+fgsfds@users.noreply.github.com> Date: Tue, 5 Aug 2025 15:10:14 +0500 Subject: [PATCH] Added filters to the xray logs viewer (#3314) * added filters to xray logs viewer * better freedom/blackhole tags handling * better freedom/blackhole tags handling 2 * fix comments * fix comments 2 --- web/controller/server.go | 43 ++++++++++++++++++++++++++++-- web/html/index.html | 27 +++++++++++++------ web/service/server.go | 56 +++++++++++++++++++++++++++++++++++----- 3 files changed, 110 insertions(+), 16 deletions(-) diff --git a/web/controller/server.go b/web/controller/server.go index dd001f5e..17b25cdc 100644 --- a/web/controller/server.go +++ b/web/controller/server.go @@ -17,7 +17,8 @@ var filenameRegex = regexp.MustCompile(`^[a-zA-Z0-9_\-.]+$`) type ServerController struct { BaseController - serverService service.ServerService + serverService service.ServerService + settingService service.SettingService lastStatus *service.Status lastGetStatusTime time.Time @@ -137,7 +138,45 @@ func (a *ServerController) getLogs(c *gin.Context) { func (a *ServerController) getXrayLogs(c *gin.Context) { count := c.Param("count") - logs := a.serverService.GetXrayLogs(count) + filter := c.PostForm("filter") + showDirect := c.PostForm("showDirect") + showBlocked := c.PostForm("showBlocked") + showProxy := c.PostForm("showProxy") + + var freedoms []string + var blackholes []string + + //getting tags for freedom and blackhole outbounds + config, err := a.settingService.GetDefaultXrayConfig() + if err == nil && config != nil { + if cfgMap, ok := config.(map[string]interface{}); ok { + if outbounds, ok := cfgMap["outbounds"].([]interface{}); ok { + for _, outbound := range outbounds { + if obMap, ok := outbound.(map[string]interface{}); ok { + switch obMap["protocol"] { + case "freedom": + if tag, ok := obMap["tag"].(string); ok { + freedoms = append(freedoms, tag) + } + case "blackhole": + if tag, ok := obMap["tag"].(string); ok { + blackholes = append(blackholes, tag) + } + } + } + } + } + } + } + + if len(freedoms) == 0 { + freedoms = []string{"direct"} + } + if len(blackholes) == 0 { + blackholes = []string{"blocked"} + } + + logs := a.serverService.GetXrayLogs(count, filter, showDirect, showBlocked, showProxy, freedoms, blackholes) jsonObj(c, logs, nil) } diff --git a/web/html/index.html b/web/html/index.html index 4089e6a6..bc5483b0 100644 --- a/web/html/index.html +++ b/web/html/index.html @@ -457,6 +457,14 @@ + + + + + Direct + Blocked + Proxy + @@ -651,6 +659,9 @@ visible: false, logs: [], rows: 20, + showDirect: true, + showBlocked: true, + showProxy: true, loading: false, show(logs) { this.visible = true; @@ -665,17 +676,17 @@ const parts = log.split(' '); - if(parts.length === 9) { + if(parts.length === 10) { const dateTime = `${parts[0]} ${parts[1]}`; const from = `${parts[3]}`; const to = `${parts[5].replace(/^\/+/, "")}`; let outboundColor = ''; - if (parts[8].startsWith('blocked')) { - outboundColor = ' style="color: #e04141;"'; + if (parts[9] === "b") { + outboundColor = ' style="color: #e04141;"'; //red for blocked } - else if (!parts[8].startsWith('direct')) { - outboundColor = ' style="color: #3c89e8;"'; + else if (parts[9] === "p") { + outboundColor = ' style="color: #3c89e8;"'; //blue for proxies } formattedLogs += ` @@ -684,10 +695,10 @@ ${dateTime} ${from} ${parts[4]} ${to} - ${parts.slice(6).join(' ')} + ${parts.slice(6, 9).join(' ')} `; } else { - formattedLogs += `${parts.join(' ')}`; + formattedLogs += `${log}`; } }); @@ -817,7 +828,7 @@ ${dateTime} }, async openXrayLogs(){ xraylogModal.loading = true; - const msg = await HttpUtil.post('server/xraylogs/'+xraylogModal.rows); + const msg = await HttpUtil.post('server/xraylogs/'+xraylogModal.rows,{filter: xraylogModal.filter, showDirect: xraylogModal.showDirect, showBlocked: xraylogModal.showBlocked, showProxy: xraylogModal.showProxy}); if (!msg.success) { return; } diff --git a/web/service/server.go b/web/service/server.go index 2b174e8b..ee13b268 100644 --- a/web/service/server.go +++ b/web/service/server.go @@ -482,8 +482,16 @@ func (s *ServerService) GetLogs(count string, level string, syslog string) []str return lines } -func (s *ServerService) GetXrayLogs(count string) []string { - c, _ := strconv.Atoi(count) +func (s *ServerService) GetXrayLogs( + count string, + filter string, + showDirect string, + showBlocked string, + showProxy string, + freedoms []string, + blackholes []string) []string { + + countInt, _ := strconv.Atoi(count) var lines []string pathToAccessLog, err := xray.GetAccessLogPath() @@ -498,21 +506,57 @@ func (s *ServerService) GetXrayLogs(count string) []string { defer file.Close() scanner := bufio.NewScanner(file) + for scanner.Scan() { - line := scanner.Text() - if strings.TrimSpace(line) == "" || strings.Contains(line, "api -> api") { + line := strings.TrimSpace(scanner.Text()) + + if line == "" || strings.Contains(line, "api -> api") { + //skipping empty lines and api calls continue } + + if filter != "" && !strings.Contains(line, filter) { + //applying filter if it's not empty + continue + } + + //adding suffixes to further distinguish entries by outbound + if hasSuffix(line, freedoms) { + if showDirect == "false" { + continue + } + line = line + " f" + } else if hasSuffix(line, blackholes) { + if showBlocked == "false" { + continue + } + line = line + " b" + } else { + if showProxy == "false" { + continue + } + line = line + " p" + } + lines = append(lines, line) } - if len(lines) > c { - lines = lines[len(lines)-c:] + if len(lines) > countInt { + lines = lines[len(lines)-countInt:] } return lines } +func hasSuffix(line string, suffixes []string) bool { + for _, sfx := range suffixes { + if strings.HasSuffix(line, sfx+"]") { + return true + } + } + return false +} + func (s *ServerService) GetConfigJson() (any, error) { config, err := s.xrayService.GetXrayConfig() if err != nil {