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 <gyc990326@gmail.com>
This commit is contained in:
NyaMisty 2023-09-29 08:50:50 +08:00 committed by GitHub
parent 0ed3c5a5ec
commit 10e7c533d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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,12 +358,27 @@ func getLogs(w http.ResponseWriter, r *http.Request) {
}
buf.Reset()
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
if wsConn == nil {