diff --git a/caddyconfig/httpcaddyfile/shorthands.go b/caddyconfig/httpcaddyfile/shorthands.go index 102bc36d..75795ae6 100644 --- a/caddyconfig/httpcaddyfile/shorthands.go +++ b/caddyconfig/httpcaddyfile/shorthands.go @@ -64,6 +64,7 @@ func placeholderShorthands() []string { "{remote_port}", "{http.request.remote.port}", "{scheme}", "{http.request.scheme}", "{uri}", "{http.request.uri}", + "{uuid}", "{http.request.uuid}", "{tls_cipher}", "{http.request.tls.cipher_suite}", "{tls_version}", "{http.request.tls.version}", "{tls_client_fingerprint}", "{http.request.tls.client.fingerprint}", diff --git a/modules/caddyhttp/logging.go b/modules/caddyhttp/logging.go index 8ecc49a6..728befd2 100644 --- a/modules/caddyhttp/logging.go +++ b/modules/caddyhttp/logging.go @@ -151,6 +151,18 @@ func (e *ExtraLogFields) Add(field zap.Field) { e.fields = append(e.fields, field) } +// Set sets a field in the list of extra fields to log. +// If the field already exists, it is replaced. +func (e *ExtraLogFields) Set(field zap.Field) { + for i := range e.fields { + if e.fields[i].Key == field.Key { + e.fields[i] = field + return + } + } + e.fields = append(e.fields, field) +} + const ( // Variable name used to indicate that this request // should be omitted from the access logs diff --git a/modules/caddyhttp/replacer.go b/modules/caddyhttp/replacer.go index f6b042ce..ef5084e3 100644 --- a/modules/caddyhttp/replacer.go +++ b/modules/caddyhttp/replacer.go @@ -40,6 +40,7 @@ import ( "time" "github.com/google/uuid" + "go.uber.org/zap" "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/modules/caddytls" @@ -157,9 +158,17 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo case "http.request.duration_ms": start := GetVar(req.Context(), "start_time").(time.Time) return time.Since(start).Seconds() * 1e3, true // multiply seconds to preserve decimal (see #4666) + case "http.request.uuid": + // fetch the UUID for this request id := GetVar(req.Context(), "uuid").(*requestID) + + // set it to this request's access log + extra := req.Context().Value(ExtraLogFieldsCtxKey).(*ExtraLogFields) + extra.Set(zap.String("uuid", id.String())) + return id.String(), true + case "http.request.body": if req.Body == nil { return "", true