@@ -22,10 +22,19 @@ type logConfig struct {
2222 err error
2323}
2424
25+ type SinkOption func (* sinkConfig )
26+
2527// New creates a new log object with the provided configurations. If no sinks
2628// are provided, a no-op sink will be used. Returns the logger and a cleanup
2729// function that should be executed before the program exits.
2830func New (service string , configs ... logConfig ) (logr.Logger , func () error ) {
31+ return NewWithCaller (service , false , configs ... )
32+ }
33+
34+ // NewWithCaller creates a new logger named after the specified service with the provided sink configurations. If
35+ // addCaller is true, call site information will be attached to each emitted log message. (This behavior can be disabled
36+ // on a per-sink basis using WithSuppressCaller.)
37+ func NewWithCaller (service string , addCaller bool , configs ... logConfig ) (logr.Logger , func () error ) {
2938 var cores []zapcore.Core
3039 var cleanupFuncs []func () error
3140
@@ -40,7 +49,7 @@ func New(service string, configs ...logConfig) (logr.Logger, func() error) {
4049 }
4150 }
4251 // create logger
43- zapLogger := zap .New (zapcore .NewTee (cores ... ))
52+ zapLogger := zap .New (zapcore .NewTee (cores ... ), zap . WithCaller ( addCaller ) )
4453 cleanupFuncs = append (cleanupFuncs , zapLogger .Sync )
4554 logger := zapr .NewLogger (zapLogger ).WithName (service )
4655
@@ -85,14 +94,15 @@ func WithSentry(opts sentry.ClientOptions, tags map[string]string) logConfig {
8594}
8695
8796type sinkConfig struct {
88- encoder zapcore.Encoder
89- sink zapcore.WriteSyncer
90- level levelSetter
91- redactor * dynamicRedactor
97+ encoder zapcore.Encoder
98+ sink zapcore.WriteSyncer
99+ level levelSetter
100+ redactor * dynamicRedactor
101+ suppressCaller bool
92102}
93103
94104// WithJSONSink adds a JSON encoded output to the logger.
95- func WithJSONSink (sink io.Writer , opts ... func ( * sinkConfig ) ) logConfig {
105+ func WithJSONSink (sink io.Writer , opts ... SinkOption ) logConfig {
96106 return newCoreConfig (
97107 zapcore .NewJSONEncoder (defaultEncoderConfig ()),
98108 zapcore .Lock (zapcore .AddSync (sink )),
@@ -102,7 +112,7 @@ func WithJSONSink(sink io.Writer, opts ...func(*sinkConfig)) logConfig {
102112}
103113
104114// WithConsoleSink adds a console-style output to the logger.
105- func WithConsoleSink (sink io.Writer , opts ... func ( * sinkConfig ) ) logConfig {
115+ func WithConsoleSink (sink io.Writer , opts ... SinkOption ) logConfig {
106116 return newCoreConfig (
107117 zapcore .NewConsoleEncoder (defaultEncoderConfig ()),
108118 zapcore .Lock (zapcore .AddSync (sink )),
@@ -162,10 +172,21 @@ func AddSink(l logr.Logger, sink logConfig, keysAndValues ...any) (logr.Logger,
162172 if err != nil {
163173 return l , nil , errors .New ("unsupported logr implementation" )
164174 }
165- zapLogger = zapLogger .WithOptions (zap .WrapCore (func (core zapcore.Core ) zapcore.Core {
166- return zapcore .NewTee (core , newSinkCore )
167- }))
168- return zapr .NewLogger (zapLogger ), firstErrorFunc (zapLogger .Sync , sink .cleanup ), nil
175+
176+ newLoggerOptions := []zap.Option {
177+ // Tee the new core together with the original core
178+ zap .WrapCore (func (core zapcore.Core ) zapcore.Core { return zapcore .NewTee (core , newSinkCore ) }),
179+
180+ // CMR: zapr.NewLogger, for whatever reason, assumes that the passed-in logger doesn't have its caller frame
181+ // adjustment already set up, so it adds a frame skip of 2. However, that assumption doesn't hold here because
182+ // we're adding a core to an existing logger rather than creating a new one. I can't figure out a way to disable
183+ // this automatic frame adjustment, so we compensate for it with the hamfisted kludge of a compensating offset.
184+ zap .AddCallerSkip (- 2 ),
185+ }
186+
187+ zapLogger = zapLogger .WithOptions (newLoggerOptions ... )
188+ newLogger := zapr .NewLogger (zapLogger )
189+ return newLogger , firstErrorFunc (zapLogger .Sync , sink .cleanup ), nil
169190}
170191
171192// getZapLogger is a helper function that gets the underlying zap logger from a
@@ -179,7 +200,7 @@ func getZapLogger(l logr.Logger) (*zap.Logger, error) {
179200
180201// WithLevel sets the sink's level to a static level. This option prevents
181202// changing the log level for this sink later on.
182- func WithLevel (level int8 ) func ( * sinkConfig ) {
203+ func WithLevel (level int8 ) SinkOption {
183204 return WithLeveler (
184205 // Zap's levels get more verbose as the number gets smaller, as explained
185206 // by zapr here: https://github.com/go-logr/zapr#increasing-verbosity
@@ -189,19 +210,27 @@ func WithLevel(level int8) func(*sinkConfig) {
189210}
190211
191212// WithLeveler sets the sink's level enabler to leveler.
192- func WithLeveler (leveler levelSetter ) func ( * sinkConfig ) {
213+ func WithLeveler (leveler levelSetter ) SinkOption {
193214 return func (conf * sinkConfig ) {
194215 conf .level = leveler
195216 }
196217}
197218
198219// WithGlobalRedaction adds values to be redacted from logs.
199- func WithGlobalRedaction () func ( * sinkConfig ) {
220+ func WithGlobalRedaction () SinkOption {
200221 return func (conf * sinkConfig ) {
201222 conf .redactor = globalRedactor
202223 }
203224}
204225
226+ // WithSuppressCaller prevents the sink being configured from logging any caller information, irrespective of any other
227+ // logger settings.
228+ func WithSuppressCaller () SinkOption {
229+ return func (conf * sinkConfig ) {
230+ conf .suppressCaller = true
231+ }
232+ }
233+
205234// ToLogger converts the logr.Logger into a legacy *log.Logger.
206235func ToLogger (l logr.Logger ) * log.Logger {
207236 return slog .NewLogLogger (logr .ToSlogHandler (l ), slog .LevelInfo )
@@ -235,7 +264,7 @@ func newCoreConfig(
235264 defaultEncoder zapcore.Encoder ,
236265 defaultSink zapcore.WriteSyncer ,
237266 defaultLevel levelSetter ,
238- opts ... func ( * sinkConfig ) ,
267+ opts ... SinkOption ,
239268) logConfig {
240269 conf := sinkConfig {
241270 encoder : defaultEncoder ,
@@ -251,9 +280,13 @@ func newCoreConfig(
251280 conf .level ,
252281 )
253282
254- if conf .redactor = = nil {
255- return logConfig { core : core }
283+ if conf .redactor ! = nil {
284+ core = NewRedactionCore ( core , conf . redactor )
256285 }
257286
258- return logConfig {core : NewRedactionCore (core , conf .redactor )}
287+ if conf .suppressCaller {
288+ core = & suppressCallerCore {Core : core }
289+ }
290+
291+ return logConfig {core : core }
259292}
0 commit comments