diff --git a/caller/caller.go b/caller/caller.go new file mode 100644 index 0000000..dadd71e --- /dev/null +++ b/caller/caller.go @@ -0,0 +1,61 @@ +package caller + +import ( + "log/slog" + "os" + "runtime" + "strings" +) + +type Caller struct { + PC uintptr + Frame runtime.Frame +} + +func (ca Caller) File() string { + return ca.Frame.File +} + +func (ca Caller) Line() int { + return ca.Frame.Line +} + +func (ca Caller) Function() string { + return ca.Frame.Function +} + +func (ca Caller) ShortFunction() string { + split := strings.Split(ca.Frame.Function, string(os.PathSeparator)) + return split[len(split)-1] +} + +func (ca Caller) LogValue() slog.Value { + if ca.PC == 0 { + return slog.AnyValue(nil) + } + + return slog.GroupValue( + slog.String("file", ca.File()), + slog.Int("line", ca.Line()), + slog.String("function", ca.ShortFunction()), + ) +} + +func New(skip int) Caller { + var c Caller + pcs := make([]uintptr, 1) + n := runtime.Callers(skip, pcs) + if n == 0 { + return c + } + c.PC = pcs[0] + c.Frame, _ = runtime.CallersFrames(pcs).Next() + return c +} + +func From(pc uintptr) Caller { + var c Caller + c.PC = pc + c.Frame, _ = runtime.CallersFrames([]uintptr{pc}).Next() + return c +} diff --git a/log/log.go b/log/log.go index 718b804..0112602 100644 --- a/log/log.go +++ b/log/log.go @@ -6,13 +6,13 @@ import ( "io" "log/slog" "os" - "runtime" "strings" "time" "github.com/go-chi/chi/v5/middleware" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" + "github.com/tigorlazuardi/redmage/caller" "github.com/tigorlazuardi/redmage/config" ) @@ -47,7 +47,7 @@ func NewHandler(cfg *config.Config) slog.Handler { type Entry struct { ctx context.Context handler slog.Handler - caller uintptr + caller caller.Caller time time.Time } @@ -60,13 +60,13 @@ func Log(ctx context.Context) *Entry { return &Entry{ctx: ctx, handler: h, time: time.Now()} } -func (entry *Entry) Caller(pc uintptr) *Entry { - entry.caller = pc +func (entry *Entry) Caller(caller caller.Caller) *Entry { + entry.caller = caller return entry } func (entry *Entry) Info(message string, fields ...any) { - record := slog.NewRecord(entry.time, slog.LevelInfo, message, entry.getCaller()) + record := slog.NewRecord(entry.time, slog.LevelInfo, message, entry.getCaller().PC) record.AddAttrs(entry.getExtra()...) record.AddAttrs(slog.Group("context", fields...)) _ = entry.handler.Handle(entry.ctx, record) @@ -74,13 +74,13 @@ func (entry *Entry) Info(message string, fields ...any) { func (entry *Entry) Infof(format string, args ...any) { message := fmt.Sprintf(format, args...) - record := slog.NewRecord(entry.time, slog.LevelInfo, message, entry.getCaller()) + record := slog.NewRecord(entry.time, slog.LevelInfo, message, entry.getCaller().PC) record.AddAttrs(entry.getExtra()...) _ = entry.handler.Handle(entry.ctx, record) } func (entry *Entry) Error(message string, fields ...any) { - record := slog.NewRecord(entry.time, slog.LevelError, message, entry.getCaller()) + record := slog.NewRecord(entry.time, slog.LevelError, message, entry.getCaller().PC) record.AddAttrs(entry.getExtra()...) record.AddAttrs(slog.Group("context", fields...)) _ = entry.handler.Handle(entry.ctx, record) @@ -88,13 +88,13 @@ func (entry *Entry) Error(message string, fields ...any) { func (entry *Entry) Errorf(format string, args ...any) { message := fmt.Sprintf(format, args...) - record := slog.NewRecord(entry.time, slog.LevelError, message, entry.getCaller()) + record := slog.NewRecord(entry.time, slog.LevelError, message, entry.getCaller().PC) record.AddAttrs(entry.getExtra()...) _ = entry.handler.Handle(entry.ctx, record) } func (entry *Entry) Debug(message string, fields ...any) { - record := slog.NewRecord(entry.time, slog.LevelDebug, message, entry.getCaller()) + record := slog.NewRecord(entry.time, slog.LevelDebug, message, entry.getCaller().PC) record.AddAttrs(entry.getExtra()...) record.AddAttrs(slog.Group("context", fields...)) _ = entry.handler.Handle(entry.ctx, record) @@ -102,13 +102,13 @@ func (entry *Entry) Debug(message string, fields ...any) { func (entry *Entry) Debugf(format string, args ...any) { message := fmt.Sprintf(format, args...) - record := slog.NewRecord(entry.time, slog.LevelDebug, message, entry.getCaller()) + record := slog.NewRecord(entry.time, slog.LevelDebug, message, entry.getCaller().PC) record.AddAttrs(entry.getExtra()...) _ = entry.handler.Handle(entry.ctx, record) } func (entry *Entry) Warn(message string, fields ...any) { - record := slog.NewRecord(entry.time, slog.LevelWarn, message, entry.getCaller()) + record := slog.NewRecord(entry.time, slog.LevelWarn, message, entry.getCaller().PC) record.AddAttrs(entry.getExtra()...) record.AddAttrs(slog.Group("context", fields...)) _ = entry.handler.Handle(entry.ctx, record) @@ -116,25 +116,16 @@ func (entry *Entry) Warn(message string, fields ...any) { func (entry *Entry) Warnf(format string, args ...any) { message := fmt.Sprintf(format, args...) - record := slog.NewRecord(entry.time, slog.LevelWarn, message, entry.getCaller()) + record := slog.NewRecord(entry.time, slog.LevelWarn, message, entry.getCaller().PC) record.AddAttrs(entry.getExtra()...) _ = entry.handler.Handle(entry.ctx, record) } -func (entry *Entry) getCaller() uintptr { - if entry.caller != 0 { +func (entry *Entry) getCaller() caller.Caller { + if entry.caller.PC != 0 { return entry.caller } - return GetCaller(4) -} - -func GetCaller(skip int) uintptr { - pc := make([]uintptr, 1) - n := runtime.Callers(skip, pc) - if n == 0 { - return 0 - } - return pc[0] + return caller.New(4) } func (entry *Entry) getExtra() []slog.Attr { diff --git a/log/pretty_handler.go b/log/pretty_handler.go index 011bbc8..59cb040 100644 --- a/log/pretty_handler.go +++ b/log/pretty_handler.go @@ -7,11 +7,11 @@ import ( "io" "log/slog" "os" - "runtime" "strings" "sync" "github.com/fatih/color" + "github.com/tigorlazuardi/redmage/caller" ) type PrettyHandler struct { @@ -89,7 +89,7 @@ func (pr *PrettyHandler) Handle(ctx context.Context, record slog.Record) error { defer putBuffer(jsonBuf) if record.PC != 0 && pr.opts.AddSource { - frame := getFrame(record.PC) + frame := caller.From(record.PC).Frame levelColor.Fprint(buf, frame.File) levelColor.Fprint(buf, ":") levelColor.Fprint(buf, frame.Line) @@ -118,7 +118,7 @@ func (pr *PrettyHandler) Handle(ctx context.Context, record slog.Record) error { _ = serializer.Handle(ctx, record) if jsonBuf.Len() > 3 { // Ignore empty json like "{}\n" _ = json.Indent(buf, jsonBuf.Bytes(), "", " ") - // json indent includes new line, no need to add extra text. + // json indent includes new line, no need to add extra new line. } else { buf.WriteByte('\n') } @@ -148,12 +148,6 @@ func (pr *PrettyHandler) createSerializer(w io.Writer) slog.Handler { return jsonHandler } -func getFrame(pc uintptr) runtime.Frame { - frames := runtime.CallersFrames([]uintptr{pc}) - frame, _ := frames.Next() - return frame -} - func (pr *PrettyHandler) clone() *PrettyHandler { return &PrettyHandler{ opts: pr.opts,