flog/log.go

94 lines
1.7 KiB
Go

package flog
import (
"fmt"
"runtime"
"strings"
"sync"
"time"
)
// All log functions
var (
Debug = logFunc(LevelDebug)
Info = logFunc(LevelInfo)
Warning = logFunc(LevelWarning)
Error = logFunc(LevelError)
Critical = logFunc(LevelCritical)
)
func logFunc(level LevelType) func(...interface{}) {
return func(message ...interface{}) {
writeMessage(level, message)
}
}
var mu sync.Mutex
func writeMessage(level LevelType, message []interface{}) {
if MinLevel > level {
return
}
entry := LogEntry{
Level: level,
Time: time.Now(),
Message: fmt.Sprint(message...),
}
if MinStackLevel <= level {
entry.StackTrace = getStackTrace()
}
mu.Lock()
defer mu.Unlock()
Format.FormatMessage(getOutput(), entry)
}
func getStackTrace() (stackTrace []StackTraceEntry) {
_, filename, _, _ := runtime.Caller(1)
pc := make([]uintptr, 50)
entries := runtime.Callers(2, pc)
frames := runtime.CallersFrames(pc[:entries])
more, firstLine := true, false
for more {
var frame runtime.Frame
frame, more = frames.Next()
if !firstLine && frame.File == filename { // Skip frames from the flog cal
continue
}
firstLine = true
if frame.Function == `runtime.gopanic` { // If a panic occurred, start at the frame that called panic
stackTrace = nil
continue
}
stackTrace = append(stackTrace, StackTraceEntry{
Function: cleanFunction(frame.Function),
File: cleanFilename(frame.File),
Line: frame.Line,
})
}
return
}
func cleanFunction(f string) string {
parts := strings.Split(f, `/vendor/`)
return parts[len(parts)-1]
}
func cleanFilename(file string) string {
parts := strings.Split(file, `/src/`)
if len(parts) < 2 {
return file
}
return strings.Join(parts[1:], `/`)
}