From c027ce6ad436f5c3ba4ce444765c176766c8a70b Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Wed, 26 Nov 2025 05:42:14 -0500 Subject: [PATCH] logging: `log_append` early option --- modules/caddyhttp/logging/caddyfile.go | 8 +++++++- modules/caddyhttp/logging/logadd.go | 26 ++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/modules/caddyhttp/logging/caddyfile.go b/modules/caddyhttp/logging/caddyfile.go index 010b48919..38d79014b 100644 --- a/modules/caddyhttp/logging/caddyfile.go +++ b/modules/caddyhttp/logging/caddyfile.go @@ -15,6 +15,8 @@ package logging import ( + "strings" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" "github.com/caddyserver/caddy/v2/modules/caddyhttp" @@ -26,7 +28,7 @@ func init() { // parseCaddyfile sets up the log_append handler from Caddyfile tokens. Syntax: // -// log_append [] +// log_append [] [<] func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { handler := new(LogAppend) err := handler.UnmarshalCaddyfile(h.Dispenser) @@ -43,6 +45,10 @@ func (h *LogAppend) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { if !d.NextArg() { return d.ArgErr() } + if strings.HasPrefix(h.Key, "<") && len(h.Key) > 1 { + h.Early = true + h.Key = h.Key[1:] + } h.Value = d.Val() return nil } diff --git a/modules/caddyhttp/logging/logadd.go b/modules/caddyhttp/logging/logadd.go index 3b554367f..ce9f63d37 100644 --- a/modules/caddyhttp/logging/logadd.go +++ b/modules/caddyhttp/logging/logadd.go @@ -42,6 +42,12 @@ type LogAppend struct { // map, the value of that key will be used. Otherwise // the value will be used as-is as a constant string. Value string `json:"value,omitempty"` + + // Early, if true, adds the log field before calling + // the next handler in the chain. By default, the log + // field is added on the way back up the middleware chain, + // after all subsequent handlers have completed. + Early bool `json:"early,omitempty"` } // CaddyModule returns the Caddy module information. @@ -53,13 +59,27 @@ func (LogAppend) CaddyModule() caddy.ModuleInfo { } func (h LogAppend) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { - // Run the next handler in the chain first. + if h.Early { + // Add the log field before calling the next handler + h.addLogField(r) + } + + // Run the next handler in the chain. // If an error occurs, we still want to add // any extra log fields that we can, so we // hold onto the error and return it later. handlerErr := next.ServeHTTP(w, r) - // On the way back up the chain, add the extra log field + if !h.Early { + // Add the log field after the handler completes + h.addLogField(r) + } + + return handlerErr +} + +// addLogField adds the log field to the request's extra log fields. +func (h LogAppend) addLogField(r *http.Request) { ctx := r.Context() vars := ctx.Value(caddyhttp.VarsCtxKey).(map[string]any) @@ -84,8 +104,6 @@ func (h LogAppend) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyh // We use zap.Any because it will reflect // to the correct type for us. extra.Add(zap.Any(h.Key, varValue)) - - return handlerErr } // Interface guards