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,29 @@ func (e *ExtraLogFields) Set(field zap.Field) {
243257 e .fields = append (e .fields , field )
244258}
245259
260+ func (e * ExtraLogFields ) getSloggerHandler (handler * extraFieldsSlogHandler ) (h slog.Handler ) {
261+ if existing , ok := e .handlers .Load (handler ); ok {
262+ return existing .(slog.Handler )
263+ }
264+
265+ if handler .moduleID == "" {
266+ h = zapslog .NewHandler (handler .core .With (e .fields ))
267+ } else {
268+ h = zapslog .NewHandler (handler .core .With (e .fields ), zapslog .WithName (handler .moduleID ))
269+ }
270+
271+ if handler .group != "" {
272+ h = h .WithGroup (handler .group )
273+ }
274+ if handler .attrs != nil {
275+ h = h .WithAttrs (handler .attrs )
276+ }
277+
278+ e .handlers .Store (handler , h )
279+
280+ return h
281+ }
282+
246283const (
247284 // Variable name used to indicate that this request
248285 // should be omitted from the access logs
@@ -254,3 +291,43 @@ const (
254291 // Variable name used to indicate the logger to be used
255292 AccessLoggerNameVarKey string = "access_logger_names"
256293)
294+
295+ type extraFieldsSlogHandler struct {
296+ defaultHandler slog.Handler
297+ core zapcore.Core
298+ moduleID string
299+ group string
300+ attrs []slog.Attr
301+ }
302+
303+ func (e * extraFieldsSlogHandler ) Enabled (ctx context.Context , level slog.Level ) bool {
304+ return e .defaultHandler .Enabled (ctx , level )
305+ }
306+
307+ func (e * extraFieldsSlogHandler ) Handle (ctx context.Context , record slog.Record ) error {
308+ if elf , ok := ctx .Value (ExtraLogFieldsCtxKey ).(* ExtraLogFields ); ok {
309+ return elf .getSloggerHandler (e ).Handle (ctx , record )
310+ }
311+
312+ return e .defaultHandler .Handle (ctx , record )
313+ }
314+
315+ func (e * extraFieldsSlogHandler ) WithAttrs (attrs []slog.Attr ) slog.Handler {
316+ return & extraFieldsSlogHandler {
317+ e .defaultHandler .WithAttrs (attrs ),
318+ e .core ,
319+ e .moduleID ,
320+ e .group ,
321+ append (e .attrs , attrs ... ),
322+ }
323+ }
324+
325+ func (e * extraFieldsSlogHandler ) WithGroup (name string ) slog.Handler {
326+ return & extraFieldsSlogHandler {
327+ e .defaultHandler .WithGroup (name ),
328+ e .core ,
329+ e .moduleID ,
330+ name ,
331+ e .attrs ,
332+ }
333+ }
0 commit comments