diff --git a/go.mod b/go.mod index f221ec5ae1691..c6af6b3c51810 100644 --- a/go.mod +++ b/go.mod @@ -126,7 +126,7 @@ require ( github.com/gravitational/license v0.0.0-20240313232707-8312e719d624 github.com/gravitational/roundtrip v1.0.2 github.com/gravitational/teleport/api v0.0.0 - github.com/gravitational/trace v1.4.0 + github.com/gravitational/trace v1.4.1-0.20241128213428-353656d83c45 github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 github.com/guptarohit/asciigraph v0.7.3 diff --git a/go.sum b/go.sum index e1626f33fbcba..3a39d5a2b3dbf 100644 --- a/go.sum +++ b/go.sum @@ -1536,6 +1536,8 @@ github.com/gravitational/saml v0.4.15-teleport.1 h1:kYSLpxEBEc7JLJJ+VjsZU8PbWI4g github.com/gravitational/saml v0.4.15-teleport.1/go.mod h1:S4+611dxnKt8z/ulbvaJzcgSHsuhjVc1QHNTcr1R7Fw= github.com/gravitational/trace v1.4.0 h1:TtTeMElVwMX21Udb1nmK2tpWYAAMJoyjevzKOaxIFZQ= github.com/gravitational/trace v1.4.0/go.mod h1:g79NZzwCjWS/VVubYowaFAQsTjVTohGi0hFbIWSyGoY= +github.com/gravitational/trace v1.4.1-0.20241128213428-353656d83c45 h1:bHx88VKuCfy7ALJ0YZ5RSC7KJAbncaz3277Kr2ONLaE= +github.com/gravitational/trace v1.4.1-0.20241128213428-353656d83c45/go.mod h1:g79NZzwCjWS/VVubYowaFAQsTjVTohGi0hFbIWSyGoY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= diff --git a/lib/utils/log/slog_handler.go b/lib/utils/log/slog_handler.go index b69b83d2a1adb..9763ae84ad469 100644 --- a/lib/utils/log/slog_handler.go +++ b/lib/utils/log/slog_handler.go @@ -20,6 +20,7 @@ package log import ( "context" + "errors" "fmt" "io" "log/slog" @@ -95,6 +96,39 @@ type SlogTextHandlerConfig struct { ReplaceAttr func(groups []string, a slog.Attr) slog.Attr } +func CompactErrors(groups []string, a slog.Attr) slog.Attr { + if err, ok := a.Value.Any().(error); ok { + var traceErr trace.Error + if errors.As(err, &traceErr) { + return slog.Attr{Key: a.Key, Value: slog.StringValue(traceErr.CompactUserMessage())} + } + return slog.Attr{Key: a.Key, Value: slog.StringValue(err.Error())} + } + return a +} + +func funcTraceOnly(traces trace.Traces) []string { + s := make([]string, len(traces)) + for i, t := range traces { + s[i] = t.Func + } + return s +} + +func CompactErrorsWithStackTrace(groups []string, a slog.Attr) slog.Attr { + if err, ok := a.Value.Any().(error); ok { + var traceErr trace.Error + if errors.As(err, &traceErr) { + return slog.Group("", + a.Key, traceErr.CompactUserMessage(), // display single-lien error + a.Key+"_trace", funcTraceOnly(traceErr.StackTraceReport()), // enrich with stacktrace + ) + } + return slog.Attr{Key: a.Key, Value: slog.StringValue(err.Error())} + } + return a +} + // NewSlogTextHandler creates a SlogTextHandler that writes messages to w. func NewSlogTextHandler(w io.Writer, cfg SlogTextHandlerConfig) *SlogTextHandler { if cfg.Padding == 0 { @@ -204,7 +238,7 @@ func (s *SlogTextHandler) appendAttr(buf []byte, a slog.Attr) []byte { buf = s.appendAttr(buf, ga) } if a.Key != "" { - s.groupPrefix = s.groupPrefix[:len(s.groupPrefix)-len(a.Key)-1 /* for keyComponentSep */] + s.groupPrefix = s.groupPrefix[:len(s.groupPrefix)-len(a.Key)-1 /* for keyComponentSep */ ] if s.groups != nil { s.groups = (s.groups)[:len(s.groups)-1] } @@ -490,6 +524,7 @@ func NewSlogJSONHandler(w io.Writer, cfg SlogJSONHandlerConfig) *SlogJSONHandler AddSource: true, Level: cfg.Level, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { + a = cfg.ReplaceAttr(groups, a) switch a.Key { case teleport.ComponentKey: if !withComponent {