From b0795b17bc2a00e14b0fa15aa1fcd91d689d4b7b Mon Sep 17 00:00:00 2001 From: Francisco <77604845+zipzap11@users.noreply.github.com> Date: Tue, 7 May 2024 13:52:29 +0700 Subject: [PATCH] misc: improve logging (#34) * misc: improve logging --------- Co-authored-by: Francisco --- log.go | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/log.go b/log.go index 221bdfb6..b9739f1c 100644 --- a/log.go +++ b/log.go @@ -2,13 +2,18 @@ package main import ( "fmt" + "github.com/kumparan/go-utils" + log "github.com/sirupsen/logrus" "io" "net/http" + "net/url" "strings" "time" ) -const formatPattern = `{"remote_ip": "%s", "time": "%s", "method": "%s", "uri": "%s", "protocol": "%s", "status": "%d", "imaginary_bytes_out": %d, "imaginary_duration_in_ms": %d, "latency_human": "%s"}%s` +const formatPattern = `{"remote_ip": "%s", "time": "%s", "method": "%s", "uri": "%s", "protocol": "%s", "status": "%d", "imaginary_bytes_out": %d, "imaginary_duration_in_ms": %d, "latency_human": "%s", "imaginary_request_uri_scheme": "%s"}%s` + +var ignoredFields = []string{"s3", "text", "image", "font"} // LogRecord implements an Apache-compatible HTTP logging type LogRecord struct { @@ -23,9 +28,40 @@ type LogRecord struct { // Log writes a log entry in the passed io.Writer stream func (r *LogRecord) Log(out io.Writer) { - timeFormat := r.time.Format(time.RFC3339Nano) + go func(record *LogRecord) { + timeFormat := record.time.Format(time.RFC3339Nano) + + splited := strings.Split(record.uri, "?") + if len(splited) <= 0 { + _, _ = fmt.Fprintf(out, formatPattern, record.ip, timeFormat, record.method, record.uri, record.protocol, record.status, record.responseBytes, record.elapsedTime.Milliseconds(), record.elapsedTime.String(), "", "\n") + return + } + if len(splited) <= 1 { + _, _ = fmt.Fprintf(out, formatPattern, record.ip, timeFormat, record.method, record.uri, record.protocol, record.status, record.responseBytes, record.elapsedTime.Milliseconds(), record.elapsedTime.String(), splited[0], "\n") + return + } - _, _ = fmt.Fprintf(out, formatPattern, r.ip, timeFormat, r.method, r.uri, r.protocol, r.status, r.responseBytes, r.elapsedTime.Milliseconds(), r.elapsedTime.String(), "\n") + maskedURI := splited[0] + queryParam, err := url.ParseQuery(splited[1]) + if err != nil { + log.WithField("queryParam", splited[1]).Error(err) + _, _ = fmt.Fprintf(out, formatPattern, record.ip, timeFormat, record.method, record.uri, record.protocol, record.status, record.responseBytes, record.elapsedTime.Milliseconds(), record.elapsedTime.String(), maskedURI, "\n") + return + } + + newQueryParam := url.Values{} + for k, params := range queryParam { + if utils.Contains(ignoredFields, k) { + newQueryParam.Add(k, "_") + continue + } + for _, v := range params { + newQueryParam.Add(k, v) + } + } + maskedURI += "?" + newQueryParam.Encode() + _, _ = fmt.Fprintf(out, formatPattern, record.ip, timeFormat, record.method, record.uri, record.protocol, record.status, record.responseBytes, record.elapsedTime.Milliseconds(), record.elapsedTime.String(), maskedURI, "\n") + }(r) } // Write acts like a proxy passing the given bytes buffer to the ResponseWritter