1
0
Fork 0
golang-forgejo-f3-gof3/logger/logger.go
Daniel Baumann 03bfe4079e
Adding upstream version 3.10.8.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-18 09:37:23 +02:00

230 lines
5.4 KiB
Go

// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package logger
import (
"bytes"
"context"
"fmt"
"io"
"log/slog"
"os"
"runtime"
"strings"
"time"
)
type logger struct {
levels map[Level]int
writer io.Writer
logger *slog.Logger
level Level
levelVar *slog.LevelVar
}
var levels = map[Level]int{
Trace: int(slog.LevelDebug) - 1,
Debug: int(slog.LevelDebug),
Info: int(slog.LevelInfo),
Warn: int(slog.LevelWarn),
Error: int(slog.LevelError),
Fatal: int(slog.LevelError + 1),
}
var levelList = []Level{
Trace,
Debug,
Info,
Warn,
Error,
Fatal,
}
func MoreVerbose(level Level) *Level {
position := levelToPosition(level) - 1
if position > 0 {
return &levelList[position]
}
return nil
}
func LessVerbose(level Level) *Level {
position := levelToPosition(level) + 1
if position < len(levelList) {
return &levelList[position]
}
return nil
}
func levelToPosition(level Level) int {
var i int
for i = 0; i < len(levelList); i++ {
if levelList[i] == level {
break
}
}
if i >= len(levelList) {
panic(fmt.Errorf("unknown verbosity %v", level))
}
return i
}
func NewLogger() Interface {
l := &logger{}
l.Init()
return l
}
type captureLogger struct {
logger
buf *bytes.Buffer
}
func NewCaptureLogger() CaptureInterface {
l := &captureLogger{}
l.buf = new(bytes.Buffer)
l.writer = l.buf
l.Init()
return l
}
func (o *captureLogger) String() string {
return o.buf.String()
}
func (o *captureLogger) GetBuffer() *bytes.Buffer {
return o.buf
}
func (o *captureLogger) Reset() {
o.buf.Reset()
}
var filenamePrefix string
func init() {
_, filename, _, _ := runtime.Caller(0)
filenamePrefix = strings.TrimSuffix(filename, "logger.go")
if filenamePrefix == filename {
// in case the source code file is moved, we can not trim the suffix, the code above should also be updated.
panic("unable to detect correct package prefix, please update file: " + filename)
}
}
func (o *logger) Log(skip int, level Level, format string, args ...any) {
slogLevel := levels[level]
logger := o.logger
if !logger.Handler().Enabled(context.Background(), slog.Level(slogLevel)) {
return
}
var pcs [1]uintptr
runtime.Callers(2+skip, pcs[:]) // 2 is to skip [Callers(), Log()]
r := slog.NewRecord(time.Now(), slog.Level(slogLevel), fmt.Sprintf(format, args...), pcs[0])
_ = logger.Handler().Handle(context.Background(), r)
}
func (o *logger) Init() {
replace := func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey && len(groups) == 0 {
return slog.Attr{}
}
if a.Key == slog.SourceKey {
source := a.Value.Any().(*slog.Source)
var function string
dot := strings.LastIndex(source.Function, ".")
if dot >= 0 {
function = ":" + source.Function[dot+1:]
}
source.File = strings.TrimPrefix(source.File, projectPackagePrefix) + function
}
return a
}
o.levelVar = new(slog.LevelVar)
if o.writer == nil {
o.writer = os.Stdout
}
o.logger = slog.New(slog.NewTextHandler(o.writer, &slog.HandlerOptions{
Level: o.levelVar,
AddSource: true,
ReplaceAttr: replace,
}))
}
func (o *logger) SetLevel(level Level) {
o.level = level
o.levelVar.Set(slog.Level(levels[o.level]))
}
func (o *logger) GetLevel() Level {
return o.level
}
func (o *logger) SetWriter(out io.Writer) {
o.writer = out
o.Init()
}
func (o *logger) Message(message string, args ...any) { o.Log(1, Info, message, args...) }
func (o *logger) Trace(message string, args ...any) { o.Log(1, Trace, message, args...) }
func (o *logger) Debug(message string, args ...any) { o.Log(1, Debug, message, args...) }
func (o *logger) Info(message string, args ...any) { o.Log(1, Info, message, args...) }
func (o *logger) Warn(message string, args ...any) { o.Log(1, Warn, message, args...) }
func (o *logger) Error(message string, args ...any) { o.Log(1, Error, message, args...) }
func (o *logger) Fatal(message string, args ...any) { o.Log(1, Fatal, message, args...) }
type Logger struct {
logger Interface
}
func (o *Logger) GetLogger() Interface { return o.logger }
func (o *Logger) SetLogger(logger Interface) { o.logger = logger }
func (o *Logger) SetLevel(level Level) { o.logger.SetLevel(level) }
func (o *Logger) GetLevel() Level { return o.logger.GetLevel() }
func (o *Logger) Message(message string, args ...any) {
o.logger.Log(1, Message, message, args...)
}
func (o *Logger) Trace(message string, args ...any) {
o.logger.Log(1, Trace, message, args...)
}
func (o *Logger) Debug(message string, args ...any) {
o.logger.Log(1, Debug, message, args...)
}
func (o *Logger) Info(message string, args ...any) {
o.logger.Log(1, Info, message, args...)
}
func (o *Logger) Warn(message string, args ...any) {
o.logger.Log(1, Warn, message, args...)
}
func (o *Logger) Error(message string, args ...any) {
o.logger.Log(1, Error, message, args...)
}
func (o *Logger) Fatal(message string, args ...any) {
o.logger.Log(1, Fatal, message, args...)
}
func (o *Logger) Log(skip int, level Level, message string, args ...any) {
o.logger.Log(skip+1, level, message, args...)
}
var projectPackagePrefix string
func init() {
_, filename, _, _ := runtime.Caller(0)
projectPackagePrefix = strings.TrimSuffix(filename, "logger/logger.go")
if projectPackagePrefix == filename {
// in case the source code file is moved, we can not trim the suffix, the code above should also be updated.
panic("unable to detect correct package prefix, please update file: " + filename)
}
}