@marcel91200 / caddy Mirror · read-only / commits / 0d44e3ec
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 12, 15:45 UTC

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 <mholt@users.noreply.github.com>

Francis Lavoie committed Mar 5, 2024 at 19:03 UTC 0d44e3ecbaa0b16894e936068785e7fe32f41b48
9 files changed +239 -12
caddyconfig/httpcaddyfile/builtins.go
+12 -5
@@ -49,7 +49,8 @@ func init() {
49 RegisterDirective("handle_errors", parseHandleErrors)
50 RegisterHandlerDirective("invoke", parseInvoke)
51 RegisterDirective("log", parseLog)
52 - RegisterHandlerDirective("skip_log", parseSkipLog)
52 + RegisterHandlerDirective("skip_log", parseLogSkip)
53 + RegisterHandlerDirective("log_skip", parseLogSkip)
54 }
55
56 // parseBind parses the bind directive. Syntax:
@@ -1038,13 +1039,19 @@ func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue
1039 return configValues, nil
1040 }
1041
1041 -// parseSkipLog parses the skip_log directive. Syntax:
1042 +// parseLogSkip parses the log_skip directive. Syntax:
1043 //
1043 -// skip_log [<matcher>]
1044 -func parseSkipLog(h Helper) (caddyhttp.MiddlewareHandler, error) {
1044 +// log_skip [<matcher>]
1045 +func parseLogSkip(h Helper) (caddyhttp.MiddlewareHandler, error) {
1046 h.Next() // consume directive name
1047 +
1048 + // "skip_log" is deprecated, replaced by "log_skip"
1049 + if h.Val() == "skip_log" {
1050 + caddy.Log().Named("config.adapter.caddyfile").Warn("the 'skip_log' directive is deprecated, please use 'log_skip' instead!")
1051 + }
1052 +
1053 if h.NextArg() {
1054 return nil, h.ArgErr()
1055 }
1049 - return caddyhttp.VarsMiddleware{"skip_log": true}, nil
1056 + return caddyhttp.VarsMiddleware{"log_skip": true}, nil
1057 }
caddyconfig/httpcaddyfile/directives.go
+2 -1
@@ -43,7 +43,8 @@ var directiveOrder = []string{
43 "vars",
44 "fs",
45 "root",
46 - "skip_log",
46 + "log_append",
47 + "log_skip",
48
49 "header",
50 "copy_response_headers", // only in reverse_proxy's handle_response
caddytest/integration/caddyfile_adapt/log_add.caddyfiletest new
+71
@@ -0,0 +1,71 @@
1 +:80 {
2 + log
3 +
4 + vars foo foo
5 +
6 + log_append const bar
7 + log_append vars foo
8 + log_append placeholder {path}
9 +
10 + log_append /only-for-this-path secret value
11 +}
12 +----------
13 +{
14 + "apps": {
15 + "http": {
16 + "servers": {
17 + "srv0": {
18 + "listen": [
19 + ":80"
20 + ],
21 + "routes": [
22 + {
23 + "handle": [
24 + {
25 + "foo": "foo",
26 + "handler": "vars"
27 + }
28 + ]
29 + },
30 + {
31 + "match": [
32 + {
33 + "path": [
34 + "/only-for-this-path"
35 + ]
36 + }
37 + ],
38 + "handle": [
39 + {
40 + "handler": "log_append",
41 + "key": "secret",
42 + "value": "value"
43 + }
44 + ]
45 + },
46 + {
47 + "handle": [
48 + {
49 + "handler": "log_append",
50 + "key": "const",
51 + "value": "bar"
52 + },
53 + {
54 + "handler": "log_append",
55 + "key": "vars",
56 + "value": "foo"
57 + },
58 + {
59 + "handler": "log_append",
60 + "key": "placeholder",
61 + "value": "{http.request.uri.path}"
62 + }
63 + ]
64 + }
65 + ],
66 + "logs": {}
67 + }
68 + }
69 + }
70 + }
71 +}
caddytest/integration/caddyfile_adapt/log_except_catchall_blocks.caddyfiletest
+4 -4
@@ -1,7 +1,7 @@
1 http://localhost:2020 {
2 log
3 - skip_log /first-hidden*
4 - skip_log /second-hidden*
3 + log_skip /first-hidden*
4 + log_skip /second-hidden*
5 respond 200
6 }
7
@@ -34,7 +34,7 @@ http://localhost:2020 {
34 "handle": [
35 {
36 "handler": "vars",
37 - "skip_log": true
37 + "log_skip": true
38 }
39 ],
40 "match": [
@@ -49,7 +49,7 @@ http://localhost:2020 {
49 "handle": [
50 {
51 "handler": "vars",
52 - "skip_log": true
52 + "log_skip": true
53 }
54 ],
55 "match": [
modules/caddyhttp/logging.go
+1 -1
@@ -166,7 +166,7 @@ func (e *ExtraLogFields) Set(field zap.Field) {
166 const (
167 // Variable name used to indicate that this request
168 // should be omitted from the access logs
169 - SkipLogVar string = "skip_log"
169 + LogSkipVar string = "log_skip"
170
171 // For adding additional fields to the access logs
172 ExtraLogFieldsCtxKey caddy.CtxKey = "extra_log_fields"
modules/caddyhttp/logging/caddyfile.go new
+53
@@ -0,0 +1,53 @@
1 +// Copyright 2015 Matthew Holt and The Caddy Authors
2 +//
3 +// Licensed under the Apache License, Version 2.0 (the "License");
4 +// you may not use this file except in compliance with the License.
5 +// You may obtain a copy of the License at
6 +//
7 +// http://www.apache.org/licenses/LICENSE-2.0
8 +//
9 +// Unless required by applicable law or agreed to in writing, software
10 +// distributed under the License is distributed on an "AS IS" BASIS,
11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 +// See the License for the specific language governing permissions and
13 +// limitations under the License.
14 +
15 +package logging
16 +
17 +import (
18 + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
19 + "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
20 + "github.com/caddyserver/caddy/v2/modules/caddyhttp"
21 +)
22 +
23 +func init() {
24 + httpcaddyfile.RegisterHandlerDirective("log_append", parseCaddyfile)
25 +}
26 +
27 +// parseCaddyfile sets up the log_append handler from Caddyfile tokens. Syntax:
28 +//
29 +// log_append [<matcher>] <key> <value>
30 +func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
31 + handler := new(LogAppend)
32 + err := handler.UnmarshalCaddyfile(h.Dispenser)
33 + return handler, err
34 +}
35 +
36 +// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
37 +func (h *LogAppend) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
38 + d.Next() // consume directive name
39 + if !d.NextArg() {
40 + return d.ArgErr()
41 + }
42 + h.Key = d.Val()
43 + if !d.NextArg() {
44 + return d.ArgErr()
45 + }
46 + h.Value = d.Val()
47 + return nil
48 +}
49 +
50 +// Interface guards
51 +var (
52 + _ caddyfile.Unmarshaler = (*LogAppend)(nil)
53 +)
modules/caddyhttp/logging/logadd.go new
+94
@@ -0,0 +1,94 @@
1 +// Copyright 2015 Matthew Holt and The Caddy Authors
2 +//
3 +// Licensed under the Apache License, Version 2.0 (the "License");
4 +// you may not use this file except in compliance with the License.
5 +// You may obtain a copy of the License at
6 +//
7 +// http://www.apache.org/licenses/LICENSE-2.0
8 +//
9 +// Unless required by applicable law or agreed to in writing, software
10 +// distributed under the License is distributed on an "AS IS" BASIS,
11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 +// See the License for the specific language governing permissions and
13 +// limitations under the License.
14 +
15 +package logging
16 +
17 +import (
18 + "net/http"
19 + "strings"
20 +
21 + "go.uber.org/zap"
22 +
23 + "github.com/caddyserver/caddy/v2"
24 + "github.com/caddyserver/caddy/v2/modules/caddyhttp"
25 +)
26 +
27 +func init() {
28 + caddy.RegisterModule(LogAppend{})
29 +}
30 +
31 +// LogAppend implements a middleware that takes a key and value, where
32 +// the key is the name of a log field and the value is a placeholder,
33 +// or variable key, or constant value to use for that field.
34 +type LogAppend struct {
35 + // Key is the name of the log field.
36 + Key string `json:"key,omitempty"`
37 +
38 + // Value is the value to use for the log field.
39 + // If it is a placeholder (with surrounding `{}`),
40 + // it will be evaluated when the log is written.
41 + // If the value is a key that exists in the `vars`
42 + // map, the value of that key will be used. Otherwise
43 + // the value will be used as-is as a constant string.
44 + Value string `json:"value,omitempty"`
45 +}
46 +
47 +// CaddyModule returns the Caddy module information.
48 +func (LogAppend) CaddyModule() caddy.ModuleInfo {
49 + return caddy.ModuleInfo{
50 + ID: "http.handlers.log_append",
51 + New: func() caddy.Module { return new(LogAppend) },
52 + }
53 +}
54 +
55 +func (h LogAppend) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
56 + // Run the next handler in the chain first.
57 + // If an error occurs, we still want to add
58 + // any extra log fields that we can, so we
59 + // hold onto the error and return it later.
60 + handlerErr := next.ServeHTTP(w, r)
61 +
62 + // On the way back up the chain, add the extra log field
63 + ctx := r.Context()
64 +
65 + vars := ctx.Value(caddyhttp.VarsCtxKey).(map[string]any)
66 + repl := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
67 + extra := ctx.Value(caddyhttp.ExtraLogFieldsCtxKey).(*caddyhttp.ExtraLogFields)
68 +
69 + var varValue any
70 + if strings.HasPrefix(h.Value, "{") &&
71 + strings.HasSuffix(h.Value, "}") &&
72 + strings.Count(h.Value, "{") == 1 {
73 + // the value looks like a placeholder, so get its value
74 + varValue, _ = repl.Get(strings.Trim(h.Value, "{}"))
75 + } else if val, ok := vars[h.Value]; ok {
76 + // the value is a key in the vars map
77 + varValue = val
78 + } else {
79 + // the value is a constant string
80 + varValue = h.Value
81 + }
82 +
83 + // Add the field to the extra log fields.
84 + // We use zap.Any because it will reflect
85 + // to the correct type for us.
86 + extra.Add(zap.Any(h.Key, varValue))
87 +
88 + return handlerErr
89 +}
90 +
91 +// Interface guards
92 +var (
93 + _ caddyhttp.MiddlewareHandler = (*LogAppend)(nil)
94 +)
modules/caddyhttp/server.go
+1 -1
@@ -715,7 +715,7 @@ func (s *Server) logRequest(
715 repl *caddy.Replacer, bodyReader *lengthReader, shouldLogCredentials bool,
716 ) {
717 // this request may be flagged as omitted from the logs
718 - if skipLog, ok := GetVar(r.Context(), SkipLogVar).(bool); ok && skipLog {
718 + if skip, ok := GetVar(r.Context(), LogSkipVar).(bool); ok && skip {
719 return
720 }
721
modules/caddyhttp/standard/imports.go
+1
@@ -10,6 +10,7 @@ import (
10 _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/encode/zstd"
11 _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/fileserver"
12 _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/headers"
13 + _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/logging"
14 _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/map"
15 _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/proxyprotocol"
16 _ "github.com/caddyserver/caddy/v2/modules/caddyhttp/push"