From 7c758f7accd19f1bb4eb76b57c034d4255c952c8 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Wed, 15 Jan 2025 20:48:37 +0900 Subject: [PATCH 1/7] feat(log): add incoming access logs and update outcoming log format --- appx/context.go | 31 ++++------------- appx/context_test.go | 7 ++-- appx/gql.go | 5 ++- log/echo.go | 83 +++++++++++++++++++++++++++++++++++++------- 4 files changed, 85 insertions(+), 41 deletions(-) diff --git a/appx/context.go b/appx/context.go index cba01e37..9fa90cb4 100644 --- a/appx/context.go +++ b/appx/context.go @@ -3,7 +3,6 @@ package appx import ( "context" "net/http" - "strings" "github.com/google/uuid" "github.com/reearth/reearthx/log" @@ -12,15 +11,15 @@ import ( type requestIDKey struct{} func ContextMiddleware(key, value any) func(http.Handler) http.Handler { - return ContextMiddlewareBy(func(r *http.Request) context.Context { + return ContextMiddlewareBy(func(w http.ResponseWriter, r *http.Request) context.Context { return context.WithValue(r.Context(), key, value) }) } -func ContextMiddlewareBy(c func(*http.Request) context.Context) func(http.Handler) http.Handler { +func ContextMiddlewareBy(c func(http.ResponseWriter, *http.Request) context.Context) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if ctx := c(r); ctx == nil { + if ctx := c(w, r); ctx == nil { next.ServeHTTP(w, r) } else { next.ServeHTTP(w, r.WithContext(ctx)) @@ -30,18 +29,14 @@ func ContextMiddlewareBy(c func(*http.Request) context.Context) func(http.Handle } func RequestIDMiddleware() func(http.Handler) http.Handler { - return ContextMiddlewareBy(func(r *http.Request) context.Context { + return ContextMiddlewareBy(func(w http.ResponseWriter, r *http.Request) context.Context { ctx := r.Context() - reqid := getHeader(r, - "X-Request-ID", - "X-Amzn-Trace-Id", // AWS - "X-Cloud-Trace-Context", // GCP - "X-ARR-LOG-ID", // Azure - ) + reqid := log.GetReqestID(w, r) if reqid == "" { reqid = uuid.NewString() } ctx = context.WithValue(ctx, requestIDKey{}, reqid) + w.Header().Set("X-Request-ID", reqid) logger := log.GetLoggerFromContextOrDefault(ctx).SetPrefix(reqid) ctx = log.AttachLoggerToContext(ctx, logger) @@ -49,7 +44,7 @@ func RequestIDMiddleware() func(http.Handler) http.Handler { }) } -func GetRequestID(ctx context.Context) string { +func GetRequestIDFromContext(ctx context.Context) string { if ctx == nil { return "" } @@ -58,15 +53,3 @@ func GetRequestID(ctx context.Context) string { } return "" } - -func getHeader(r *http.Request, keys ...string) string { - for _, k := range keys { - if v := r.Header.Get(k); v != "" { - return v - } - if v := r.Header.Get(strings.ToLower(k)); v != "" { - return v - } - } - return "" -} diff --git a/appx/context_test.go b/appx/context_test.go index a95093bc..b79be0f2 100644 --- a/appx/context_test.go +++ b/appx/context_test.go @@ -25,8 +25,9 @@ func TestContextMiddleware(t *testing.T) { } func TestContextMiddlewareBy(t *testing.T) { - key := struct{}{} - ts := httptest.NewServer(ContextMiddlewareBy(func(r *http.Request) context.Context { + type keys struct{} + key := keys{} + ts := httptest.NewServer(ContextMiddlewareBy(func(w http.ResponseWriter, r *http.Request) context.Context { if r.Method == http.MethodPost { return context.WithValue(r.Context(), key, "aaa") } @@ -49,7 +50,7 @@ func TestContextMiddlewareBy(t *testing.T) { func TestRequestIDMiddleware(t *testing.T) { ts := httptest.NewServer(RequestIDMiddleware()(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, _ = w.Write([]byte(GetRequestID(r.Context()))) + _, _ = w.Write([]byte(GetRequestIDFromContext(r.Context()))) }))) defer ts.Close() diff --git a/appx/gql.go b/appx/gql.go index 685b0687..e0cd70bc 100644 --- a/appx/gql.go +++ b/appx/gql.go @@ -8,6 +8,7 @@ import ( "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/handler/extension" "github.com/ravilushqa/otelgqlgen" + "github.com/reearth/reearthx/log" "github.com/vektah/gqlparser/v2/gqlerror" ) @@ -33,8 +34,10 @@ func GraphQLHandler(c GraphQLHandlerConfig) http.Handler { srv.SetErrorPresenter( // show more detailed error messgage in debug mode func(ctx context.Context, e error) *gqlerror.Error { + path := graphql.GetFieldContext(ctx).Path() + log.Debugfc(ctx, "gql error: %v: %v", path, e) if c.Dev { - return gqlerror.ErrorPathf(graphql.GetFieldContext(ctx).Path(), e.Error()) + return gqlerror.ErrorPathf(path, "%v", e) } return graphql.DefaultErrorPresenter(ctx, e) }, diff --git a/log/echo.go b/log/echo.go index 657719fa..449b2bb5 100644 --- a/log/echo.go +++ b/log/echo.go @@ -1,7 +1,10 @@ package log import ( + "fmt" "io" + "net/http" + "strings" "time" "github.com/labstack/echo/v4" @@ -203,29 +206,54 @@ func (l *Echo) AccessLogger() echo.MiddlewareFunc { req := c.Request() res := c.Response() start := time.Now() - if err := next(c); err != nil { - c.Error(err) - } - stop := time.Now() - logger := GetLoggerFromContext(c.Request().Context()) - if logger == nil { - logger = l.logger - } - logger.Infow( - "Handled request", + reqid := GetReqestID(res, req) + args := []any{ + "time_unix", start.Unix(), "remote_ip", c.RealIP(), "host", req.Host, + "origin", req.Header.Get("Origin"), "uri", req.RequestURI, "method", req.Method, "path", req.URL.Path, + "protocol", req.Proto, "referer", req.Referer(), "user_agent", req.UserAgent(), - "status", res.Status, - "latency", stop.Sub(start).Microseconds(), - "latency_human", stop.Sub(start).String(), "bytes_in", req.ContentLength, + "request_id", reqid, + "route", c.Path(), + } + + logger := GetLoggerFromContext(c.Request().Context()) + if logger == nil { + logger = l.logger + } + + // incoming log + logger.Infow( + fmt.Sprintf("<-- %s %s %s", req.Method, req.URL.Path, reqid), + args..., + ) + + if err := next(c); err != nil { + c.Error(err) + } + + res = c.Response() + stop := time.Now() + latency := stop.Sub(start) + latencyHuman := latency.String() + args = append(args, + "status", res.Status, "bytes_out", res.Size, + "letency", latency.Microseconds(), + "latency_human", latencyHuman, + ) + + // outcoming log + logger.Infow( + fmt.Sprintf("--> %s %s %s %d %s", req.Method, req.URL.Path, reqid, res.Status, latencyHuman), + args..., ) return nil } @@ -240,3 +268,32 @@ func fromMap(m map[string]any) (res []any) { } return } + +func GetReqestID(w http.ResponseWriter, r *http.Request) string { + if reqid := getHeader(r, + "X-Request-ID", + "X-Cloud-Trace-Context", // Google Cloud + "X-Amzn-Trace-Id", // AWS + "X-ARR-LOG-ID", // Azure + ); reqid != "" { + return reqid + } + + if reqid := w.Header().Get("X-Request-ID"); reqid != "" { + return reqid + } + + return "" +} + +func getHeader(r *http.Request, keys ...string) string { + for _, k := range keys { + if v := r.Header.Get(k); v != "" { + return v + } + if v := r.Header.Get(strings.ToLower(k)); v != "" { + return v + } + } + return "" +} From 9ca6b9071b50d3959af9374905641202e361f1cc Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 16 Jan 2025 23:12:41 +0900 Subject: [PATCH 2/7] feat(server): simplify access log --- log/echo.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/log/echo.go b/log/echo.go index 449b2bb5..36f7ccb4 100644 --- a/log/echo.go +++ b/log/echo.go @@ -212,7 +212,6 @@ func (l *Echo) AccessLogger() echo.MiddlewareFunc { "time_unix", start.Unix(), "remote_ip", c.RealIP(), "host", req.Host, - "origin", req.Header.Get("Origin"), "uri", req.RequestURI, "method", req.Method, "path", req.URL.Path, @@ -231,7 +230,7 @@ func (l *Echo) AccessLogger() echo.MiddlewareFunc { // incoming log logger.Infow( - fmt.Sprintf("<-- %s %s %s", req.Method, req.URL.Path, reqid), + fmt.Sprintf("<-- %s %s", req.Method, req.URL.Path), args..., ) @@ -252,7 +251,7 @@ func (l *Echo) AccessLogger() echo.MiddlewareFunc { // outcoming log logger.Infow( - fmt.Sprintf("--> %s %s %s %d %s", req.Method, req.URL.Path, reqid, res.Status, latencyHuman), + fmt.Sprintf("--> %s %d %s %s", req.Method, res.Status, req.URL.Path, latencyHuman), args..., ) return nil From 83ed95f16a17a8dbee24807852839f69cbaf53f3 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 28 Jan 2025 15:53:01 +0900 Subject: [PATCH 3/7] feat(log): add caller to logs --- log/logger.go | 43 ++++++++++++++++++++++++++++++++++++++++++- log/logger_test.go | 27 ++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/log/logger.go b/log/logger.go index b3d9adc5..d92ebdf8 100644 --- a/log/logger.go +++ b/log/logger.go @@ -58,7 +58,10 @@ func newLogger(w io.Writer, atom zap.AtomicLevel, name string) *zap.SugaredLogge zapcore.Lock(zapcore.AddSync(w)), atom, ), - ).Sugar().Named(name) + ).Sugar().Named(name).WithOptions( + zap.AddCaller(), + zap.AddCallerSkip(1), + ) } func encoder() zapcore.Encoder { @@ -73,6 +76,44 @@ func encoder() zapcore.Encoder { } } +func (l *Logger) AppendPrefixMessage(prefix string) *Logger { + return l.AppendDynamicPrefix(func() Format { + return Format{Format: prefix} + }) +} + +func (l *Logger) AppendSuffixMessage(suffix string) *Logger { + return l.AppendDynamicSuffix(func() Format { + return Format{Format: suffix} + }) +} + +func (l *Logger) AppendDynamicPrefix(prefix func() Format) *Logger { + if l.dynPrefix == nil { + return l.SetDynamicPrefix(prefix) + } + + return l.SetDynamicPrefix(func() Format { + if l.dynPrefix == nil { + return prefix() + } + return l.dynPrefix().Append(prefix()) + }) +} + +func (l *Logger) AppendDynamicSuffix(suffix func() Format) *Logger { + if l.dynSuffix == nil { + return l.SetDynamicSuffix(suffix) + } + + return l.SetDynamicSuffix(func() Format { + if l.dynSuffix == nil { + return suffix() + } + return l.dynSuffix().Append(suffix()) + }) +} + func (l *Logger) SetDynamicPrefix(prefix func() Format) *Logger { return &Logger{ logger: l.logger, diff --git a/log/logger_test.go b/log/logger_test.go index 30201e50..ce8e78ae 100644 --- a/log/logger_test.go +++ b/log/logger_test.go @@ -57,7 +57,7 @@ func TestLogger_DynamicPrefixSuffix(t *testing.T) { }).SetDynamicSuffix(func() Format { return Format{ Format: " <%s>", - Args: []any{"prefix"}, + Args: []any{"suffix"}, } }) l.Infof("hoge %s", "fuga") @@ -65,8 +65,29 @@ func TestLogger_DynamicPrefixSuffix(t *testing.T) { scanner := bufio.NewScanner(w) assert.True(t, scanner.Scan()) - assert.Contains(t, scanner.Text(), "[test] hoge fuga ") + assert.Contains(t, scanner.Text(), "[test] hoge fuga ") + assert.True(t, scanner.Scan()) + assert.Contains(t, scanner.Text(), "[test] [fuga 1] ") + assert.False(t, scanner.Scan()) +} + +func TestLogger_AppendDynamicPrefixS(t *testing.T) { + w := &bytes.Buffer{} + l := NewWithOutput(w).AppendDynamicPrefix(func() Format { + return Format{ + Format: "[%s] ", + Args: []any{"prefix"}, + } + }).AppendPrefixMessage(" ").AppendDynamicSuffix(func() Format { + return Format{ + Format: " [%s]", + Args: []any{"suffix"}, + } + }).AppendSuffixMessage(" ") + l.Infof("hoge %s", "fuga") + + scanner := bufio.NewScanner(w) assert.True(t, scanner.Scan()) - assert.Contains(t, scanner.Text(), "[test] [fuga 1] ") + assert.Contains(t, scanner.Text(), "[prefix] hoge fuga [suffix] ") assert.False(t, scanner.Scan()) } From c3eb7341e67a483bc7efcc4b6ed8ded884c8f84a Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 28 Jan 2025 17:45:38 +0900 Subject: [PATCH 4/7] fix(log): fix caller skip depth --- log/context.go | 8 ++++++-- log/context_test.go | 9 +++++---- log/echo_test.go | 4 ++-- log/logger.go | 20 ++++++++++++++++++++ log/logger_test.go | 4 ++-- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/log/context.go b/log/context.go index 2eabe838..763ce738 100644 --- a/log/context.go +++ b/log/context.go @@ -20,9 +20,13 @@ func GetLoggerFromContext(ctx context.Context) *Logger { func GetLoggerFromContextOrDefault(ctx context.Context) *Logger { if logger := GetLoggerFromContext(ctx); logger != nil { - return logger + return logger.AddCallerSkip(1) } - return globalLogger + return globalLogger.AddCallerSkip(1) +} + +func UpdateContext(ctx context.Context, f func(logger *Logger) *Logger) context.Context { + return AttachLoggerToContext(ctx, f(GetLoggerFromContextOrDefault(ctx))) } func Tracefc(ctx context.Context, format string, args ...any) { diff --git a/log/context_test.go b/log/context_test.go index a162010e..151921d6 100644 --- a/log/context_test.go +++ b/log/context_test.go @@ -16,8 +16,9 @@ func TestContextLogger(t *testing.T) { SetOutput(DefaultOutput) }) - l := NewWithOutput(w).SetPrefix("test") + l := NewWithOutput(w).SetPrefix("prefix") ctx := AttachLoggerToContext(context.Background(), l) + Infofc(ctx, "hoge %s", "fuga") Infofc(context.Background(), "hoge %s", "fuga2") //nolint:staticcheck // test nil context @@ -25,12 +26,12 @@ func TestContextLogger(t *testing.T) { scanner := bufio.NewScanner(w) assert.True(t, scanner.Scan()) - assert.Contains(t, scanner.Text(), "test\thoge fuga") + assert.Contains(t, scanner.Text(), "\tprefix\t") assert.True(t, scanner.Scan()) assert.Contains(t, scanner.Text(), "hoge fuga2") - assert.NotContains(t, scanner.Text(), "test") + assert.NotContains(t, scanner.Text(), "\tprefix\t") assert.True(t, scanner.Scan()) assert.Contains(t, scanner.Text(), "hoge fuga3") - assert.NotContains(t, scanner.Text(), "test") + assert.NotContains(t, scanner.Text(), "\tprefix\t") assert.False(t, scanner.Scan()) } diff --git a/log/echo_test.go b/log/echo_test.go index f6409e42..bb6edf2e 100644 --- a/log/echo_test.go +++ b/log/echo_test.go @@ -12,11 +12,11 @@ func TestEcho(t *testing.T) { w := &bytes.Buffer{} l := NewEcho() l.SetOutput(w) - l.SetPrefix("test") + l.SetPrefix("prefix") l.Infof("hoge %s", "fuga") scanner := bufio.NewScanner(w) assert.True(t, scanner.Scan()) - assert.Contains(t, scanner.Text(), "test\thoge fuga") + assert.Contains(t, scanner.Text(), "\tprefix\t") assert.False(t, scanner.Scan()) } diff --git a/log/logger.go b/log/logger.go index d92ebdf8..82c7e247 100644 --- a/log/logger.go +++ b/log/logger.go @@ -177,6 +177,26 @@ func (l *Logger) ClearPrefix() *Logger { } } +func (l *Logger) WithCaller(enabled bool) *Logger { + return &Logger{ + logger: l.logger.WithOptions(zap.WithCaller(enabled)), + atom: l.atom, + prefix: l.prefix, + dynPrefix: l.dynPrefix, + dynSuffix: l.dynSuffix, + } +} + +func (l *Logger) AddCallerSkip(skip int) *Logger { + return &Logger{ + logger: l.logger.WithOptions(zap.AddCallerSkip(skip)), + atom: l.atom, + prefix: l.prefix, + dynPrefix: l.dynPrefix, + dynSuffix: l.dynSuffix, + } +} + func (l *Logger) Debugf(format string, args ...any) { f := l.format(format, args...) l.logger.Debugf(f.Format, f.Args...) diff --git a/log/logger_test.go b/log/logger_test.go index ce8e78ae..b8fa2a29 100644 --- a/log/logger_test.go +++ b/log/logger_test.go @@ -37,9 +37,9 @@ func TestLogger_SetPrefix(t *testing.T) { scanner := bufio.NewScanner(w) assert.True(t, scanner.Scan()) - assert.Contains(t, scanner.Text(), "test\thoge fuga") + assert.Regexp(t, `\ttest\t.+?\thoge fuga$`, scanner.Text()) // .+? is a caller assert.True(t, scanner.Scan()) - assert.Contains(t, scanner.Text(), "test\t[fuga 1]") + assert.Regexp(t, `\ttest\t.+?\t\[fuga 1\]$`, scanner.Text()) assert.True(t, scanner.Scan()) assert.Contains(t, scanner.Text(), "test") assert.Contains(t, scanner.Text(), "abcd") From 5675c40c2eb1ab96263cf93153d6e22b2619b568 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 28 Jan 2025 18:17:50 +0900 Subject: [PATCH 5/7] fix(log): fix caller skip --- log/context.go | 43 +++++++++++++++++++++++++------------------ log/global.go | 2 +- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/log/context.go b/log/context.go index 763ce738..259e5909 100644 --- a/log/context.go +++ b/log/context.go @@ -20,9 +20,9 @@ func GetLoggerFromContext(ctx context.Context) *Logger { func GetLoggerFromContextOrDefault(ctx context.Context) *Logger { if logger := GetLoggerFromContext(ctx); logger != nil { - return logger.AddCallerSkip(1) + return logger } - return globalLogger.AddCallerSkip(1) + return globalLogger } func UpdateContext(ctx context.Context, f func(logger *Logger) *Logger) context.Context { @@ -30,65 +30,72 @@ func UpdateContext(ctx context.Context, f func(logger *Logger) *Logger) context. } func Tracefc(ctx context.Context, format string, args ...any) { - GetLoggerFromContextOrDefault(ctx).Debugf(format, args...) + getLoggerFromContextOrDefault(ctx).Debugf(format, args...) } func Debugfc(ctx context.Context, format string, args ...any) { - GetLoggerFromContextOrDefault(ctx).Debugf(format, args...) + getLoggerFromContextOrDefault(ctx).Debugf(format, args...) } func Infofc(ctx context.Context, format string, args ...any) { - GetLoggerFromContextOrDefault(ctx).Infof(format, args...) + getLoggerFromContextOrDefault(ctx).Infof(format, args...) } func Printfc(ctx context.Context, format string, args ...any) { - GetLoggerFromContextOrDefault(ctx).Infof(format, args...) + getLoggerFromContextOrDefault(ctx).Infof(format, args...) } func Warnfc(ctx context.Context, format string, args ...any) { - GetLoggerFromContextOrDefault(ctx).Warnf(format, args...) + getLoggerFromContextOrDefault(ctx).Warnf(format, args...) } func Errorfc(ctx context.Context, format string, args ...any) { - GetLoggerFromContextOrDefault(ctx).Errorf(format, args...) + getLoggerFromContextOrDefault(ctx).Errorf(format, args...) } func Fatalfc(ctx context.Context, format string, args ...any) { - GetLoggerFromContextOrDefault(ctx).Fatalf(format, args...) + getLoggerFromContextOrDefault(ctx).Fatalf(format, args...) } func Panicfc(ctx context.Context, format string, args ...any) { - GetLoggerFromContextOrDefault(ctx).Panicf(format, args...) + getLoggerFromContextOrDefault(ctx).Panicf(format, args...) } func Tracec(ctx context.Context, args ...any) { - GetLoggerFromContextOrDefault(ctx).Debug(args...) + getLoggerFromContextOrDefault(ctx).Debug(args...) } func Debugc(ctx context.Context, args ...any) { - GetLoggerFromContextOrDefault(ctx).Debug(args...) + getLoggerFromContextOrDefault(ctx).Debug(args...) } func Infoc(ctx context.Context, args ...any) { - GetLoggerFromContextOrDefault(ctx).Info(args...) + getLoggerFromContextOrDefault(ctx).Info(args...) } func Printc(ctx context.Context, args ...any) { - GetLoggerFromContextOrDefault(ctx).Info(args...) + getLoggerFromContextOrDefault(ctx).Info(args...) } func Warnc(ctx context.Context, args ...any) { - GetLoggerFromContextOrDefault(ctx).Warn(args...) + getLoggerFromContextOrDefault(ctx).Warn(args...) } func Errorc(ctx context.Context, args ...any) { - GetLoggerFromContextOrDefault(ctx).Error(args...) + getLoggerFromContextOrDefault(ctx).Error(args...) } func Fatalc(ctx context.Context, args ...any) { - GetLoggerFromContextOrDefault(ctx).Fatal(args...) + getLoggerFromContextOrDefault(ctx).Fatal(args...) } func Panicc(ctx context.Context, args ...any) { - GetLoggerFromContextOrDefault(ctx).Panic(args...) + getLoggerFromContextOrDefault(ctx).Panic(args...) +} + +func getLoggerFromContextOrDefault(ctx context.Context) *Logger { + if logger := GetLoggerFromContext(ctx); logger != nil { + return logger.AddCallerSkip(1) + } + return globalLogger } diff --git a/log/global.go b/log/global.go index f891c443..19933fd9 100644 --- a/log/global.go +++ b/log/global.go @@ -7,7 +7,7 @@ import ( ) var ( - globalLogger = New() + globalLogger = New().AddCallerSkip(1) ) func SetLevel(l zapcore.Level) { From 471511f39d3cd9a7e848ea12b0e429d5f171c0c7 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Tue, 28 Jan 2025 19:03:21 +0900 Subject: [PATCH 6/7] fix(log): disable caller on access logging --- log/echo.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/log/echo.go b/log/echo.go index 36f7ccb4..c691201b 100644 --- a/log/echo.go +++ b/log/echo.go @@ -26,6 +26,12 @@ func NewEcho() *Echo { } func NewEchoWith(logger *Logger) *Echo { + return &Echo{ + logger: logger.AddCallerSkip(1), + } +} + +func NewEchoWithRaw(logger *Logger) *Echo { return &Echo{ logger: logger, } @@ -227,6 +233,7 @@ func (l *Echo) AccessLogger() echo.MiddlewareFunc { if logger == nil { logger = l.logger } + logger = logger.WithCaller(false) // incoming log logger.Infow( From 7860571926f2163d855c502b2c517cb8a1b30825 Mon Sep 17 00:00:00 2001 From: rot1024 Date: Thu, 30 Jan 2025 22:55:42 +0900 Subject: [PATCH 7/7] feat(log): WithPrefixMessage func --- log/context.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/log/context.go b/log/context.go index 259e5909..fc4f7efd 100644 --- a/log/context.go +++ b/log/context.go @@ -29,6 +29,12 @@ func UpdateContext(ctx context.Context, f func(logger *Logger) *Logger) context. return AttachLoggerToContext(ctx, f(GetLoggerFromContextOrDefault(ctx))) } +func WithPrefixMessage(ctx context.Context, prefix string) context.Context { + return UpdateContext(ctx, func(logger *Logger) *Logger { + return logger.AppendPrefixMessage(prefix) + }) +} + func Tracefc(ctx context.Context, format string, args ...any) { getLoggerFromContextOrDefault(ctx).Debugf(format, args...) }