-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhandler.go
More file actions
122 lines (101 loc) · 2.77 KB
/
handler.go
File metadata and controls
122 lines (101 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package alog
import (
"context"
"io"
"log/slog"
"os"
"strings"
)
// ContextKey is the type used for context keys in the alog package
type ContextKey string
// LogAttrKey is the context key used to store log attributes
const LogAttrKey ContextKey = "alog_attributes"
// LoggerOptions holds configuration for creating a new logger
type LoggerOptions struct {
Output io.Writer
Level slog.Level
Source bool
Attrs []slog.Attr
}
// LoggerOptionsFunc is a function that modifies LoggerOptions
type LoggerOptionsFunc func(*LoggerOptions)
// WithOutput sets the output writer for the logger
func WithOutput(w io.Writer) LoggerOptionsFunc {
return func(o *LoggerOptions) {
o.Output = w
}
}
// WithLevel sets the minimum log level
func WithLevel(l slog.Level) LoggerOptionsFunc {
return func(o *LoggerOptions) {
o.Level = l
}
}
// WithSource enables or disables source code location in logs
func WithSource(b bool) LoggerOptionsFunc {
return func(o *LoggerOptions) {
o.Source = b
}
}
// WithAttrs adds default attributes to the logger
func WithAttrs(attrs ...slog.Attr) LoggerOptionsFunc {
return func(o *LoggerOptions) {
o.Attrs = attrs
}
}
// Logger creates a new slog.Logger with the specified options
func Logger(opts ...LoggerOptionsFunc) *slog.Logger {
options := LoggerOptions{
Output: os.Stdout,
Level: slog.LevelInfo,
Source: true,
Attrs: nil,
}
for _, opt := range opts {
opt(&options)
}
jsonLogHandler := slog.NewJSONHandler(options.Output, &slog.HandlerOptions{
AddSource: options.Source,
Level: options.Level,
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == "msg" {
a.Key = "message"
}
if a.Key == "level" {
a.Key = "severity"
a.Value = slog.StringValue(strings.ToLower(a.Value.String()))
}
return a
},
}).WithAttrs(options.Attrs)
// Wrap the JSON handler with our context-aware handler
logger := slog.New(&contextHandler{Handler: jsonLogHandler})
return logger
}
// contextHandler is a slog.Handler that extracts attributes from the context
type contextHandler struct {
slog.Handler
}
// Handle implements slog.Handler.Handle by extracting attributes from ctx
func (h *contextHandler) Handle(ctx context.Context, r slog.Record) error {
if ctx != nil {
if attrs, ok := ctx.Value(LogAttrKey).([]slog.Attr); ok && len(attrs) > 0 {
for _, attr := range attrs {
r.AddAttrs(attr)
}
}
}
return h.Handler.Handle(ctx, r)
}
// Append adds a key-value pair to the context for logging
func Append(ctx context.Context, attr slog.Attr) context.Context {
if ctx == nil {
ctx = context.Background()
}
var attrs []slog.Attr
if existingAttrs, ok := ctx.Value(LogAttrKey).([]slog.Attr); ok {
attrs = existingAttrs
}
attrs = append(attrs, attr)
return context.WithValue(ctx, LogAttrKey, attrs)
}