From 6ac1e0ca46cd19900348a561e3dd542e57ab573e Mon Sep 17 00:00:00 2001 From: Chigozirim Igweamaka Date: Wed, 15 May 2024 04:58:30 +0100 Subject: [PATCH] Write utility for logging --- utils/logger.go | 98 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 utils/logger.go diff --git a/utils/logger.go b/utils/logger.go new file mode 100644 index 0000000..01081d3 --- /dev/null +++ b/utils/logger.go @@ -0,0 +1,98 @@ +package utils + +import ( + "context" + "log/slog" + "os" + "path/filepath" + + "github.com/mdobak/go-xerrors" +) + +type stackFrame struct { + Func string `json:"func"` + Source string `json:"source"` + Line int `json:"line"` +} + +func replaceAttr(_ []string, a slog.Attr) slog.Attr { + switch a.Value.Kind() { + case slog.KindAny: + switch v := a.Value.Any().(type) { + case error: + a.Value = fmtErr(v) + } + } + + return a +} + +// marshalStack extracts stack frames from the error +func marshalStack(err error) []stackFrame { + trace := xerrors.StackTrace(err) + + if len(trace) == 0 { + return nil + } + + frames := trace.Frames() + + s := make([]stackFrame, len(frames)) + + for i, v := range frames { + f := stackFrame{ + Source: filepath.Join( + filepath.Base(filepath.Dir(v.File)), + filepath.Base(v.File), + ), + Func: filepath.Base(v.Function), + Line: v.Line, + } + + s[i] = f + } + + return s +} + +// fmtErr returns a slog.Value with keys `msg` and `trace`. If the error +// does not implement interface { StackTrace() errors.StackTrace }, the `trace` +// key is omitted. +func fmtErr(err error) slog.Value { + var groupValues []slog.Attr + + groupValues = append(groupValues, slog.String("msg", err.Error())) + + frames := marshalStack(err) + + if frames != nil { + groupValues = append(groupValues, + slog.Any("trace", frames), + ) + } + + return slog.GroupValue(groupValues...) +} + +func GetLogger() *slog.Logger { + h := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + ReplaceAttr: replaceAttr, + }) + + logger := slog.New(h) + return logger +} + +func main() { + h := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + ReplaceAttr: replaceAttr, + }) + + logger := slog.New(h) + + ctx := context.Background() + + err := xerrors.New("something happened") + + logger.ErrorContext(ctx, "image uploaded", slog.Any("error", err)) +}