package logging import ( "context" ) // contextKey is the key type for context values to avoid collisions. type contextKey struct{} // loggerKey is the key used to store the logger in context. var loggerKey = contextKey{} // defaultLogger is used when no logger is found in context. // It's initialized lazily to avoid import cycles. var defaultLogger *Logger // SetDefault sets the default logger used when FromContext finds no logger. // Call this during application initialization. func SetDefault(l *Logger) { defaultLogger = l } // Default returns the default logger. // Returns a nop logger if SetDefault was never called. func Default() *Logger { if defaultLogger == nil { return Nop() } return defaultLogger } // WithContext returns a new context with the logger attached. func WithContext(ctx context.Context, l *Logger) context.Context { return context.WithValue(ctx, loggerKey, l) } // FromContext extracts the logger from context. // Returns the default logger if no logger is found. func FromContext(ctx context.Context) *Logger { if ctx == nil { return Default() } if l, ok := ctx.Value(loggerKey).(*Logger); ok { return l } return Default() } // WithFields returns a new context with additional fields added to the logger. // This is a convenience function for adding fields in middleware. func WithFields(ctx context.Context, args ...any) context.Context { l := FromContext(ctx).With(args...) return WithContext(ctx, l) } // WithRequestContext returns a new context with request-scoped fields. // This is typically called by middleware to enrich the logger. func WithRequestContext(ctx context.Context, requestID, userID, apiKeyID string) context.Context { l := FromContext(ctx) if requestID != "" { l = l.WithRequestID(requestID) } if userID != "" { l = l.WithUserID(userID) } if apiKeyID != "" { l = l.With(FieldAPIKeyID, apiKeyID) } return WithContext(ctx, l) }