Skip to content

Commit 6a49847

Browse files
committed
feat(logr): init
1 parent 261b8ad commit 6a49847

File tree

7 files changed

+305
-0
lines changed

7 files changed

+305
-0
lines changed

logr/level.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package logr
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
// Level type
9+
type Level uint32
10+
11+
const (
12+
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
13+
// Commonly used for hooks to send errors to an error tracking service.
14+
ErrorLevel Level = iota
15+
// WarnLevel level. Non-critical entries that deserve eyes.
16+
WarnLevel
17+
// InfoLevel level. General operational entries about what's going on inside the
18+
// application.
19+
InfoLevel
20+
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
21+
DebugLevel
22+
)
23+
24+
func (level Level) String() string {
25+
if b, err := level.MarshalText(); err == nil {
26+
return string(b)
27+
} else {
28+
return "unknown"
29+
}
30+
}
31+
32+
// ParseLevel takes a string level and returns the Logrus log level constant.
33+
func ParseLevel(lvl string) (Level, error) {
34+
switch strings.ToLower(lvl) {
35+
case "error":
36+
return ErrorLevel, nil
37+
case "warn", "warning":
38+
return WarnLevel, nil
39+
case "info":
40+
return InfoLevel, nil
41+
case "debug":
42+
return DebugLevel, nil
43+
}
44+
return 0, fmt.Errorf("not a valid logrus Level: %q", lvl)
45+
}
46+
47+
func (level *Level) UnmarshalText(text []byte) error {
48+
l, err := ParseLevel(string(text))
49+
if err != nil {
50+
return err
51+
}
52+
*level = l
53+
return nil
54+
}
55+
56+
func (level Level) MarshalText() ([]byte, error) {
57+
switch level {
58+
case DebugLevel:
59+
return []byte("debug"), nil
60+
case InfoLevel:
61+
return []byte("info"), nil
62+
case WarnLevel:
63+
return []byte("warning"), nil
64+
case ErrorLevel:
65+
return []byte("error"), nil
66+
}
67+
return nil, fmt.Errorf("not a valid logrus level %d", level)
68+
}

logr/logr.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package logr
2+
3+
import (
4+
"context"
5+
)
6+
7+
type Logger interface {
8+
// Start start span for tracing
9+
//
10+
// ctx log = logr.Start(ctx, "SpanName")
11+
// defer log.End()
12+
//
13+
Start(ctx context.Context, name string, keyAndValues ...any) (context.Context, Logger)
14+
// End end span
15+
End()
16+
17+
// WithValues key value pairs
18+
WithValues(keyAndValues ...any) Logger
19+
20+
// Debug debug info
21+
Debug(msg string, args ...any)
22+
// Info info
23+
Info(msg string, args ...any)
24+
25+
// Warn
26+
Warn(err error)
27+
28+
// Error
29+
Error(err error)
30+
}

logr/logr_ctx.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package logr
2+
3+
import "context"
4+
5+
type contextKey struct{}
6+
7+
func WithLogger(ctx context.Context, logger Logger) context.Context {
8+
return context.WithValue(ctx, contextKey{}, logger)
9+
}
10+
11+
func FromContext(ctx context.Context) Logger {
12+
if v, ok := ctx.Value(contextKey{}).(Logger); ok {
13+
return v
14+
}
15+
return Discard()
16+
}
17+
18+
func Start(ctx context.Context, name string, keyAndValues ...any) (context.Context, Logger) {
19+
return FromContext(ctx).Start(ctx, name, keyAndValues...)
20+
}
21+
22+
func LoggerFromContext(ctx context.Context) (Logger, bool) {
23+
v, ok := ctx.Value(contextKey{}).(Logger)
24+
return v, ok
25+
}
26+
27+
func LoggerInjectContext(ctx context.Context, logger Logger) context.Context {
28+
return context.WithValue(ctx, contextKey{}, logger)
29+
}

logr/logr_discord.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package logr
2+
3+
import "context"
4+
5+
func Discard() Logger {
6+
return &discardLogger{}
7+
}
8+
9+
type discardLogger struct{}
10+
11+
func (d *discardLogger) WithValues(keyAndValues ...any) Logger {
12+
return d
13+
}
14+
15+
func (d *discardLogger) Start(ctx context.Context, name string, keyAndValues ...any) (context.Context, Logger) {
16+
return ctx, d
17+
}
18+
19+
func (discardLogger) End() {
20+
}
21+
22+
func (discardLogger) Debug(format string, args ...any) {
23+
}
24+
25+
func (discardLogger) Info(format string, args ...any) {
26+
}
27+
28+
func (discardLogger) Warn(err error) {
29+
}
30+
31+
func (discardLogger) Error(err error) {
32+
}

