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"
"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 {

View file

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