Skip to content

Commit 8112997

Browse files
add and use slog adapter (#123)
1 parent 2998911 commit 8112997

File tree

4 files changed

+160
-6
lines changed

4 files changed

+160
-6
lines changed

cmd/depserver/main.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package main
33
import (
44
"flag"
55
"fmt"
6-
stdlog "log"
6+
stdslog "log/slog"
77
"math/rand"
88
"net/http"
99
"os"
@@ -13,11 +13,12 @@ import (
1313
"github.com/micromdm/nanodep/client"
1414
dephttp "github.com/micromdm/nanodep/http"
1515
"github.com/micromdm/nanodep/http/api"
16+
"github.com/micromdm/nanodep/log/caller"
17+
"github.com/micromdm/nanodep/log/slog"
1618
"github.com/micromdm/nanodep/proxy"
1719

1820
"github.com/google/uuid"
1921
"github.com/micromdm/nanolib/envflag"
20-
"github.com/micromdm/nanolib/log/stdlogfmt"
2122
)
2223

2324
// overridden by -ldflags -X
@@ -59,10 +60,11 @@ func main() {
5960
os.Exit(1)
6061
}
6162

62-
logger := stdlogfmt.New(
63-
stdlogfmt.WithLogger(stdlog.Default()),
64-
stdlogfmt.WithDebugFlag(*flDebug),
65-
)
63+
level := stdslog.LevelInfo
64+
if *flDebug {
65+
level = stdslog.LevelDebug
66+
}
67+
logger := caller.New(slog.New(stdslog.New(stdslog.NewTextHandler(os.Stdout, &stdslog.HandlerOptions{Level: level}))))
6668

6769
storage, err := cli.Storage(*flStorage, *flDSN, *flOptions)
6870
if err != nil {

log/caller/caller.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package caller
2+
3+
import (
4+
"fmt"
5+
"path/filepath"
6+
"runtime"
7+
8+
"github.com/micromdm/nanolib/log"
9+
)
10+
11+
// Logger wraps another logger and adds callsite information to the logs.
12+
// Be careful about placement and usage of this logger as correct
13+
// reporting of the callsite depends on call depth/stack frame location.
14+
type Logger struct {
15+
logger log.Logger
16+
lctx []interface{}
17+
skip int
18+
}
19+
20+
type Option func(*Logger)
21+
22+
// WithSkip skips over any additional stack frames.
23+
// The argument skip is the number of additional stack frames to ascend.
24+
// This option is unnecessary if this logger is the "top" of the logging stack.
25+
func WithSkip(skip int) Option {
26+
return func(l *Logger) {
27+
l.skip = skip
28+
}
29+
}
30+
31+
func New(logger log.Logger, opts ...Option) *Logger {
32+
if logger == nil {
33+
panic("nil logger")
34+
}
35+
l := &Logger{logger: logger}
36+
for _, opt := range opts {
37+
opt(l)
38+
}
39+
return l
40+
}
41+
42+
// caller returns filename:lineno
43+
func caller(skip int) string {
44+
_, filename, line, _ := runtime.Caller(skip + 1) // skip past *this* func
45+
return fmt.Sprintf("%s:%d", filepath.Base(filename), line)
46+
}
47+
48+
// Info logs at the info level with caller info.
49+
func (logger *Logger) Info(logs ...interface{}) {
50+
logs = append(logs, "caller", caller(logger.skip+1))
51+
logger.logger.Info(append(logger.lctx, logs...)...)
52+
}
53+
54+
// Debug logs at the debug level with caller info.
55+
func (logger *Logger) Debug(logs ...interface{}) {
56+
logs = append(logs, "caller", caller(logger.skip+1))
57+
logger.logger.Debug(append(logger.lctx, logs...)...)
58+
}
59+
60+
// With returns a logger with additoinal context.
61+
func (logger *Logger) With(logs ...interface{}) log.Logger {
62+
logger2 := *logger
63+
logger2.lctx = append(logger2.lctx, logs...)
64+
return &logger2
65+
}

log/slog/slog.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package slog
2+
3+
import (
4+
"log/slog"
5+
6+
"github.com/micromdm/nanolib/log"
7+
)
8+
9+
// Logger wraps stdlib slog for logging.
10+
type Logger struct {
11+
lctx []any
12+
slogger *slog.Logger
13+
}
14+
15+
func New(slogger *slog.Logger) *Logger {
16+
if slogger == nil {
17+
panic("nil slogger")
18+
}
19+
return &Logger{slogger: slogger}
20+
}
21+
22+
func extractMsg(logs []any) (string, []any) {
23+
if len(logs) < 2 {
24+
return "", logs
25+
}
26+
for i := 0; i < len(logs); i += 2 {
27+
if field, ok := logs[i].(string); ok && field == "msg" {
28+
if i+1 < len(logs) {
29+
if field, ok = logs[i+1].(string); ok {
30+
return field, append(logs[0:i], logs[i+2:]...)
31+
}
32+
}
33+
}
34+
}
35+
return "", logs
36+
}
37+
38+
// Info logs to the slog at the info level.
39+
func (logger *Logger) Info(logs ...interface{}) {
40+
allLogs := append(logger.lctx, logs...)
41+
msg, msglessLogs := extractMsg(allLogs)
42+
logger.slogger.Info(msg, msglessLogs...)
43+
}
44+
45+
// Debug logs to the slog with at the debug level.
46+
func (logger *Logger) Debug(logs ...interface{}) {
47+
allLogs := append(logger.lctx, logs...)
48+
msg, msglessLogs := extractMsg(allLogs)
49+
logger.slogger.Debug(msg, msglessLogs...)
50+
}
51+
52+
// With returns a logger with additoinal context.
53+
func (logger *Logger) With(logs ...interface{}) log.Logger {
54+
logger2 := *logger
55+
logger2.lctx = append(logger2.lctx, logs...)
56+
return &logger2
57+
}

log/slog/slog_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package slog
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestContext(t *testing.T) {
9+
logger := &Logger{}
10+
logger2 := logger.With("msg1", "hello")
11+
logger3 := logger2.With("msg2", "world")
12+
logger4 := logger3.(*Logger)
13+
14+
if have, want := len(logger4.lctx), 4; have != want {
15+
t.Errorf("length: have: %v, want: %v", have, want)
16+
}
17+
}
18+
19+
func TestExtractMsg(t *testing.T) {
20+
logs := []any{"foo", "bar", "msg", "wow", "hello", "world"}
21+
msg, msglessLogs := extractMsg(logs)
22+
23+
if have, want := msg, "wow"; have != want {
24+
t.Errorf("msg: have: %v, want: %v", have, want)
25+
}
26+
27+
if have, want := msglessLogs, []any{"foo", "bar", "hello", "world"}; !reflect.DeepEqual(have, want) {
28+
t.Errorf("msg: have: %v, want: %v", have, want)
29+
}
30+
}

0 commit comments

Comments
 (0)