logr/logr_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package logr_test
2+
3+
import (
4+
"context"
5+
stdslog "log/slog"
6+
7+
"github.com/octohelm/x/logr"
8+
"github.com/octohelm/x/logr/slog"
9+
)
10+
11+
func ExampleLogger() {
12+
ctx := logr.WithLogger(context.Background(), slog.Logger(slog.Default()))
13+
14+
log := logr.FromContext(ctx).WithValues("k", "k")
15+
16+
log.Debug("test %d", 1)
17+
log.Info("test %d", 1)
18+
// Output:
19+
}
20+
21+
func ExampleLogger_Start() {
22+
ctx := logr.WithLogger(context.Background(), slog.Logger(slog.Default(slog.EnableLevel(stdslog.LevelDebug))))
23+
24+
_, log := logr.Start(ctx, "span", "k", "k")
25+
defer log.End()
26+
27+
log.Debug("test %d", 1)
28+
log.Info("test %d", 1)
29+
// Output:
30+
}

logr/slog/handler.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package slog
2+
3+
import (
4+
"context"
5+
"log/slog"
6+
)
7+
8+
func EnableLevel(lvl slog.Level) func(h *handler) {
9+
return func(h *handler) {
10+
h.lvl = lvl
11+
}
12+
}
13+
14+
func Default(optFns ...func(h *handler)) *slog.Logger {
15+
h := &handler{h: slog.Default().Handler()}
16+
for _, fn := range optFns {
17+
fn(h)
18+
}
19+
return slog.New(h)
20+
}
21+
22+
type handler struct {
23+
h slog.Handler
24+
lvl slog.Level
25+
}
26+
27+
func (h *handler) Handle(ctx context.Context, r slog.Record) error {
28+
return h.h.Handle(ctx, r)
29+
}
30+
31+
func (h *handler) WithAttrs(attrs []slog.Attr) slog.Handler {
32+
return &handler{h: h.h.WithAttrs(attrs)}
33+
}
34+
35+
func (h *handler) WithGroup(name string) slog.Handler {
36+
return &handler{h: h.h.WithGroup(name)}
37+
}
38+
39+
func (h *handler) Enabled(ctx context.Context, l slog.Level) bool {
40+
return l >= h.lvl
41+
}

logr/slog/logger.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package slog
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log/slog"
7+
"strings"
8+
9+
"github.com/octohelm/x/logr"
10+
)
11+
12+
func Logger(l *slog.Logger) logr.Logger {
13+
return &logger{slog: l, ctx: context.Background()}
14+
}
15+
16+
type logger struct {
17+
ctx context.Context
18+
slog *slog.Logger
19+
spans []string
20+
}
21+
22+
func (d *logger) WithValues(keyAndValues ...any) logr.Logger {
23+
return &logger{
24+
spans: d.spans,
25+
slog: d.slog.With(keyAndValues...),
26+
}
27+
}
28+
29+
func (d *logger) Start(ctx context.Context, name string, keyAndValues ...any) (context.Context, logr.Logger) {
30+
spans := append(d.spans, name)
31+
32+
if len(keyAndValues) == 0 {
33+
return ctx, &logger{
34+
ctx: ctx,
35+
spans: spans,
36+
slog: d.slog.WithGroup(strings.Join(spans, "/")),
37+
}
38+
}
39+
40+
return ctx, &logger{
41+
spans: spans,
42+
slog: d.slog.WithGroup(strings.Join(spans, "/")).With(keyAndValues...),
43+
}
44+
}
45+
46+
func (d *logger) End() {
47+
if len(d.spans) != 0 {
48+
d.spans = d.spans[0 : len(d.spans)-1]
49+
}
50+
}
51+
52+
func (d *logger) Debug(format string, args ...any) {
53+
if !d.slog.Enabled(d.ctx, slog.LevelDebug) {
54+
return
55+
}
56+
d.slog.Log(d.ctx, slog.LevelDebug, fmt.Sprintf(format, args...))
57+
}
58+
59+
func (d *logger) Info(format string, args ...any) {
60+
if !d.slog.Enabled(d.ctx, slog.LevelInfo) {
61+
return
62+
}
63+
d.slog.Log(d.ctx, slog.LevelInfo, fmt.Sprintf(format, args...))
64+
}
65+
66+
func (d *logger) Warn(err error) {
67+
if !d.slog.Enabled(d.ctx, slog.LevelWarn) {
68+
return
69+
}
70+
d.slog.Log(d.ctx, slog.LevelWarn, err.Error(), slog.Any("err", err))
71+
}
72+
73+
func (d *logger) Error(err error) {
74+
d.slog.Error("", slog.Any("error", err))
75+
}

0 commit comments

Comments
 (0)