1
0
Fork 0

Adding upstream version 3.10.8.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-18 09:37:23 +02:00
parent 37e9b6d587
commit 03bfe4079e
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
356 changed files with 28857 additions and 0 deletions

24
logger/context.go Normal file
View file

@ -0,0 +1,24 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package logger
import (
"context"
)
type key int
const (
loggerKey key = iota + 1
)
func ContextSetLogger(ctx context.Context, value Interface) context.Context {
return context.WithValue(ctx, loggerKey, value)
}
func ContextGetLogger(ctx context.Context) Interface {
value, _ := ctx.Value(loggerKey).(Interface)
return value
}

20
logger/context_test.go Normal file
View file

@ -0,0 +1,20 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package logger
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
)
func Test_LoggerContext(t *testing.T) {
ctx := context.Background()
assert.Nil(t, ContextGetLogger(ctx))
logger := NewLogger()
ctx = ContextSetLogger(ctx, logger)
assert.EqualValues(t, logger, ContextGetLogger(ctx))
}

70
logger/interface.go Normal file
View file

@ -0,0 +1,70 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package logger
import (
"bytes"
)
type Level int
const (
_ = iota
Message Level = iota
Trace Level = iota
Debug Level = iota
Info Level = iota
Warn Level = iota
Error Level = iota
Fatal Level = iota
)
var toString = map[Level]string{
Message: "message",
Trace: "trace",
Debug: "debug",
Info: "info",
Warn: "warn",
Error: "error",
Fatal: "fatal",
}
func (l Level) String() string {
s, ok := toString[l]
if ok {
return s
}
return "undefined"
}
type Fun func(string, ...any)
type CaptureInterface interface {
Interface
GetBuffer() *bytes.Buffer
String() string
Reset()
}
type MessageInterface interface {
Message(string, ...any)
Trace(string, ...any)
Debug(string, ...any)
Info(string, ...any)
Warn(string, ...any)
Error(string, ...any)
Fatal(string, ...any)
Log(skip int, level Level, message string, args ...any)
}
type ManageInterface interface {
SetLevel(level Level)
GetLevel() Level
}
type Interface interface {
MessageInterface
ManageInterface
}

230
logger/logger.go Normal file
View file

@ -0,0 +1,230 @@
// 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)
}
}

29
logger/logger_test.go Normal file
View file

@ -0,0 +1,29 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package logger
import (
"testing"
)
func Test_Logger(t *testing.T) {
for _, testCase := range []struct {
expected string
level Level
call func(MessageInterface, string, ...any)
}{
{expected: "level=INFO ", level: Info, call: func(logger MessageInterface, message string, args ...any) { logger.Message(message, args...) }},
{expected: "level=DEBUG-1 ", level: Trace, call: func(logger MessageInterface, message string, args ...any) { logger.Trace(message, args...) }},
{expected: "level=DEBUG ", level: Debug, call: func(logger MessageInterface, message string, args ...any) { logger.Debug(message, args...) }},
{expected: "level=INFO ", level: Info, call: func(logger MessageInterface, message string, args ...any) { logger.Info(message, args...) }},
{expected: "level=WARN ", level: Warn, call: func(logger MessageInterface, message string, args ...any) { logger.Warn(message, args...) }},
{expected: "level=ERROR ", level: Error, call: func(logger MessageInterface, message string, args ...any) { logger.Error(message, args...) }},
{expected: "level=ERROR+1 ", level: Fatal, call: func(logger MessageInterface, message string, args ...any) { logger.Fatal(message, args...) }},
} {
t.Run(testCase.expected+testCase.level.String(), func(t *testing.T) {
testLoggerCase(t, testCase.expected, testCase.level, testCase.call)
})
}
}

View file

@ -0,0 +1,54 @@
// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package logger
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func testLoggerCase(t *testing.T, expected string, level Level, loggerFunc func(MessageInterface, string, ...any)) {
logger := NewCaptureLogger()
logger.SetLevel(level)
messages := []string{
"MESSAGE HERE",
}
moreVerbose := MoreVerbose(level)
if moreVerbose != nil {
messages = append(messages, "MESSAGE MORE VERBOSE")
}
lessVerbose := LessVerbose(level)
if lessVerbose != nil {
messages = append(messages, "MESSAGE LESS VERBOSE")
}
loggerFunc(logger, "MESSAGE %s", "HERE")
if moreVerbose != nil {
logger.Log(1, *moreVerbose, "MESSAGE %s", "MORE VERBOSE")
}
if lessVerbose != nil {
logger.Log(1, *lessVerbose, "MESSAGE %s", "LESS VERBOSE")
}
i := 0
assert.Contains(t, logger.String(), messages[i])
if moreVerbose != nil {
i++
require.True(t, len(messages) > i)
assert.NotContains(t, logger.String(), messages[i])
}
if lessVerbose != nil {
i++
require.True(t, len(messages) > i)
assert.Contains(t, logger.String(), messages[i])
}
assert.Contains(t, logger.String(), expected)
// verifies the call stack is calculated correctly and this is the
// reason for having this function in a separate file
assert.Contains(t, logger.String(), "logger_test.go")
}