85 lines
1.5 KiB
Go
85 lines
1.5 KiB
Go
package caller
|
|
|
|
import (
|
|
"context"
|
|
"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) ShortFile() string {
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
return ca.Frame.File
|
|
}
|
|
if after, found := strings.CutPrefix(ca.Frame.File, wd); found {
|
|
return strings.TrimPrefix(after, string(os.PathSeparator))
|
|
}
|
|
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.ShortFile()),
|
|
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
|
|
}
|
|
|
|
type contextKey struct{}
|
|
|
|
func WithContext(ctx context.Context, caller Caller) context.Context {
|
|
return context.WithValue(ctx, contextKey{}, caller)
|
|
}
|
|
|
|
func FromContext(ctx context.Context) (Caller, bool) {
|
|
call, ok := ctx.Value(contextKey{}).(Caller)
|
|
return call, ok
|
|
}
|