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"