From 0932a9c83ff6dafbbca390bd68f4121ae794c042 Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Fri, 29 Sep 2023 08:50:50 +0800 Subject: [PATCH] feat: support clash premium's structured log stream (#735) * feat: support clash premium's structured log stream New version of Clash for Windows uses `ws://external-controller/logs?token=&level=info&format=structured` to get real time log. When Clash Premium Core reveices `format=structured`, it returns a different form of JSON log entry. Supporting this feature will allow better Clash for Windows integration Signed-off-by: Misty --- hub/route/server.go | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/hub/route/server.go b/hub/route/server.go index d2fecd05..3d0df95e 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -293,6 +293,16 @@ type Log struct { Type string `json:"type"` Payload string `json:"payload"` } +type LogStructuredField struct { + Key string `json:"key"` + Value string `json:"value"` +} +type LogStructured struct { + Time string `json:"time"` + Level string `json:"level"` + Message string `json:"message"` + Fields []LogStructuredField `json:"fields"` +} func getLogs(w http.ResponseWriter, r *http.Request) { levelText := r.URL.Query().Get("level") @@ -300,6 +310,12 @@ func getLogs(w http.ResponseWriter, r *http.Request) { levelText = "info" } + formatText := r.URL.Query().Get("format") + isStructured := false + if formatText == "structured" { + isStructured = true + } + level, ok := log.LogLevelMapping[levelText] if !ok { render.Status(r, http.StatusBadRequest) @@ -342,11 +358,26 @@ func getLogs(w http.ResponseWriter, r *http.Request) { } buf.Reset() - if err := json.NewEncoder(buf).Encode(Log{ - Type: logM.Type(), - Payload: logM.Payload, - }); err != nil { - break + if !isStructured { + if err := json.NewEncoder(buf).Encode(Log{ + Type: logM.Type(), + Payload: logM.Payload, + }); err != nil { + break + } + } else { + newLevel := logM.Type() + if newLevel == "warning" { + newLevel = "warn" + } + if err := json.NewEncoder(buf).Encode(LogStructured{ + Time: time.Now().Format(time.TimeOnly), + Level: newLevel, + Message: logM.Payload, + Fields: []LogStructuredField{}, + }); err != nil { + break + } } var err error