aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules/caddyhttp/logging
diff options
context:
space:
mode:
authorFrancis Lavoie <[email protected]>2024-03-05 19:03:59 -0500
committerGitHub <[email protected]>2024-03-05 17:03:59 -0700
commit0d44e3ecbaa0b16894e936068785e7fe32f41b48 (patch)
treed7e8ef2fcd16bae95e89bcaf94d1f359f8c7d451 /modules/caddyhttp/logging
parent2a78c9c5e428549fbb40b57b1bd78cf7746e37e3 (diff)
downloadcaddy-0d44e3ecbaa0b16894e936068785e7fe32f41b48.tar.gz
caddy-0d44e3ecbaa0b16894e936068785e7fe32f41b48.zip
logging: Implement `log_append` handler (#6066)
* logging: Implement `extra_log` handler * Rename to `log_append` * Rename `skip_log` to `log_skip` --------- Co-authored-by: Matt Holt <[email protected]>
Diffstat (limited to 'modules/caddyhttp/logging')
-rw-r--r--modules/caddyhttp/logging/caddyfile.go53
-rw-r--r--modules/caddyhttp/logging/logadd.go94
2 files changed, 147 insertions, 0 deletions
diff --git a/modules/caddyhttp/logging/caddyfile.go b/modules/caddyhttp/logging/caddyfile.go
new file mode 100644
index 000000000..010b48919
--- /dev/null
+++ b/modules/caddyhttp/logging/caddyfile.go
@@ -0,0 +1,53 @@
+// Copyright 2015 Matthew Holt and The Caddy Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package logging
+
+import (
+ "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
+ "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
+ "github.com/caddyserver/caddy/v2/modules/caddyhttp"
+)
+
+func init() {
+ httpcaddyfile.RegisterHandlerDirective("log_append", parseCaddyfile)
+}
+
+// parseCaddyfile sets up the log_append handler from Caddyfile tokens. Syntax:
+//
+// log_append [<matcher>] <key> <value>
+func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
+ handler := new(LogAppend)
+ err := handler.UnmarshalCaddyfile(h.Dispenser)
+ return handler, err
+}
+
+// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
+func (h *LogAppend) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
+ d.Next() // consume directive name
+ if !d.NextArg() {
+ return d.ArgErr()
+ }
+ h.Key = d.Val()
+ if !d.NextArg() {
+ return d.ArgErr()
+ }
+ h.Value = d.Val()
+ return nil
+}
+
+// Interface guards
+var (
+ _ caddyfile.Unmarshaler = (*LogAppend)(nil)
+)
diff --git a/modules/caddyhttp/logging/logadd.go b/modules/caddyhttp/logging/logadd.go
new file mode 100644
index 000000000..3b554367f
--- /dev/null
+++ b/modules/caddyhttp/logging/logadd.go
@@ -0,0 +1,94 @@
+// Copyright 2015 Matthew Holt and The Caddy Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package logging
+
+import (
+ "net/http"
+ "strings"
+
+ "go.uber.org/zap"
+
+ "github.com/caddyserver/caddy/v2"
+ "github.com/caddyserver/caddy/v2/modules/caddyhttp"
+)
+
+func init() {
+ caddy.RegisterModule(LogAppend{})
+}
+
+// LogAppend implements a middleware that takes a key and value, where
+// the key is the name of a log field and the value is a placeholder,
+// or variable key, or constant value to use for that field.
+type LogAppend struct {
+ // Key is the name of the log field.
+ Key string `json:"key,omitempty"`
+
+ // Value is the value to use for the log field.
+ // If it is a placeholder (with surrounding `{}`),
+ // it will be evaluated when the log is written.
+ // If the value is a key that exists in the `vars`
+ // 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"`
+}
+
+// CaddyModule returns the Caddy module information.
+func (LogAppend) CaddyModule() caddy.ModuleInfo {
+ return caddy.ModuleInfo{
+ ID: "http.handlers.log_append",
+ New: func() caddy.Module { return new(LogAppend) },
+ }
+}
+
+func (h LogAppend) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
+ // Run the next handler in the chain first.
+ // 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
+ ctx := r.Context()
+
+ vars := ctx.Value(caddyhttp.VarsCtxKey).(map[string]any)
+ repl := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
+ extra := ctx.Value(caddyhttp.ExtraLogFieldsCtxKey).(*caddyhttp.ExtraLogFields)
+
+ var varValue any
+ if strings.HasPrefix(h.Value, "{") &&
+ strings.HasSuffix(h.Value, "}") &&
+ strings.Count(h.Value, "{") == 1 {
+ // the value looks like a placeholder, so get its value
+ varValue, _ = repl.Get(strings.Trim(h.Value, "{}"))
+ } else if val, ok := vars[h.Value]; ok {
+ // the value is a key in the vars map
+ varValue = val
+ } else {
+ // the value is a constant string
+ varValue = h.Value
+ }
+
+ // Add the field to the extra log fields.
+ // 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
+var (
+ _ caddyhttp.MiddlewareHandler = (*LogAppend)(nil)
+)