caller: support for caller lib

This commit is contained in:
Tigor Hutasuhut 2024-04-06 20:42:01 +07:00
parent d02962dc65
commit aec979048e
3 changed files with 79 additions and 33 deletions

61
caller/caller.go Normal file
View file

@ -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
}

View file

@ -6,13 +6,13 @@ import (
"io" "io"
"log/slog" "log/slog"
"os" "os"
"runtime"
"strings" "strings"
"time" "time"
"github.com/go-chi/chi/v5/middleware" "github.com/go-chi/chi/v5/middleware"
"github.com/mattn/go-colorable" "github.com/mattn/go-colorable"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/tigorlazuardi/redmage/caller"
"github.com/tigorlazuardi/redmage/config" "github.com/tigorlazuardi/redmage/config"
) )
@ -47,7 +47,7 @@ func NewHandler(cfg *config.Config) slog.Handler {
type Entry struct { type Entry struct {
ctx context.Context ctx context.Context
handler slog.Handler handler slog.Handler
caller uintptr caller caller.Caller
time time.Time time time.Time
} }
@ -60,13 +60,13 @@ func Log(ctx context.Context) *Entry {
return &Entry{ctx: ctx, handler: h, time: time.Now()} return &Entry{ctx: ctx, handler: h, time: time.Now()}
} }
func (entry *Entry) Caller(pc uintptr) *Entry { func (entry *Entry) Caller(caller caller.Caller) *Entry {
entry.caller = pc entry.caller = caller
return entry return entry
} }
func (entry *Entry) Info(message string, fields ...any) { 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(entry.getExtra()...)
record.AddAttrs(slog.Group("context", fields...)) record.AddAttrs(slog.Group("context", fields...))
_ = entry.handler.Handle(entry.ctx, record) _ = 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) { func (entry *Entry) Infof(format string, args ...any) {
message := fmt.Sprintf(format, args...) 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()...) record.AddAttrs(entry.getExtra()...)
_ = entry.handler.Handle(entry.ctx, record) _ = entry.handler.Handle(entry.ctx, record)
} }
func (entry *Entry) Error(message string, fields ...any) { 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(entry.getExtra()...)
record.AddAttrs(slog.Group("context", fields...)) record.AddAttrs(slog.Group("context", fields...))
_ = entry.handler.Handle(entry.ctx, record) _ = 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) { func (entry *Entry) Errorf(format string, args ...any) {
message := fmt.Sprintf(format, args...) 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()...) record.AddAttrs(entry.getExtra()...)
_ = entry.handler.Handle(entry.ctx, record) _ = entry.handler.Handle(entry.ctx, record)
} }
func (entry *Entry) Debug(message string, fields ...any) { 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(entry.getExtra()...)
record.AddAttrs(slog.Group("context", fields...)) record.AddAttrs(slog.Group("context", fields...))
_ = entry.handler.Handle(entry.ctx, record) _ = 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) { func (entry *Entry) Debugf(format string, args ...any) {
message := fmt.Sprintf(format, args...) 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()...) record.AddAttrs(entry.getExtra()...)
_ = entry.handler.Handle(entry.ctx, record) _ = entry.handler.Handle(entry.ctx, record)
} }
func (entry *Entry) Warn(message string, fields ...any) { 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(entry.getExtra()...)
record.AddAttrs(slog.Group("context", fields...)) record.AddAttrs(slog.Group("context", fields...))
_ = entry.handler.Handle(entry.ctx, record) _ = 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) { func (entry *Entry) Warnf(format string, args ...any) {
message := fmt.Sprintf(format, args...) 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()...) record.AddAttrs(entry.getExtra()...)
_ = entry.handler.Handle(entry.ctx, record) _ = entry.handler.Handle(entry.ctx, record)
} }
func (entry *Entry) getCaller() uintptr { func (entry *Entry) getCaller() caller.Caller {
if entry.caller != 0 { if entry.caller.PC != 0 {
return entry.caller return entry.caller
} }
return GetCaller(4) return caller.New(4)
}
func GetCaller(skip int) uintptr {
pc := make([]uintptr, 1)
n := runtime.Callers(skip, pc)
if n == 0 {
return 0
}
return pc[0]
} }
func (entry *Entry) getExtra() []slog.Attr { func (entry *Entry) getExtra() []slog.Attr {

View file

@ -7,11 +7,11 @@ import (
"io" "io"
"log/slog" "log/slog"
"os" "os"
"runtime"
"strings" "strings"
"sync" "sync"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/tigorlazuardi/redmage/caller"
) )
type PrettyHandler struct { type PrettyHandler struct {
@ -89,7 +89,7 @@ func (pr *PrettyHandler) Handle(ctx context.Context, record slog.Record) error {
defer putBuffer(jsonBuf) defer putBuffer(jsonBuf)
if record.PC != 0 && pr.opts.AddSource { 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, frame.File)
levelColor.Fprint(buf, ":") levelColor.Fprint(buf, ":")
levelColor.Fprint(buf, frame.Line) levelColor.Fprint(buf, frame.Line)
@ -118,7 +118,7 @@ func (pr *PrettyHandler) Handle(ctx context.Context, record slog.Record) error {
_ = serializer.Handle(ctx, record) _ = serializer.Handle(ctx, record)
if jsonBuf.Len() > 3 { // Ignore empty json like "{}\n" if jsonBuf.Len() > 3 { // Ignore empty json like "{}\n"
_ = json.Indent(buf, jsonBuf.Bytes(), "", " ") _ = 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 { } else {
buf.WriteByte('\n') buf.WriteByte('\n')
} }
@ -148,12 +148,6 @@ func (pr *PrettyHandler) createSerializer(w io.Writer) slog.Handler {
return jsonHandler return jsonHandler
} }
func getFrame(pc uintptr) runtime.Frame {
frames := runtime.CallersFrames([]uintptr{pc})
frame, _ := frames.Next()
return frame
}
func (pr *PrettyHandler) clone() *PrettyHandler { func (pr *PrettyHandler) clone() *PrettyHandler {
return &PrettyHandler{ return &PrettyHandler{
opts: pr.opts, opts: pr.opts,