1515package caddyhttp
1616
1717import (
18+ "context"
1819 "encoding/json"
1920 "errors"
21+ "log/slog"
2022 "net"
2123 "net/http"
2224 "strings"
25+ "sync"
2326
2427 "go.uber.org/zap"
28+ "go.uber.org/zap/exp/zapslog"
2529 "go.uber.org/zap/zapcore"
2630
2731 "github.com/caddyserver/caddy/v2"
2832)
2933
34+ func init () {
35+ caddy .RegisterSlogHandlerFactory (func (handler slog.Handler , core zapcore.Core , moduleID string ) slog.Handler {
36+ return & extraFieldsSlogHandler {defaultHandler : handler , core : core , moduleID : moduleID }
37+ })
38+ }
39+
3040// ServerLogConfig describes a server's logging configuration. If
3141// enabled without customization, all requests to this server are
3242// logged to the default logger; logger destinations may be
@@ -223,17 +233,21 @@ func errLogValues(err error) (status int, msg string, fields func() []zapcore.Fi
223233
224234// ExtraLogFields is a list of extra fields to log with every request.
225235type ExtraLogFields struct {
226- fields []zapcore.Field
236+ fields []zapcore.Field
237+ handlers sync.Map
227238}
228239
229240// Add adds a field to the list of extra fields to log.
230241func (e * ExtraLogFields ) Add (field zap.Field ) {
242+ e .handlers .Clear ()
231243 e .fields = append (e .fields , field )
232244}
233245
234246// Set sets a field in the list of extra fields to log.
235247// If the field already exists, it is replaced.
236248func (e * ExtraLogFields ) Set (field zap.Field ) {
249+ e .handlers .Clear ()
250+
237251 for i := range e .fields {
238252 if e .fields [i ].Key == field .Key {
239253 e .fields [i ] = field
@@ -243,6 +257,30 @@ func (e *ExtraLogFields) Set(field zap.Field) {
243257 e .fields = append (e .fields , field )
244258}
245259
260+ // INTERNAL
261+ func (e * ExtraLogFields ) getSloggerHandler (handler * extraFieldsSlogHandler ) (h slog.Handler ) {
262+ if existing , ok := e .handlers .Load (handler ); ok {
263+ return existing .(slog.Handler )
264+ }
265+
266+ if handler .moduleID == "" {
267+ h = zapslog .NewHandler (handler .core .With (e .fields ))
268+ } else {
269+ h = zapslog .NewHandler (handler .core .With (e .fields ), zapslog .WithName (handler .moduleID ))
270+ }
271+
272+ if handler .group != "" {
273+ h = h .WithGroup (handler .group )
274+ }
275+ if handler .attrs != nil {
276+ h = h .WithAttrs (handler .attrs )
277+ }
278+
279+ e .handlers .Store (handler , h )
280+
281+ return h
282+ }
283+
246284const (
247285 // Variable name used to indicate that this request
248286 // should be omitted from the access logs
@@ -254,3 +292,43 @@ const (
254292 // Variable name used to indicate the logger to be used
255293 AccessLoggerNameVarKey string = "access_logger_names"
256294)
295+
296+ type extraFieldsSlogHandler struct {
297+ defaultHandler slog.Handler
298+ core zapcore.Core
299+ moduleID string
300+ group string
301+ attrs []slog.Attr
302+ }
303+
304+ func (e * extraFieldsSlogHandler ) Enabled (ctx context.Context , level slog.Level ) bool {
305+ return e .defaultHandler .Enabled (ctx , level )
306+ }
307+
308+ func (e * extraFieldsSlogHandler ) Handle (ctx context.Context , record slog.Record ) error {
309+ if elf , ok := ctx .Value (ExtraLogFieldsCtxKey ).(* ExtraLogFields ); ok {
310+ return elf .getSloggerHandler (e ).Handle (ctx , record )
311+ }
312+
313+ return e .defaultHandler .Handle (ctx , record )
314+ }
315+
316+ func (e * extraFieldsSlogHandler ) WithAttrs (attrs []slog.Attr ) slog.Handler {
317+ return & extraFieldsSlogHandler {
318+ e .defaultHandler .WithAttrs (attrs ),
319+ e .core ,
320+ e .moduleID ,
321+ e .group ,
322+ append (e .attrs , attrs ... ),
323+ }
324+ }
325+
326+ func (e * extraFieldsSlogHandler ) WithGroup (name string ) slog.Handler {
327+ return & extraFieldsSlogHandler {
328+ e .defaultHandler .WithGroup (name ),
329+ e .core ,
330+ e .moduleID ,
331+ name ,
332+ e .attrs ,
333+ }
334+ }
0 commit comments