feat: add caller information

This commit is contained in:
Martin Riedl 2024-01-04 15:14:54 +01:00
parent 6353cb045a
commit a98708a4a9
Signed by: martinr92
GPG key ID: FB68DA65516A804C
4 changed files with 86 additions and 6 deletions

View file

@ -16,6 +16,7 @@ package golog
import (
"fmt"
"runtime"
"time"
)
@ -25,6 +26,7 @@ type Entry struct {
Message string
Level Level
Time time.Time
CallStack []runtime.Frame
}
type Content struct {

View file

@ -16,6 +16,7 @@ package golog
import (
"encoding/json"
"fmt"
"log"
"time"
)
@ -47,6 +48,13 @@ func (formatter *FormatterJSON) Process(entry *Entry) {
// add message
formatter.data["message"] = entry.Message
// add call stack
if len(entry.CallStack) > 0 {
caller := entry.CallStack[0]
formatter.data["file"] = fmt.Sprintf("%s:%d", caller.File, caller.Line)
formatter.data["function"] = caller.Function
}
// add additional fields
if formatter.FlatContent {
for _, content := range entry.Content {

View file

@ -47,6 +47,13 @@ func (formatter *FormatterKeyValue) Process(entry *Entry) {
// add message
formatter.addKV("message", entry.Message)
// add call stack
if len(entry.CallStack) > 0 {
caller := entry.CallStack[0]
formatter.addKV("file", fmt.Sprintf("%s:%d", caller.File, caller.Line))
formatter.addKV("function", caller.Function)
}
// add additional fields
for _, content := range entry.Content {
formatter.addKV(content.Key, content.Value)

View file

@ -14,10 +14,17 @@
package golog
import "time"
import (
"log"
"runtime"
"strings"
"time"
)
var Default = NewLoggerDefault()
const maxCallersPCs = 20
type Logger struct {
Outputs []*Output
}
@ -36,12 +43,68 @@ func (logger *Logger) LogEntry(entry *Entry) {
// set execution time
entry.Time = time.Now()
// set call stack
entry.CallStack = logger.callStack()
// run each output
for _, output := range logger.Outputs {
output.Send(entry)
}
}
func (logger *Logger) callStack() (response []runtime.Frame) {
// get call stack
pcs := make([]uintptr, maxCallersPCs)
runtime.Callers(1, pcs)
frames := runtime.CallersFrames(pcs)
var self string
for {
// check for next frame
frame, more := frames.Next()
if !more {
break
}
// extract self package
if self == "" {
self = logger.framePackage(frame)
log.Println("self:", self, frame.Function) // TODO: remove
continue
}
// ignore self
currentPackage := logger.framePackage(frame)
log.Println("package:", currentPackage, frame.Function) // TODO: remove
if currentPackage != self {
response = append(response, frame)
}
}
return
}
func (logger *Logger) framePackage(frame runtime.Frame) string {
s := frame.Function
// special handling, if no full qualified package exists
lastSlash := strings.LastIndexByte(s, '/')
if lastSlash == -1 {
firstDot := strings.IndexByte(s, '.')
if firstDot == -1 {
return s
}
return s[:firstDot]
}
// extract package
firstDot := strings.IndexByte(s[:lastSlash], '.')
if firstDot == -1 {
return s[:lastSlash]
}
return s[:lastSlash+firstDot]
}
func (logger *Logger) Log(level Level, args ...any) {
entry := NewEntry(logger)
entry.Log(level, args...)