144 lines
2.9 KiB
Go
144 lines
2.9 KiB
Go
// Copyright 2023 Martin Riedl
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package log
|
|
|
|
import (
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var Default = NewLoggerDefault()
|
|
|
|
const maxCallersPCs = 20
|
|
|
|
type Logger struct {
|
|
Outputs []*Output
|
|
}
|
|
|
|
func NewLogger(outputs []*Output) *Logger {
|
|
return &Logger{
|
|
Outputs: outputs,
|
|
}
|
|
}
|
|
|
|
func NewLoggerDefault() *Logger {
|
|
return NewLogger([]*Output{NewOutputDefault()})
|
|
}
|
|
|
|
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)
|
|
continue
|
|
}
|
|
|
|
// ignore self
|
|
currentPackage := logger.framePackage(frame)
|
|
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...)
|
|
}
|
|
|
|
func (logger *Logger) With(key string, value any) *Entry {
|
|
entry := NewEntry(logger)
|
|
entry.With(key, value)
|
|
return entry
|
|
}
|
|
|
|
func (logger *Logger) WithContent(content []Content) *Entry {
|
|
entry := NewEntry(logger)
|
|
entry.WithContent(content)
|
|
return entry
|
|
}
|
|
|
|
func (logger *Logger) Fatal(args ...any) {
|
|
logger.Log(LevelFatal, args...)
|
|
}
|
|
|
|
func (logger *Logger) Error(args ...any) {
|
|
logger.Log(LevelError, args...)
|
|
}
|
|
|
|
func (logger *Logger) Warning(args ...any) {
|
|
logger.Log(LevelWarning, args...)
|
|
}
|
|
|
|
func (logger *Logger) Info(args ...any) {
|
|
logger.Log(LevelInfo, args...)
|
|
}
|
|
|
|
func (logger *Logger) Debug(args ...any) {
|
|
logger.Log(LevelDebug, args...)
|
|
}
|
|
|
|
func (logger *Logger) Trace(args ...any) {
|
|
logger.Log(LevelTrace, args...)
|
|
}
|