Codebase list golang-github-go-logr-logr / 52a0608
Add optional CallDepth support This adds an optional extension interface which log implementations may implement, plus a helper function to use this interface if it is supported. Discussed in https://github.com/go-logr/logr/pull/31 and specifically https://github.com/go-logr/logr/pull/31#issuecomment-754180027 Tim Hockin 3 years ago
2 changed file(s) with 80 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
141141
142142 // TODO: consider adding back in format strings if they're really needed
143143 // TODO: consider other bits of zap/zapcore functionality like ObjectMarshaller (for arbitrary objects)
144 // TODO: consider other bits of glog functionality like Flush, InfoDepth, OutputStats
144 // TODO: consider other bits of glog functionality like Flush, OutputStats
145145
146146 // Logger represents the ability to log messages, both errors and not.
147147 type Logger interface {
218218 func NewContext(ctx context.Context, l Logger) context.Context {
219219 return context.WithValue(ctx, contextKey{}, l)
220220 }
221
222 // CallDepthLogger represents a Logger that knows how to climb the call stack
223 // to identify the original call site and can offset the depth by a specified
224 // number of frames. This is useful for users who have helper functions
225 // between the "real" call site and the actual calls to Logger methods.
226 // Implementations that log information about the call site (such as file,
227 // function, or line) would otherwise log information about the intermediate
228 // helper functions.
229 //
230 // This is an optional interface and implementations are not required to
231 // support it.
232 type CallDepthLogger interface {
233 Logger
234
235 // WithCallDepth returns a Logger that will offset the call stack by the
236 // specified number of frames when logging call site information. If depth
237 // is 0 the attribution should be to the direct caller of this method. If
238 // depth is 1 the attribution should skip 1 call frame, and so on.
239 // Successive calls to this are additive.
240 WithCallDepth(depth int) Logger
241 }
242
243 // WithCallDepth returns a Logger that will offset the call stack by the
244 // specified number of frames when logging call site information, if possible.
245 // This is useful for users who have helper functions between the "real" call
246 // site and the actual calls to Logger methods. If depth is 0 the attribution
247 // should be to the direct caller of this function. If depth is 1 the
248 // attribution should skip 1 call frame, and so on. Successive calls to this
249 // are additive.
250 //
251 // If the underlying log implementation supports the CallDepthLogger interface,
252 // the WithCallDepth method will be called and the result returned. If the
253 // implementation does not support CallDepthLogger, the original Logger will be
254 // returned.
255 //
256 // Callers which care about whether this was supported or not should test for
257 // CallDepthLogger support themselves.
258 func WithCallDepth(logger Logger, depth int) Logger {
259 if decorator, ok := logger.(CallDepthLogger); ok {
260 return decorator.WithCallDepth(depth)
261 }
262 return logger
263 }
7373 t.Errorf("expected output to be the same as input: got in=%p, out=%p", logger, out)
7474 }
7575 }
76
77 // testCallDepthLogger is a Logger just for testing that does nothing.
78 type testCallDepthLogger struct {
79 *testLogger
80 depth int
81 }
82
83 func (l *testCallDepthLogger) WithCallDepth(depth int) Logger {
84 return &testCallDepthLogger{l.testLogger, l.depth + depth}
85 }
86
87 // Verify that it actually implements the interface
88 var _ CallDepthLogger = &testCallDepthLogger{}
89
90 func TestWithCallDepth(t *testing.T) {
91 // Test an impl that does not support it.
92 t.Run("not supported", func(t *testing.T) {
93 in := &testLogger{}
94 out := WithCallDepth(in, 42)
95 if out.(*testLogger) != in {
96 t.Errorf("expected output to be the same as input: got in=%p, out=%p", in, out)
97 }
98 })
99
100 // Test an impl that does support it.
101 t.Run("supported", func(t *testing.T) {
102 in := &testCallDepthLogger{&testLogger{}, 0}
103 out := WithCallDepth(in, 42)
104 if out.(*testCallDepthLogger) == in {
105 t.Errorf("expected output to be different than input: got in=out=%p", in)
106 }
107 if cdl := out.(*testCallDepthLogger); cdl.depth != 42 {
108 t.Errorf("expected depth=42, got %d", cdl.depth)
109 }
110 })
111 }