-
Notifications
You must be signed in to change notification settings - Fork 74
Expand file tree
/
Copy pathzerolog_logger.go
More file actions
149 lines (129 loc) · 4.48 KB
/
zerolog_logger.go
File metadata and controls
149 lines (129 loc) · 4.48 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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package ghostferry
import (
"fmt"
"io"
"os"
"sync"
"time"
"github.com/rs/zerolog"
)
// globalZerologMu protects globalZerologLogger during reconfiguration.
var globalZerologMu sync.RWMutex
// globalZerologLogger is the package-level zerolog instance.
// It is initialized to write JSON to os.Stderr with timestamps.
var globalZerologLogger = newGlobalZerolog(os.Stderr)
func newGlobalZerolog(w io.Writer) zerolog.Logger {
return zerolog.New(w).With().Timestamp().Logger()
}
// zerologContextField adds a key-value pair to a zerolog.Context using the
// native typed method when possible, avoiding Interface() reflection for the
// most common types in the codebase (string, int, uint64, uint32, error, etc.).
func zerologContextField(ctx zerolog.Context, key string, value any) zerolog.Context {
switch v := value.(type) {
case string:
return ctx.Str(key, v)
case int:
return ctx.Int(key, v)
case int64:
return ctx.Int64(key, v)
case uint16:
return ctx.Uint16(key, v)
case uint32:
return ctx.Uint32(key, v)
case uint64:
return ctx.Uint64(key, v)
case bool:
return ctx.Bool(key, v)
case error:
return ctx.AnErr(key, v)
case time.Duration:
return ctx.Dur(key, v)
case fmt.Stringer:
return ctx.Stringer(key, v)
default:
return ctx.Interface(key, v)
}
}
// zerologLogger wraps zerolog.Logger to implement the Logger interface.
type zerologLogger struct {
logger zerolog.Logger
}
func (l *zerologLogger) Debug(args ...any) { l.logger.Debug().Msg(fmt.Sprint(args...)) }
func (l *zerologLogger) Debugf(format string, args ...any) { l.logger.Debug().Msgf(format, args...) }
func (l *zerologLogger) Info(args ...any) { l.logger.Info().Msg(fmt.Sprint(args...)) }
func (l *zerologLogger) Infof(format string, args ...any) { l.logger.Info().Msgf(format, args...) }
func (l *zerologLogger) Warn(args ...any) { l.logger.Warn().Msg(fmt.Sprint(args...)) }
func (l *zerologLogger) Warnf(format string, args ...any) { l.logger.Warn().Msgf(format, args...) }
func (l *zerologLogger) Error(args ...any) { l.logger.Error().Msg(fmt.Sprint(args...)) }
func (l *zerologLogger) Errorf(format string, args ...any) { l.logger.Error().Msgf(format, args...) }
func (l *zerologLogger) Panicf(format string, args ...any) { l.logger.Panic().Msgf(format, args...) }
func (l *zerologLogger) WithField(key string, value any) Logger {
return &zerologLogger{logger: zerologContextField(l.logger.With(), key, value).Logger()}
}
func (l *zerologLogger) WithFields(fields Fields) Logger {
ctx := l.logger.With()
for k, v := range fields {
ctx = zerologContextField(ctx, k, v)
}
return &zerologLogger{logger: ctx.Logger()}
}
func (l *zerologLogger) WithError(err error) Logger {
return &zerologLogger{logger: l.logger.With().Err(err).Logger()}
}
// --- internal factory functions (called by logger.go dispatch) ---
func zerologWithField(key string, value any) Logger {
globalZerologMu.RLock()
base := globalZerologLogger
globalZerologMu.RUnlock()
return &zerologLogger{logger: zerologContextField(base.With(), key, value).Logger()}
}
func zerologWithFields(fields Fields) Logger {
globalZerologMu.RLock()
base := globalZerologLogger
globalZerologMu.RUnlock()
ctx := base.With()
for k, v := range fields {
ctx = zerologContextField(ctx, k, v)
}
return &zerologLogger{logger: ctx.Logger()}
}
func zerologWithError(err error) Logger {
globalZerologMu.RLock()
base := globalZerologLogger
globalZerologMu.RUnlock()
return &zerologLogger{logger: base.With().Err(err).Logger()}
}
func newZerologDefaultLogger() Logger {
globalZerologMu.RLock()
base := globalZerologLogger
globalZerologMu.RUnlock()
return &zerologLogger{logger: base}
}
func setZerologLevel(level LogLevel) {
switch level {
case LogLevelDebug:
zerolog.SetGlobalLevel(zerolog.DebugLevel)
case LogLevelInfo:
zerolog.SetGlobalLevel(zerolog.InfoLevel)
case LogLevelWarn:
zerolog.SetGlobalLevel(zerolog.WarnLevel)
case LogLevelError:
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
}
}
func setZerologJSONFormatter() {
// zerolog outputs JSON by default -- this is a no-op.
}
func setZerologOutput(w io.Writer) {
globalZerologMu.Lock()
globalZerologLogger = newGlobalZerolog(w)
globalZerologMu.Unlock()
}
func init() {
// Match logrus field names so the Ruby integration tests (which parse
// JSON output by "msg", "level", "error") work with either backend.
zerolog.MessageFieldName = "msg"
zerolog.ErrorFieldName = "error"
zerolog.TimestampFieldName = "time"
zerolog.LevelFieldName = "level"
}