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, 08:15 UTC
perf: use zap's Check() to prevent useless allocs (#6560)
* perf: use zap's Check() to prevent useless allocs * fix * fix * fix * fix * restore previous replacer behavior * fix linter
Kévin Dunglas committed
Sep 13, 2024 at 19:16 UTC
f4bf4e0097853438eb69c573bbaa0581e9b9c02d
30 files changed
+599
-282
modules/caddyhttp/caddyauth/caddyauth.go
+4
-3
@@ -19,6 +19,7 @@ import (
19
"net/http"
20
21
"go.uber.org/zap"
22
+ "go.uber.org/zap/zapcore"
23
24
"github.com/caddyserver/caddy/v2"
25
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
@@ -76,9 +77,9 @@ func (a Authentication) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
77
for provName, prov := range a.Providers {
78
user, authed, err = prov.Authenticate(w, r)
79
if err != nil {
79
- a.logger.Error("auth provider returned error",
80
- zap.String("provider", provName),
81
- zap.Error(err))
80
+ if c := a.logger.Check(zapcore.ErrorLevel, "auth provider returned error"); c != nil {
81
+ c.Write(zap.String("provider", provName), zap.Error(err))
82
+ }
83
continue
84
}
85
if authed {
modules/caddyhttp/fileserver/browse.go
+7
-4
@@ -33,6 +33,7 @@ import (
33
"time"
34
35
"go.uber.org/zap"
36
+ "go.uber.org/zap/zapcore"
37
38
"github.com/caddyserver/caddy/v2"
39
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
@@ -68,9 +69,9 @@ type Browse struct {
69
}
70
71
func (fsrv *FileServer) serveBrowse(fileSystem fs.FS, root, dirPath string, w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
71
- fsrv.logger.Debug("browse enabled; listing directory contents",
72
- zap.String("path", dirPath),
73
- zap.String("root", root))
72
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "browse enabled; listing directory contents"); c != nil {
73
+ c.Write(zap.String("path", dirPath), zap.String("root", root))
74
+ }
75
76
// Navigation on the client-side gets messed up if the
77
// URL doesn't end in a trailing slash because hrefs to
@@ -92,7 +93,9 @@ func (fsrv *FileServer) serveBrowse(fileSystem fs.FS, root, dirPath string, w ht
93
origReq := r.Context().Value(caddyhttp.OriginalRequestCtxKey).(http.Request)
94
if r.URL.Path == "" || path.Base(origReq.URL.Path) == path.Base(r.URL.Path) {
95
if !strings.HasSuffix(origReq.URL.Path, "/") {
95
- fsrv.logger.Debug("redirecting to trailing slash to preserve hrefs", zap.String("request_path", r.URL.Path))
96
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "redirecting to trailing slash to preserve hrefs"); c != nil {
97
+ c.Write(zap.String("request_path", r.URL.Path))
98
+ }
99
return redirect(w, r, origReq.URL.Path+"/")
100
}
101
}
modules/caddyhttp/fileserver/browsetplcontext.go
+4
-3
@@ -28,6 +28,7 @@ import (
28
29
"github.com/dustin/go-humanize"
30
"go.uber.org/zap"
31
+ "go.uber.org/zap/zapcore"
32
33
"github.com/caddyserver/caddy/v2"
34
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
@@ -57,9 +58,9 @@ func (fsrv *FileServer) directoryListing(ctx context.Context, fileSystem fs.FS,
58
59
info, err := entry.Info()
60
if err != nil {
60
- fsrv.logger.Error("could not get info about directory entry",
61
- zap.String("name", entry.Name()),
62
- zap.String("root", root))
61
+ if c := fsrv.logger.Check(zapcore.ErrorLevel, "could not get info about directory entry"); c != nil {
62
+ c.Write(zap.String("name", entry.Name()), zap.String("root", root))
63
+ }
64
continue
65
}
66
modules/caddyhttp/fileserver/matcher.go
+11
-3
@@ -33,6 +33,7 @@ import (
33
"github.com/google/cel-go/common/types/ref"
34
"github.com/google/cel-go/parser"
35
"go.uber.org/zap"
36
+ "go.uber.org/zap/zapcore"
37
38
"github.com/caddyserver/caddy/v2"
39
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -326,7 +327,9 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) {
327
328
fileSystem, ok := m.fsmap.Get(fsName)
329
if !ok {
329
- m.logger.Error("use of unregistered filesystem", zap.String("fs", fsName))
330
+ if c := m.logger.Check(zapcore.ErrorLevel, "use of unregistered filesystem"); c != nil {
331
+ c.Write(zap.String("fs", fsName))
332
+ }
333
return false
334
}
335
type matchCandidate struct {
@@ -356,7 +359,10 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) {
359
return val, nil
360
})
361
if err != nil {
359
- m.logger.Error("evaluating placeholders", zap.Error(err))
362
+ if c := m.logger.Check(zapcore.ErrorLevel, "evaluating placeholders"); c != nil {
363
+ c.Write(zap.Error(err))
364
+ }
365
+
366
expandedFile = file // "oh well," I guess?
367
}
368
@@ -379,7 +385,9 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) {
385
} else {
386
globResults, err = fs.Glob(fileSystem, fullPattern)
387
if err != nil {
382
- m.logger.Error("expanding glob", zap.Error(err))
388
+ if c := m.logger.Check(zapcore.ErrorLevel, "expanding glob"); c != nil {
389
+ c.Write(zap.Error(err))
390
+ }
391
}
392
}
393
modules/caddyhttp/fileserver/staticfiles.go
+63
-28
@@ -31,6 +31,7 @@ import (
31
"strings"
32
33
"go.uber.org/zap"
34
+ "go.uber.org/zap/zapcore"
35
36
"github.com/caddyserver/caddy/v2"
37
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
@@ -286,11 +287,14 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
287
// remove any trailing `/` as it breaks fs.ValidPath() in the stdlib
288
filename := strings.TrimSuffix(caddyhttp.SanitizedPathJoin(root, r.URL.Path), "/")
289
289
- fsrv.logger.Debug("sanitized path join",
290
- zap.String("site_root", root),
291
- zap.String("fs", fsName),
292
- zap.String("request_path", r.URL.Path),
293
- zap.String("result", filename))
290
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "sanitized path join"); c != nil {
291
+ c.Write(
292
+ zap.String("site_root", root),
293
+ zap.String("fs", fsName),
294
+ zap.String("request_path", r.URL.Path),
295
+ zap.String("result", filename),
296
+ )
297
+ }
298
299
// get information about the file
300
info, err := fs.Stat(fileSystem, filename)
@@ -313,9 +317,12 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
317
indexPath := caddyhttp.SanitizedPathJoin(filename, indexPage)
318
if fileHidden(indexPath, filesToHide) {
319
// pretend this file doesn't exist
316
- fsrv.logger.Debug("hiding index file",
317
- zap.String("filename", indexPath),
318
- zap.Strings("files_to_hide", filesToHide))
320
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "hiding index file"); c != nil {
321
+ c.Write(
322
+ zap.String("filename", indexPath),
323
+ zap.Strings("files_to_hide", filesToHide),
324
+ )
325
+ }
326
continue
327
}
328
@@ -335,7 +342,9 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
342
info = indexInfo
343
filename = indexPath
344
implicitIndexFile = true
338
- fsrv.logger.Debug("located index file", zap.String("filename", filename))
345
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "located index file"); c != nil {
346
+ c.Write(zap.String("filename", filename))
347
+ }
348
break
349
}
350
}
@@ -343,9 +352,12 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
352
// if still referencing a directory, delegate
353
// to browse or return an error
354
if info.IsDir() {
346
- fsrv.logger.Debug("no index file in directory",
347
- zap.String("path", filename),
348
- zap.Strings("index_filenames", fsrv.IndexNames))
355
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "no index file in directory"); c != nil {
356
+ c.Write(
357
+ zap.String("path", filename),
358
+ zap.Strings("index_filenames", fsrv.IndexNames),
359
+ )
360
+ }
361
if fsrv.Browse != nil && !fileHidden(filename, filesToHide) {
362
return fsrv.serveBrowse(fileSystem, root, filename, w, r, next)
363
}
@@ -355,9 +367,12 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
367
// one last check to ensure the file isn't hidden (we might
368
// have changed the filename from when we last checked)
369
if fileHidden(filename, filesToHide) {
358
- fsrv.logger.Debug("hiding file",
359
- zap.String("filename", filename),
360
- zap.Strings("files_to_hide", filesToHide))
370
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "hiding file"); c != nil {
371
+ c.Write(
372
+ zap.String("filename", filename),
373
+ zap.Strings("files_to_hide", filesToHide),
374
+ )
375
+ }
376
return fsrv.notFound(w, r, next)
377
}
378
@@ -375,15 +390,21 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
390
if path.Base(origReq.URL.Path) == path.Base(r.URL.Path) {
391
if implicitIndexFile && !strings.HasSuffix(origReq.URL.Path, "/") {
392
to := origReq.URL.Path + "/"
378
- fsrv.logger.Debug("redirecting to canonical URI (adding trailing slash for directory)",
379
- zap.String("from_path", origReq.URL.Path),
380
- zap.String("to_path", to))
393
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "redirecting to canonical URI (adding trailing slash for directory"); c != nil {
394
+ c.Write(
395
+ zap.String("from_path", origReq.URL.Path),
396
+ zap.String("to_path", to),
397
+ )
398
+ }
399
return redirect(w, r, to)
400
} else if !implicitIndexFile && strings.HasSuffix(origReq.URL.Path, "/") {
401
to := origReq.URL.Path[:len(origReq.URL.Path)-1]
384
- fsrv.logger.Debug("redirecting to canonical URI (removing trailing slash for file)",
385
- zap.String("from_path", origReq.URL.Path),
386
- zap.String("to_path", to))
402
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "redirecting to canonical URI (removing trailing slash for file"); c != nil {
403
+ c.Write(
404
+ zap.String("from_path", origReq.URL.Path),
405
+ zap.String("to_path", to),
406
+ )
407
+ }
408
return redirect(w, r, to)
409
}
410
}
@@ -411,13 +432,19 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
432
compressedFilename := filename + precompress.Suffix()
433
compressedInfo, err := fs.Stat(fileSystem, compressedFilename)
434
if err != nil || compressedInfo.IsDir() {
414
- fsrv.logger.Debug("precompressed file not accessible", zap.String("filename", compressedFilename), zap.Error(err))
435
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "precompressed file not accessible"); c != nil {
436
+ c.Write(zap.String("filename", compressedFilename), zap.Error(err))
437
+ }
438
continue
439
}
417
- fsrv.logger.Debug("opening compressed sidecar file", zap.String("filename", compressedFilename), zap.Error(err))
440
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "opening compressed sidecar file"); c != nil {
441
+ c.Write(zap.String("filename", compressedFilename), zap.Error(err))
442
+ }
443
file, err = fsrv.openFile(fileSystem, compressedFilename, w)
444
if err != nil {
420
- fsrv.logger.Warn("opening precompressed file failed", zap.String("filename", compressedFilename), zap.Error(err))
445
+ if c := fsrv.logger.Check(zapcore.WarnLevel, "opening precompressed file failed"); c != nil {
446
+ c.Write(zap.String("filename", compressedFilename), zap.Error(err))
447
+ }
448
if caddyErr, ok := err.(caddyhttp.HandlerError); ok && caddyErr.StatusCode == http.StatusServiceUnavailable {
449
return err
450
}
@@ -448,7 +475,9 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
475
476
// no precompressed file found, use the actual file
477
if file == nil {
451
- fsrv.logger.Debug("opening file", zap.String("filename", filename))
478
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "opening file"); c != nil {
479
+ c.Write(zap.String("filename", filename))
480
+ }
481
482
// open the file
483
file, err = fsrv.openFile(fileSystem, filename, w)
@@ -548,10 +577,14 @@ func (fsrv *FileServer) openFile(fileSystem fs.FS, filename string, w http.Respo
577
if err != nil {
578
err = fsrv.mapDirOpenError(fileSystem, err, filename)
579
if errors.Is(err, fs.ErrNotExist) {
551
- fsrv.logger.Debug("file not found", zap.String("filename", filename), zap.Error(err))
580
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "file not found"); c != nil {
581
+ c.Write(zap.String("filename", filename), zap.Error(err))
582
+ }
583
return nil, caddyhttp.Error(http.StatusNotFound, err)
584
} else if errors.Is(err, fs.ErrPermission) {
554
- fsrv.logger.Debug("permission denied", zap.String("filename", filename), zap.Error(err))
585
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "permission denied"); c != nil {
586
+ c.Write(zap.String("filename", filename), zap.Error(err))
587
+ }
588
return nil, caddyhttp.Error(http.StatusForbidden, err)
589
}
590
// maybe the server is under load and ran out of file descriptors?
@@ -559,7 +592,9 @@ func (fsrv *FileServer) openFile(fileSystem fs.FS, filename string, w http.Respo
592
//nolint:gosec
593
backoff := weakrand.Intn(maxBackoff-minBackoff) + minBackoff
594
w.Header().Set("Retry-After", strconv.Itoa(backoff))
562
- fsrv.logger.Debug("retry after backoff", zap.String("filename", filename), zap.Int("backoff", backoff), zap.Error(err))
595
+ if c := fsrv.logger.Check(zapcore.DebugLevel, "retry after backoff"); c != nil {
596
+ c.Write(zap.String("filename", filename), zap.Int("backoff", backoff), zap.Error(err))
597
+ }
598
return nil, caddyhttp.Error(http.StatusServiceUnavailable, err)
599
}
600
return file, nil
modules/caddyhttp/intercept/intercept.go
+4
-1
@@ -23,6 +23,7 @@ import (
23
"sync"
24
25
"go.uber.org/zap"
26
+ "go.uber.org/zap/zapcore"
27
28
"github.com/caddyserver/caddy/v2"
29
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -165,7 +166,9 @@ func (ir Intercept) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy
166
}
167
repl.Set("http.intercept.status_code", rec.Status())
168
168
- ir.logger.Debug("handling response", zap.Int("handler", rec.handlerIndex))
169
+ if c := ir.logger.Check(zapcore.DebugLevel, "handling response"); c != nil {
170
+ c.Write(zap.Int("handler", rec.handlerIndex))
171
+ }
172
173
// pass the request through the response handler routes
174
return rec.handler.Routes.Compile(next).ServeHTTP(w, r)
modules/caddyhttp/ip_matchers.go
+8
-2
@@ -26,6 +26,7 @@ import (
26
"github.com/google/cel-go/cel"
27
"github.com/google/cel-go/common/types/ref"
28
"go.uber.org/zap"
29
+ "go.uber.org/zap/zapcore"
30
31
"github.com/caddyserver/caddy/v2"
32
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -150,12 +151,17 @@ func (m MatchRemoteIP) Match(r *http.Request) bool {
151
address := r.RemoteAddr
152
clientIP, zoneID, err := parseIPZoneFromString(address)
153
if err != nil {
153
- m.logger.Error("getting remote IP", zap.Error(err))
154
+ if c := m.logger.Check(zapcore.ErrorLevel, "getting remote "); c != nil {
155
+ c.Write(zap.Error(err))
156
+ }
157
+
158
return false
159
}
160
matches, zoneFilter := matchIPByCidrZones(clientIP, zoneID, m.cidrs, m.zones)
161
if !matches && !zoneFilter {
158
- m.logger.Debug("zone ID from remote IP did not match", zap.String("zone", zoneID))
162
+ if c := m.logger.Check(zapcore.DebugLevel, "zone ID from remote IP did not match"); c != nil {
163
+ c.Write(zap.String("zone", zoneID))
164
+ }
165
}
166
return matches
167
}
modules/caddyhttp/logging.go
+7
-5
@@ -193,7 +193,7 @@ func (sa *StringArray) UnmarshalJSON(b []byte) error {
193
// to use, the error log message, and any extra fields.
194
// If err is a HandlerError, the returned values will
195
// have richer information.
196
-func errLogValues(err error) (status int, msg string, fields []zapcore.Field) {
196
+func errLogValues(err error) (status int, msg string, fields func() []zapcore.Field) {
197
var handlerErr HandlerError
198
if errors.As(err, &handlerErr) {
199
status = handlerErr.StatusCode
@@ -202,10 +202,12 @@ func errLogValues(err error) (status int, msg string, fields []zapcore.Field) {
202
} else {
203
msg = handlerErr.Err.Error()
204
}
205
- fields = []zapcore.Field{
206
- zap.Int("status", handlerErr.StatusCode),
207
- zap.String("err_id", handlerErr.ID),
208
- zap.String("err_trace", handlerErr.Trace),
205
+ fields = func() []zapcore.Field {
206
+ return []zapcore.Field{
207
+ zap.Int("status", handlerErr.StatusCode),
208
+ zap.String("err_id", handlerErr.ID),
209
+ zap.String("err_trace", handlerErr.Trace),
210
+ }
211
}
212
return
213
}
modules/caddyhttp/push/handler.go
+15
-9
@@ -20,6 +20,7 @@ import (
20
"strings"
21
22
"go.uber.org/zap"
23
+ "go.uber.org/zap/zapcore"
24
25
"github.com/caddyserver/caddy/v2"
26
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
@@ -92,14 +93,17 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhtt
93
94
// push first!
95
for _, resource := range h.Resources {
95
- h.logger.Debug("pushing resource",
96
- zap.String("uri", r.RequestURI),
97
- zap.String("push_method", resource.Method),
98
- zap.String("push_target", resource.Target),
99
- zap.Object("push_headers", caddyhttp.LoggableHTTPHeader{
100
- Header: hdr,
101
- ShouldLogCredentials: shouldLogCredentials,
102
- }))
96
+ if c := h.logger.Check(zapcore.DebugLevel, "pushing resource"); c != nil {
97
+ c.Write(
98
+ zap.String("uri", r.RequestURI),
99
+ zap.String("push_method", resource.Method),
100
+ zap.String("push_target", resource.Target),
101
+ zap.Object("push_headers", caddyhttp.LoggableHTTPHeader{
102
+ Header: hdr,
103
+ ShouldLogCredentials: shouldLogCredentials,
104
+ }),
105
+ )
106
+ }
107
err := pusher.Push(repl.ReplaceAll(resource.Target, "."), &http.PushOptions{
108
Method: resource.Method,
109
Header: hdr,
@@ -209,7 +213,9 @@ func (lp linkPusher) WriteHeader(statusCode int) {
213
if links, ok := lp.ResponseWriter.Header()["Link"]; ok {
214
// only initiate these pushes if it hasn't been done yet
215
if val := caddyhttp.GetVar(lp.request.Context(), pushedLink); val == nil {
212
- lp.handler.logger.Debug("pushing Link resources", zap.Strings("linked", links))
216
+ if c := lp.handler.logger.Check(zapcore.DebugLevel, "pushing Link resources"); c != nil {
217
+ c.Write(zap.Strings("linked", links))
218
+ }
219
caddyhttp.SetVar(lp.request.Context(), pushedLink, true)
220
lp.handler.servePreloadLinks(lp.pusher, lp.header, links)
221
}
modules/caddyhttp/requestbody/requestbody.go
+7
-2
@@ -20,6 +20,7 @@ import (
20
"time"
21
22
"go.uber.org/zap"
23
+ "go.uber.org/zap/zapcore"
24
25
"github.com/caddyserver/caddy/v2"
26
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
@@ -69,12 +70,16 @@ func (rb RequestBody) ServeHTTP(w http.ResponseWriter, r *http.Request, next cad
70
rc := http.NewResponseController(w)
71
if rb.ReadTimeout > 0 {
72
if err := rc.SetReadDeadline(time.Now().Add(rb.ReadTimeout)); err != nil {
72
- rb.logger.Error("could not set read deadline", zap.Error(err))
73
+ if c := rb.logger.Check(zapcore.ErrorLevel, "could not set read deadline"); c != nil {
74
+ c.Write(zap.Error(err))
75
+ }
76
}
77
}
78
if rb.WriteTimeout > 0 {
79
if err := rc.SetWriteDeadline(time.Now().Add(rb.WriteTimeout)); err != nil {
77
- rb.logger.Error("could not set write deadline", zap.Error(err))
80
+ if c := rb.logger.Check(zapcore.ErrorLevel, "could not set write deadline"); c != nil {
81
+ c.Write(zap.Error(err))
82
+ }
83
}
84
}
85
}
modules/caddyhttp/reverseproxy/fastcgi/client.go
+7
-3
@@ -40,6 +40,7 @@ import (
40
"time"
41
42
"go.uber.org/zap"
43
+ "go.uber.org/zap/zapcore"
44
)
45
46
// FCGIListenSockFileno describes listen socket file number.
@@ -184,10 +185,13 @@ func (f clientCloser) Close() error {
185
return f.rwc.Close()
186
}
187
188
+ logLevel := zapcore.WarnLevel
189
if f.status >= 400 {
188
- f.logger.Error("stderr", zap.ByteString("body", stderr))
189
- } else {
190
- f.logger.Warn("stderr", zap.ByteString("body", stderr))
190
+ logLevel = zapcore.ErrorLevel
191
+ }
192
+
193
+ if c := f.logger.Check(logLevel, "stderr"); c != nil {
194
+ c.Write(zap.ByteString("body", stderr))
195
}
196
197
return f.rwc.Close()
modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
+7
-4
@@ -148,10 +148,13 @@ func (t Transport) RoundTrip(r *http.Request) (*http.Response, error) {
148
zap.Object("request", loggableReq),
149
zap.Object("env", loggableEnv),
150
)
151
- logger.Debug("roundtrip",
152
- zap.String("dial", address),
153
- zap.Object("env", loggableEnv),
154
- zap.Object("request", loggableReq))
151
+ if c := t.logger.Check(zapcore.DebugLevel, "roundtrip"); c != nil {
152
+ c.Write(
153
+ zap.String("dial", address),
154
+ zap.Object("env", loggableEnv),
155
+ zap.Object("request", loggableReq),
156
+ )
157
+ }
158
159
// connect to the backend
160
dialer := net.Dialer{Timeout: time.Duration(t.DialTimeout)}
modules/caddyhttp/reverseproxy/healthchecks.go
+98
-56
@@ -28,6 +28,7 @@ import (
28
"time"
29
30
"go.uber.org/zap"
31
+ "go.uber.org/zap/zapcore"
32
33
"github.com/caddyserver/caddy/v2"
34
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
@@ -270,9 +271,12 @@ type CircuitBreaker interface {
271
func (h *Handler) activeHealthChecker() {
272
defer func() {
273
if err := recover(); err != nil {
273
- h.HealthChecks.Active.logger.Error("active health checker panicked",
274
- zap.Any("error", err),
275
- zap.ByteString("stack", debug.Stack()))
274
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "active health checker panicked"); c != nil {
275
+ c.Write(
276
+ zap.Any("error", err),
277
+ zap.ByteString("stack", debug.Stack()),
278
+ )
279
+ }
280
}
281
}()
282
ticker := time.NewTicker(time.Duration(h.HealthChecks.Active.Interval))
@@ -295,26 +299,33 @@ func (h *Handler) doActiveHealthCheckForAllHosts() {
299
go func(upstream *Upstream) {
300
defer func() {
301
if err := recover(); err != nil {
298
- h.HealthChecks.Active.logger.Error("active health check panicked",
299
- zap.Any("error", err),
300
- zap.ByteString("stack", debug.Stack()))
302
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "active health checker panicked"); c != nil {
303
+ c.Write(
304
+ zap.Any("error", err),
305
+ zap.ByteString("stack", debug.Stack()),
306
+ )
307
+ }
308
}
309
}()
310
311
networkAddr, err := caddy.NewReplacer().ReplaceOrErr(upstream.Dial, true, true)
312
if err != nil {
306
- h.HealthChecks.Active.logger.Error("invalid use of placeholders in dial address for active health checks",
307
- zap.String("address", networkAddr),
308
- zap.Error(err),
309
- )
313
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "invalid use of placeholders in dial address for active health checks"); c != nil {
314
+ c.Write(
315
+ zap.String("address", networkAddr),
316
+ zap.Error(err),
317
+ )
318
+ }
319
return
320
}
321
addr, err := caddy.ParseNetworkAddress(networkAddr)
322
if err != nil {
314
- h.HealthChecks.Active.logger.Error("bad network address",
315
- zap.String("address", networkAddr),
316
- zap.Error(err),
317
- )
323
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "bad network address"); c != nil {
324
+ c.Write(
325
+ zap.String("address", networkAddr),
326
+ zap.Error(err),
327
+ )
328
+ }
329
return
330
}
331
if hcp := uint(upstream.activeHealthCheckPort); hcp != 0 {
@@ -324,9 +335,11 @@ func (h *Handler) doActiveHealthCheckForAllHosts() {
335
addr.StartPort, addr.EndPort = hcp, hcp
336
}
337
if addr.PortRangeSize() != 1 {
327
- h.HealthChecks.Active.logger.Error("multiple addresses (upstream must map to only one address)",
328
- zap.String("address", networkAddr),
329
- )
338
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "multiple addresses (upstream must map to only one address)"); c != nil {
339
+ c.Write(
340
+ zap.String("address", networkAddr),
341
+ )
342
+ }
343
return
344
}
345
hostAddr := addr.JoinHostPort(0)
@@ -339,10 +352,12 @@ func (h *Handler) doActiveHealthCheckForAllHosts() {
352
}
353
err = h.doActiveHealthCheck(DialInfo{Network: addr.Network, Address: dialAddr}, hostAddr, networkAddr, upstream)
354
if err != nil {
342
- h.HealthChecks.Active.logger.Error("active health check failed",
343
- zap.String("address", hostAddr),
344
- zap.Error(err),
345
- )
355
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "active health check failed"); c != nil {
356
+ c.Write(
357
+ zap.String("address", hostAddr),
358
+ zap.Error(err),
359
+ )
360
+ }
361
}
362
}(upstream)
363
}
@@ -441,9 +456,12 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ
456
// increment failures and then check if it has reached the threshold to mark unhealthy
457
err := upstream.Host.countHealthFail(1)
458
if err != nil {
444
- h.HealthChecks.Active.logger.Error("could not count active health failure",
445
- zap.String("host", upstream.Dial),
446
- zap.Error(err))
459
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "could not count active health failure"); c != nil {
460
+ c.Write(
461
+ zap.String("host", upstream.Dial),
462
+ zap.Error(err),
463
+ )
464
+ }
465
return
466
}
467
if upstream.Host.activeHealthFails() >= h.HealthChecks.Active.Fails {
@@ -459,14 +477,19 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ
477
// increment passes and then check if it has reached the threshold to be healthy
478
err := upstream.Host.countHealthPass(1)
479
if err != nil {
462
- h.HealthChecks.Active.logger.Error("could not count active health pass",
463
- zap.String("host", upstream.Dial),
464
- zap.Error(err))
480
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "could not count active health pass"); c != nil {
481
+ c.Write(
482
+ zap.String("host", upstream.Dial),
483
+ zap.Error(err),
484
+ )
485
+ }
486
return
487
}
488
if upstream.Host.activeHealthPasses() >= h.HealthChecks.Active.Passes {
489
if upstream.setHealthy(true) {
469
- h.HealthChecks.Active.logger.Info("host is up", zap.String("host", hostAddr))
490
+ if c := h.HealthChecks.Active.logger.Check(zapcore.InfoLevel, "host is up"); c != nil {
491
+ c.Write(zap.String("host", hostAddr))
492
+ }
493
h.events.Emit(h.ctx, "healthy", map[string]any{"host": hostAddr})
494
upstream.Host.resetHealth()
495
}
@@ -476,10 +499,12 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ
499
// do the request, being careful to tame the response body
500
resp, err := h.HealthChecks.Active.httpClient.Do(req)
501
if err != nil {
479
- h.HealthChecks.Active.logger.Info("HTTP request failed",
480
- zap.String("host", hostAddr),
481
- zap.Error(err),
482
- )
502
+ if c := h.HealthChecks.Active.logger.Check(zapcore.InfoLevel, "HTTP request failed"); c != nil {
503
+ c.Write(
504
+ zap.String("host", hostAddr),
505
+ zap.Error(err),
506
+ )
507
+ }
508
markUnhealthy()
509
return nil
510
}
@@ -496,18 +521,22 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ
521
// if status code is outside criteria, mark down
522
if h.HealthChecks.Active.ExpectStatus > 0 {
523
if !caddyhttp.StatusCodeMatches(resp.StatusCode, h.HealthChecks.Active.ExpectStatus) {
499
- h.HealthChecks.Active.logger.Info("unexpected status code",
500
- zap.Int("status_code", resp.StatusCode),
501
- zap.String("host", hostAddr),
502
- )
524
+ if c := h.HealthChecks.Active.logger.Check(zapcore.InfoLevel, "unexpected status code"); c != nil {
525
+ c.Write(
526
+ zap.Int("status_code", resp.StatusCode),
527
+ zap.String("host", hostAddr),
528
+ )
529
+ }
530
markUnhealthy()
531
return nil
532
}
533
} else if resp.StatusCode < 200 || resp.StatusCode >= 300 {
507
- h.HealthChecks.Active.logger.Info("status code out of tolerances",
508
- zap.Int("status_code", resp.StatusCode),
509
- zap.String("host", hostAddr),
510
- )
534
+ if c := h.HealthChecks.Active.logger.Check(zapcore.InfoLevel, "status code out of tolerances"); c != nil {
535
+ c.Write(
536
+ zap.Int("status_code", resp.StatusCode),
537
+ zap.String("host", hostAddr),
538
+ )
539
+ }
540
markUnhealthy()
541
return nil
542
}
@@ -516,17 +545,21 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ
545
if h.HealthChecks.Active.bodyRegexp != nil {
546
bodyBytes, err := io.ReadAll(body)
547
if err != nil {
519
- h.HealthChecks.Active.logger.Info("failed to read response body",
520
- zap.String("host", hostAddr),
521
- zap.Error(err),
522
- )
548
+ if c := h.HealthChecks.Active.logger.Check(zapcore.InfoLevel, "failed to read response body"); c != nil {
549
+ c.Write(
550
+ zap.String("host", hostAddr),
551
+ zap.Error(err),
552
+ )
553
+ }
554
markUnhealthy()
555
return nil
556
}
557
if !h.HealthChecks.Active.bodyRegexp.Match(bodyBytes) {
527
- h.HealthChecks.Active.logger.Info("response body failed expectations",
528
- zap.String("host", hostAddr),
529
- )
558
+ if c := h.HealthChecks.Active.logger.Check(zapcore.InfoLevel, "response body failed expectations"); c != nil {
559
+ c.Write(
560
+ zap.String("host", hostAddr),
561
+ )
562
+ }
563
markUnhealthy()
564
return nil
565
}
@@ -556,9 +589,12 @@ func (h *Handler) countFailure(upstream *Upstream) {
589
// count failure immediately
590
err := upstream.Host.countFail(1)
591
if err != nil {
559
- h.HealthChecks.Passive.logger.Error("could not count failure",
560
- zap.String("host", upstream.Dial),
561
- zap.Error(err))
592
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "could not count failure"); c != nil {
593
+ c.Write(
594
+ zap.String("host", upstream.Dial),
595
+ zap.Error(err),
596
+ )
597
+ }
598
return
599
}
600
@@ -566,9 +602,12 @@ func (h *Handler) countFailure(upstream *Upstream) {
602
go func(host *Host, failDuration time.Duration) {
603
defer func() {
604
if err := recover(); err != nil {
569
- h.HealthChecks.Passive.logger.Error("passive health check failure forgetter panicked",
570
- zap.Any("error", err),
571
- zap.ByteString("stack", debug.Stack()))
605
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "passive health check failure forgetter panicked"); c != nil {
606
+ c.Write(
607
+ zap.Any("error", err),
608
+ zap.ByteString("stack", debug.Stack()),
609
+ )
610
+ }
611
}
612
}()
613
timer := time.NewTimer(failDuration)
@@ -581,9 +620,12 @@ func (h *Handler) countFailure(upstream *Upstream) {
620
}
621
err := host.countFail(-1)
622
if err != nil {
584
- h.HealthChecks.Passive.logger.Error("could not forget failure",
585
- zap.String("host", upstream.Dial),
586
- zap.Error(err))
623
+ if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "could not forget failure"); c != nil {
624
+ c.Write(
625
+ zap.String("host", upstream.Dial),
626
+ zap.Error(err),
627
+ )
628
+ }
629
}
630
}(upstream.Host, failDuration)
631
}
modules/caddyhttp/reverseproxy/httptransport.go
+7
-2
@@ -33,6 +33,7 @@ import (
33
"github.com/pires/go-proxyproto"
34
"github.com/quic-go/quic-go/http3"
35
"go.uber.org/zap"
36
+ "go.uber.org/zap/zapcore"
37
"golang.org/x/net/http2"
38
39
"github.com/caddyserver/caddy/v2"
@@ -750,7 +751,9 @@ func (c *tcpRWTimeoutConn) Read(b []byte) (int, error) {
751
if c.readTimeout > 0 {
752
err := c.TCPConn.SetReadDeadline(time.Now().Add(c.readTimeout))
753
if err != nil {
753
- c.logger.Error("failed to set read deadline", zap.Error(err))
754
+ if ce := c.logger.Check(zapcore.ErrorLevel, "failed to set read deadline"); ce != nil {
755
+ ce.Write(zap.Error(err))
756
+ }
757
}
758
}
759
return c.TCPConn.Read(b)
@@ -760,7 +763,9 @@ func (c *tcpRWTimeoutConn) Write(b []byte) (int, error) {
763
if c.writeTimeout > 0 {
764
err := c.TCPConn.SetWriteDeadline(time.Now().Add(c.writeTimeout))
765
if err != nil {
763
- c.logger.Error("failed to set write deadline", zap.Error(err))
766
+ if ce := c.logger.Check(zapcore.ErrorLevel, "failed to set write deadline"); ce != nil {
767
+ ce.Write(zap.Error(err))
768
+ }
769
}
770
}
771
return c.TCPConn.Write(b)
modules/caddyhttp/reverseproxy/metrics.go
+7
-3
@@ -8,6 +8,7 @@ import (
8
"github.com/prometheus/client_golang/prometheus"
9
"github.com/prometheus/client_golang/prometheus/promauto"
10
"go.uber.org/zap"
11
+ "go.uber.org/zap/zapcore"
12
)
13
14
var reverseProxyMetrics = struct {
@@ -48,9 +49,12 @@ func (m *metricsUpstreamsHealthyUpdater) Init() {
49
go func() {
50
defer func() {
51
if err := recover(); err != nil {
51
- reverseProxyMetrics.logger.Error("upstreams healthy metrics updater panicked",
52
- zap.Any("error", err),
53
- zap.ByteString("stack", debug.Stack()))
52
+ if c := reverseProxyMetrics.logger.Check(zapcore.ErrorLevel, "upstreams healthy metrics updater panicked"); c != nil {
53
+ c.Write(
54
+ zap.Any("error", err),
55
+ zap.ByteString("stack", debug.Stack()),
56
+ )
57
+ }
58
}
59
}()
60
modules/caddyhttp/reverseproxy/reverseproxy.go
+38
-16
@@ -33,6 +33,7 @@ import (
33
"time"
34
35
"go.uber.org/zap"
36
+ "go.uber.org/zap/zapcore"
37
"golang.org/x/net/http/httpguts"
38
39
"github.com/caddyserver/caddy/v2"
@@ -439,7 +440,9 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
440
if h.LoadBalancing != nil {
441
lbWait = time.Duration(h.LoadBalancing.TryInterval)
442
}
442
- h.logger.Debug("retrying", zap.Error(proxyErr), zap.Duration("after", lbWait))
443
+ if c := h.logger.Check(zapcore.DebugLevel, "retrying"); c != nil {
444
+ c.Write(zap.Error(proxyErr), zap.Duration("after", lbWait))
445
+ }
446
}
447
retries++
448
}
@@ -466,13 +469,17 @@ func (h *Handler) proxyLoopIteration(r *http.Request, origReq *http.Request, w h
469
if h.DynamicUpstreams != nil {
470
dUpstreams, err := h.DynamicUpstreams.GetUpstreams(r)
471
if err != nil {
469
- h.logger.Error("failed getting dynamic upstreams; falling back to static upstreams", zap.Error(err))
472
+ if c := h.logger.Check(zapcore.ErrorLevel, "failed getting dynamic upstreams; falling back to static upstreams"); c != nil {
473
+ c.Write(zap.Error(err))
474
+ }
475
} else {
476
upstreams = dUpstreams
477
for _, dUp := range dUpstreams {
478
h.provisionUpstream(dUp)
479
}
475
- h.logger.Debug("provisioned dynamic upstreams", zap.Int("count", len(dUpstreams)))
480
+ if c := h.logger.Check(zapcore.DebugLevel, "provisioned dynamic upstreams"); c != nil {
481
+ c.Write(zap.Int("count", len(dUpstreams)))
482
+ }
483
defer func() {
484
// these upstreams are dynamic, so they are only used for this iteration
485
// of the proxy loop; be sure to let them go away when we're done with them
@@ -503,9 +510,12 @@ func (h *Handler) proxyLoopIteration(r *http.Request, origReq *http.Request, w h
510
return true, fmt.Errorf("making dial info: %v", err)
511
}
512
506
- h.logger.Debug("selected upstream",
507
- zap.String("dial", dialInfo.Address),
508
- zap.Int("total_upstreams", len(upstreams)))
513
+ if c := h.logger.Check(zapcore.DebugLevel, "selected upstream"); c != nil {
514
+ c.Write(
515
+ zap.String("dial", dialInfo.Address),
516
+ zap.Int("total_upstreams", len(upstreams)),
517
+ )
518
+ }
519
520
// attach to the request information about how to dial the upstream;
521
// this is necessary because the information cannot be sufficiently
@@ -811,16 +821,22 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe
821
ShouldLogCredentials: shouldLogCredentials,
822
}),
823
)
824
+
825
if err != nil {
815
- logger.Debug("upstream roundtrip", zap.Error(err))
826
+ if c := logger.Check(zapcore.DebugLevel, "upstream roundtrip"); c != nil {
827
+ c.Write(zap.Error(err))
828
+ }
829
return err
830
}
818
- logger.Debug("upstream roundtrip",
819
- zap.Object("headers", caddyhttp.LoggableHTTPHeader{
820
- Header: res.Header,
821
- ShouldLogCredentials: shouldLogCredentials,
822
- }),
823
- zap.Int("status", res.StatusCode))
831
+ if c := logger.Check(zapcore.DebugLevel, "upstream roundtrip"); c != nil {
832
+ c.Write(
833
+ zap.Object("headers", caddyhttp.LoggableHTTPHeader{
834
+ Header: res.Header,
835
+ ShouldLogCredentials: shouldLogCredentials,
836
+ }),
837
+ zap.Int("status", res.StatusCode),
838
+ )
839
+ }
840
841
// duration until upstream wrote response headers (roundtrip duration)
842
repl.Set("http.reverse_proxy.upstream.latency", duration)
@@ -879,7 +895,9 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe
895
repl.Set("http.reverse_proxy.status_code", res.StatusCode)
896
repl.Set("http.reverse_proxy.status_text", res.Status)
897
882
- logger.Debug("handling response", zap.Int("handler", i))
898
+ if c := logger.Check(zapcore.DebugLevel, "handling response"); c != nil {
899
+ c.Write(zap.Int("handler", i))
900
+ }
901
902
// we make some data available via request context to child routes
903
// so that they may inherit some options and functions from the
@@ -975,7 +993,9 @@ func (h *Handler) finalizeResponse(
993
err := h.copyResponse(rw, res.Body, h.flushInterval(req, res), logger)
994
errClose := res.Body.Close() // close now, instead of defer, to populate res.Trailer
995
if h.VerboseLogs || errClose != nil {
978
- logger.Debug("closed response body from upstream", zap.Error(errClose))
996
+ if c := logger.Check(zapcore.DebugLevel, "closed response body from upstream"); c != nil {
997
+ c.Write(zap.Error(errClose))
998
+ }
999
}
1000
if err != nil {
1001
// we're streaming the response and we've already written headers, so
@@ -983,7 +1003,9 @@ func (h *Handler) finalizeResponse(
1003
// we'll just log the error and abort the stream here and panic just as
1004
// the standard lib's proxy to propagate the stream error.
1005
// see issue https://github.com/caddyserver/caddy/issues/5951
986
- logger.Warn("aborting with incomplete response", zap.Error(err))
1006
+ if c := logger.Check(zapcore.WarnLevel, "aborting with incomplete response"); c != nil {
1007
+ c.Write(zap.Error(err))
1008
+ }
1009
// no extra logging from stdlib
1010
panic(http.ErrAbortHandler)
1011
}
modules/caddyhttp/reverseproxy/streaming.go
+59
-25
@@ -31,6 +31,7 @@ import (
31
"unsafe"
32
33
"go.uber.org/zap"
34
+ "go.uber.org/zap/zapcore"
35
"golang.org/x/net/http/httpguts"
36
)
37
@@ -41,14 +42,18 @@ func (h *Handler) handleUpgradeResponse(logger *zap.Logger, wg *sync.WaitGroup,
42
// Taken from https://github.com/golang/go/commit/5c489514bc5e61ad9b5b07bd7d8ec65d66a0512a
43
// We know reqUpType is ASCII, it's checked by the caller.
44
if !asciiIsPrint(resUpType) {
44
- logger.Debug("backend tried to switch to invalid protocol",
45
- zap.String("backend_upgrade", resUpType))
45
+ if c := logger.Check(zapcore.DebugLevel, "backend tried to switch to invalid protocol"); c != nil {
46
+ c.Write(zap.String("backend_upgrade", resUpType))
47
+ }
48
return
49
}
50
if !asciiEqualFold(reqUpType, resUpType) {
49
- logger.Debug("backend tried to switch to unexpected protocol via Upgrade header",
50
- zap.String("backend_upgrade", resUpType),
51
- zap.String("requested_upgrade", reqUpType))
51
+ if c := logger.Check(zapcore.DebugLevel, "backend tried to switch to unexpected protocol via Upgrade header"); c != nil {
52
+ c.Write(
53
+ zap.String("backend_upgrade", resUpType),
54
+ zap.String("requested_upgrade", reqUpType),
55
+ )
56
+ }
57
return
58
}
59
@@ -68,12 +73,16 @@ func (h *Handler) handleUpgradeResponse(logger *zap.Logger, wg *sync.WaitGroup,
73
//nolint:bodyclose
74
conn, brw, hijackErr := http.NewResponseController(rw).Hijack()
75
if errors.Is(hijackErr, http.ErrNotSupported) {
71
- h.logger.Error("can't switch protocols using non-Hijacker ResponseWriter", zap.String("type", fmt.Sprintf("%T", rw)))
76
+ if c := logger.Check(zapcore.ErrorLevel, "can't switch protocols using non-Hijacker ResponseWriter"); c != nil {
77
+ c.Write(zap.String("type", fmt.Sprintf("%T", rw)))
78
+ }
79
return
80
}
81
82
if hijackErr != nil {
76
- h.logger.Error("hijack failed on protocol switch", zap.Error(hijackErr))
83
+ if c := logger.Check(zapcore.ErrorLevel, "hijack failed on protocol switch"); c != nil {
84
+ c.Write(zap.Error(hijackErr))
85
+ }
86
return
87
}
88
@@ -93,11 +102,15 @@ func (h *Handler) handleUpgradeResponse(logger *zap.Logger, wg *sync.WaitGroup,
102
start := time.Now()
103
defer func() {
104
conn.Close()
96
- logger.Debug("connection closed", zap.Duration("duration", time.Since(start)))
105
+ if c := logger.Check(zapcore.DebugLevel, "hijack failed on protocol switch"); c != nil {
106
+ c.Write(zap.Duration("duration", time.Since(start)))
107
+ }
108
}()
109
110
if err := brw.Flush(); err != nil {
100
- logger.Debug("response flush", zap.Error(err))
111
+ if c := logger.Check(zapcore.DebugLevel, "response flush"); c != nil {
112
+ c.Write(zap.Error(err))
113
+ }
114
return
115
}
116
@@ -107,7 +120,9 @@ func (h *Handler) handleUpgradeResponse(logger *zap.Logger, wg *sync.WaitGroup,
120
data, _ := brw.Peek(buffered)
121
_, err := backConn.Write(data)
122
if err != nil {
110
- logger.Debug("backConn write failed", zap.Error(err))
123
+ if c := logger.Check(zapcore.DebugLevel, "backConn write failed"); c != nil {
124
+ c.Write(zap.Error(err))
125
+ }
126
return
127
}
128
}
@@ -148,9 +163,13 @@ func (h *Handler) handleUpgradeResponse(logger *zap.Logger, wg *sync.WaitGroup,
163
go spc.copyFromBackend(errc)
164
select {
165
case err := <-errc:
151
- logger.Debug("streaming error", zap.Error(err))
166
+ if c := logger.Check(zapcore.DebugLevel, "streaming error"); c != nil {
167
+ c.Write(zap.Error(err))
168
+ }
169
case time := <-timeoutc:
153
- logger.Debug("stream timed out", zap.Time("timeout", time))
170
+ if c := logger.Check(zapcore.DebugLevel, "stream timed out"); c != nil {
171
+ c.Write(zap.Time("timeout", time))
172
+ }
173
}
174
}
175
@@ -247,7 +266,9 @@ func (h Handler) copyBuffer(dst io.Writer, src io.Reader, buf []byte, logger *za
266
logger.Debug("waiting to read from upstream")
267
nr, rerr := src.Read(buf)
268
logger := logger.With(zap.Int("read", nr))
250
- logger.Debug("read from upstream", zap.Error(rerr))
269
+ if c := logger.Check(zapcore.DebugLevel, "read from upstream"); c != nil {
270
+ c.Write(zap.Error(rerr))
271
+ }
272
if rerr != nil && rerr != io.EOF && rerr != context.Canceled {
273
// TODO: this could be useful to know (indeed, it revealed an error in our
274
// fastcgi PoC earlier; but it's this single error report here that necessitates
@@ -256,7 +277,9 @@ func (h Handler) copyBuffer(dst io.Writer, src io.Reader, buf []byte, logger *za
277
// something we need to report to the client, but read errors are a problem on our
278
// end for sure. so we need to decide what we want.)
279
// p.logf("copyBuffer: ReverseProxy read error during body copy: %v", rerr)
259
- h.logger.Error("reading from backend", zap.Error(rerr))
280
+ if c := logger.Check(zapcore.ErrorLevel, "reading from backend"); c != nil {
281
+ c.Write(zap.Error(rerr))
282
+ }
283
}
284
if nr > 0 {
285
logger.Debug("writing to downstream")
@@ -264,10 +287,13 @@ func (h Handler) copyBuffer(dst io.Writer, src io.Reader, buf []byte, logger *za
287
if nw > 0 {
288
written += int64(nw)
289
}
267
- logger.Debug("wrote to downstream",
268
- zap.Int("written", nw),
269
- zap.Int64("written_total", written),
270
- zap.Error(werr))
290
+ if c := logger.Check(zapcore.DebugLevel, "wrote to downstream"); c != nil {
291
+ c.Write(
292
+ zap.Int("written", nw),
293
+ zap.Int64("written_total", written),
294
+ zap.Error(werr),
295
+ )
296
+ }
297
if werr != nil {
298
return written, fmt.Errorf("writing: %w", werr)
299
}
@@ -347,13 +373,17 @@ func (h *Handler) cleanupConnections() error {
373
if len(h.connections) > 0 {
374
delay := time.Duration(h.StreamCloseDelay)
375
h.connectionsCloseTimer = time.AfterFunc(delay, func() {
350
- h.logger.Debug("closing streaming connections after delay",
351
- zap.Duration("delay", delay))
376
+ if c := h.logger.Check(zapcore.DebugLevel, "closing streaming connections after delay"); c != nil {
377
+ c.Write(zap.Duration("delay", delay))
378
+ }
379
err := h.closeConnections()
380
if err != nil {
354
- h.logger.Error("failed to closed connections after delay",
355
- zap.Error(err),
356
- zap.Duration("delay", delay))
381
+ if c := h.logger.Check(zapcore.ErrorLevel, "failed to closed connections after delay"); c != nil {
382
+ c.Write(
383
+ zap.Error(err),
384
+ zap.Duration("delay", delay),
385
+ )
386
+ }
387
}
388
})
389
}
@@ -494,7 +524,9 @@ func (m *maxLatencyWriter) Write(p []byte) (n int, err error) {
524
m.mu.Lock()
525
defer m.mu.Unlock()
526
n, err = m.dst.Write(p)
497
- m.logger.Debug("wrote bytes", zap.Int("n", n), zap.Error(err))
527
+ if c := m.logger.Check(zapcore.DebugLevel, "wrote bytes"); c != nil {
528
+ c.Write(zap.Int("n", n), zap.Error(err))
529
+ }
530
if m.latency < 0 {
531
m.logger.Debug("flushing immediately")
532
//nolint:errcheck
@@ -510,7 +542,9 @@ func (m *maxLatencyWriter) Write(p []byte) (n int, err error) {
542
} else {
543
m.t.Reset(m.latency)
544
}
513
- m.logger.Debug("timer set for delayed flush", zap.Duration("duration", m.latency))
545
+ if c := m.logger.Check(zapcore.DebugLevel, "timer set for delayed flush"); c != nil {
546
+ c.Write(zap.Duration("duration", m.latency))
547
+ }
548
m.flushPending = true
549
return
550
}
modules/caddyhttp/reverseproxy/upstreams.go
+41
-21
@@ -12,6 +12,7 @@ import (
12
"time"
13
14
"go.uber.org/zap"
15
+ "go.uber.org/zap/zapcore"
16
17
"github.com/caddyserver/caddy/v2"
18
)
@@ -136,10 +137,13 @@ func (su SRVUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
137
return allNew(cached.upstreams), nil
138
}
139
139
- su.logger.Debug("refreshing SRV upstreams",
140
- zap.String("service", service),
141
- zap.String("proto", proto),
142
- zap.String("name", name))
140
+ if c := su.logger.Check(zapcore.DebugLevel, "refreshing SRV upstreams"); c != nil {
141
+ c.Write(
142
+ zap.String("service", service),
143
+ zap.String("proto", proto),
144
+ zap.String("name", name),
145
+ )
146
+ }
147
148
_, records, err := su.resolver.LookupSRV(r.Context(), service, proto, name)
149
if err != nil {
@@ -148,23 +152,30 @@ func (su SRVUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
152
// only return an error if no records were also returned.
153
if len(records) == 0 {
154
if su.GracePeriod > 0 {
151
- su.logger.Error("SRV lookup failed; using previously cached", zap.Error(err))
155
+ if c := su.logger.Check(zapcore.ErrorLevel, "SRV lookup failed; using previously cached"); c != nil {
156
+ c.Write(zap.Error(err))
157
+ }
158
cached.freshness = time.Now().Add(time.Duration(su.GracePeriod) - time.Duration(su.Refresh))
159
srvs[suAddr] = cached
160
return allNew(cached.upstreams), nil
161
}
162
return nil, err
163
}
158
- su.logger.Warn("SRV records filtered", zap.Error(err))
164
+ if c := su.logger.Check(zapcore.WarnLevel, "SRV records filtered"); c != nil {
165
+ c.Write(zap.Error(err))
166
+ }
167
}
168
169
upstreams := make([]Upstream, len(records))
170
for i, rec := range records {
163
- su.logger.Debug("discovered SRV record",
164
- zap.String("target", rec.Target),
165
- zap.Uint16("port", rec.Port),
166
- zap.Uint16("priority", rec.Priority),
167
- zap.Uint16("weight", rec.Weight))
171
+ if c := su.logger.Check(zapcore.DebugLevel, "discovered SRV record"); c != nil {
172
+ c.Write(
173
+ zap.String("target", rec.Target),
174
+ zap.Uint16("port", rec.Port),
175
+ zap.Uint16("priority", rec.Priority),
176
+ zap.Uint16("weight", rec.Weight),
177
+ )
178
+ }
179
addr := net.JoinHostPort(rec.Target, strconv.Itoa(int(rec.Port)))
180
upstreams[i] = Upstream{Dial: addr}
181
}
@@ -361,10 +372,13 @@ func (au AUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
372
name := repl.ReplaceAll(au.Name, "")
373
port := repl.ReplaceAll(au.Port, "")
374
364
- au.logger.Debug("refreshing A upstreams",
365
- zap.String("version", ipVersion),
366
- zap.String("name", name),
367
- zap.String("port", port))
375
+ if c := au.logger.Check(zapcore.DebugLevel, "refreshing A upstreams"); c != nil {
376
+ c.Write(
377
+ zap.String("version", ipVersion),
378
+ zap.String("name", name),
379
+ zap.String("port", port),
380
+ )
381
+ }
382
383
ips, err := au.resolver.LookupIP(r.Context(), ipVersion, name)
384
if err != nil {
@@ -373,8 +387,9 @@ func (au AUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
387
388
upstreams := make([]Upstream, len(ips))
389
for i, ip := range ips {
376
- au.logger.Debug("discovered A record",
377
- zap.String("ip", ip.String()))
390
+ if c := au.logger.Check(zapcore.DebugLevel, "discovered A record"); c != nil {
391
+ c.Write(zap.String("ip", ip.String()))
392
+ }
393
upstreams[i] = Upstream{
394
Dial: net.JoinHostPort(ip.String(), port),
395
}
@@ -467,11 +482,16 @@ func (mu MultiUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
482
483
up, err := src.GetUpstreams(r)
484
if err != nil {
470
- mu.logger.Error("upstream source returned error",
471
- zap.Int("source_idx", i),
472
- zap.Error(err))
485
+ if c := mu.logger.Check(zapcore.ErrorLevel, "upstream source returned error"); c != nil {
486
+ c.Write(
487
+ zap.Int("source_idx", i),
488
+ zap.Error(err),
489
+ )
490
+ }
491
} else if len(up) == 0 {
474
- mu.logger.Warn("upstream source returned 0 upstreams", zap.Int("source_idx", i))
492
+ if c := mu.logger.Check(zapcore.WarnLevel, "upstream source returned 0 upstreams"); c != nil {
493
+ c.Write(zap.Int("source_idx", i))
494
+ }
495
} else {
496
upstreams = append(upstreams, up...)
497
}
modules/caddyhttp/rewrite/rewrite.go
+4
-6
@@ -133,19 +133,17 @@ func (rewr Rewrite) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy
133
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
134
const message = "rewrote request"
135
136
- if rewr.logger.Check(zap.DebugLevel, message) == nil {
136
+ c := rewr.logger.Check(zap.DebugLevel, message)
137
+ if c == nil {
138
rewr.Rewrite(r, repl)
139
return next.ServeHTTP(w, r)
140
}
141
141
- logger := rewr.logger.With(
142
- zap.Object("request", caddyhttp.LoggableHTTPRequest{Request: r}),
143
- )
144
-
142
changed := rewr.Rewrite(r, repl)
143
144
if changed {
148
- logger.Debug(message,
145
+ c.Write(
146
+ zap.Object("request", caddyhttp.LoggableHTTPRequest{Request: r}),
147
zap.String("method", r.Method),
148
zap.String("uri", r.RequestURI),
149
)
modules/caddyhttp/server.go
+91
-50
@@ -275,7 +275,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
275
if r.ProtoMajor < 3 {
276
err := s.h3server.SetQUICHeaders(w.Header())
277
if err != nil {
278
- s.logger.Error("setting HTTP/3 Alt-Svc header", zap.Error(err))
278
+ if c := s.logger.Check(zapcore.ErrorLevel, "setting HTTP/3 Alt-Svc header"); c != nil {
279
+ c.Write(zap.Error(err))
280
+ }
281
}
282
}
283
}
@@ -283,9 +285,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
285
// reject very long methods; probably a mistake or an attack
286
if len(r.Method) > 32 {
287
if s.shouldLogRequest(r) {
286
- s.accessLogger.Debug("rejecting request with long method",
287
- zap.String("method_trunc", r.Method[:32]),
288
- zap.String("remote_addr", r.RemoteAddr))
288
+ if c := s.accessLogger.Check(zapcore.DebugLevel, "rejecting request with long method"); c != nil {
289
+ c.Write(
290
+ zap.String("method_trunc", r.Method[:32]),
291
+ zap.String("remote_addr", r.RemoteAddr),
292
+ )
293
+ }
294
}
295
w.WriteHeader(http.StatusMethodNotAllowed)
296
return
@@ -300,7 +305,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
305
//nolint:bodyclose
306
err := http.NewResponseController(w).EnableFullDuplex()
307
if err != nil {
303
- s.logger.Warn("failed to enable full duplex", zap.Error(err))
308
+ if c := s.logger.Check(zapcore.WarnLevel, "failed to enable full duplex"); c != nil {
309
+ c.Write(zap.Error(err))
310
+ }
311
}
312
}
313
@@ -379,6 +386,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
386
// add HTTP error information to request context
387
r = s.Errors.WithError(r, err)
388
389
+ var fields []zapcore.Field
390
if s.Errors != nil && len(s.Errors.Routes) > 0 {
391
// execute user-defined error handling route
392
err2 := s.errorHandlerChain.ServeHTTP(w, r)
@@ -386,17 +394,28 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
394
// user's error route handled the error response
395
// successfully, so now just log the error
396
for _, logger := range errLoggers {
389
- logger.Debug(errMsg, errFields...)
397
+ if c := logger.Check(zapcore.DebugLevel, errMsg); c != nil {
398
+ if fields == nil {
399
+ fields = errFields()
400
+ }
401
+
402
+ c.Write(fields...)
403
+ }
404
}
405
} else {
406
// well... this is awkward
393
- errFields = append([]zapcore.Field{
394
- zap.String("error", err2.Error()),
395
- zap.Namespace("first_error"),
396
- zap.String("msg", errMsg),
397
- }, errFields...)
407
for _, logger := range errLoggers {
399
- logger.Error("error handling handler error", errFields...)
408
+ if c := logger.Check(zapcore.ErrorLevel, "error handling handler error"); c != nil {
409
+ if fields == nil {
410
+ fields = errFields()
411
+ fields = append([]zapcore.Field{
412
+ zap.String("error", err2.Error()),
413
+ zap.Namespace("first_error"),
414
+ zap.String("msg", errMsg),
415
+ }, fields...)
416
+ }
417
+ c.Write(fields...)
418
+ }
419
}
420
if handlerErr, ok := err.(HandlerError); ok {
421
w.WriteHeader(handlerErr.StatusCode)
@@ -405,11 +424,17 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
424
}
425
}
426
} else {
427
+ logLevel := zapcore.DebugLevel
428
+ if errStatus >= 500 {
429
+ logLevel = zapcore.ErrorLevel
430
+ }
431
+
432
for _, logger := range errLoggers {
409
- if errStatus >= 500 {
410
- logger.Error(errMsg, errFields...)
411
- } else {
412
- logger.Debug(errMsg, errFields...)
433
+ if c := logger.Check(logLevel, errMsg); c != nil {
434
+ if fields == nil {
435
+ fields = errFields()
436
+ }
437
+ c.Write(fields...)
438
}
439
}
440
w.WriteHeader(errStatus)
@@ -746,7 +771,9 @@ func (s *Server) logTrace(mh MiddlewareHandler) {
771
if s.Logs == nil || !s.Logs.Trace {
772
return
773
}
749
- s.traceLogger.Debug(caddy.GetModuleName(mh), zap.Any("module", mh))
774
+ if c := s.traceLogger.Check(zapcore.DebugLevel, caddy.GetModuleName(mh)); c != nil {
775
+ c.Write(zap.Any("module", mh))
776
+ }
777
}
778
779
// logRequest logs the request to access logs, unless skipped.
@@ -759,50 +786,64 @@ func (s *Server) logRequest(
786
return
787
}
788
762
- repl.Set("http.response.status", wrec.Status()) // will be 0 if no response is written by us (Go will write 200 to client)
763
- repl.Set("http.response.size", wrec.Size())
789
+ status := wrec.Status()
790
+ size := wrec.Size()
791
+
792
+ repl.Set("http.response.status", status) // will be 0 if no response is written by us (Go will write 200 to client)
793
+ repl.Set("http.response.size", size)
794
repl.Set("http.response.duration", duration)
795
repl.Set("http.response.duration_ms", duration.Seconds()*1e3) // multiply seconds to preserve decimal (see #4666)
796
767
- userID, _ := repl.GetString("http.auth.user.id")
768
-
769
- reqBodyLength := 0
770
- if bodyReader != nil {
771
- reqBodyLength = bodyReader.Length
772
- }
773
-
774
- extra := r.Context().Value(ExtraLogFieldsCtxKey).(*ExtraLogFields)
775
-
776
- fieldCount := 6
777
- fields := make([]zapcore.Field, 0, fieldCount+len(extra.fields))
778
- fields = append(fields,
779
- zap.Int("bytes_read", reqBodyLength),
780
- zap.String("user_id", userID),
781
- zap.Duration("duration", *duration),
782
- zap.Int("size", wrec.Size()),
783
- zap.Int("status", wrec.Status()),
784
- zap.Object("resp_headers", LoggableHTTPHeader{
785
- Header: wrec.Header(),
786
- ShouldLogCredentials: shouldLogCredentials,
787
- }))
788
- fields = append(fields, extra.fields...)
789
-
797
loggers := []*zap.Logger{accLog}
798
if s.Logs != nil {
799
loggers = s.Logs.wrapLogger(accLog, r)
800
}
801
795
- // wrapping may return multiple loggers, so we log to all of them
802
+ message := "handled request"
803
+ if nop, ok := GetVar(r.Context(), "unhandled").(bool); ok && nop {
804
+ message = "NOP"
805
+ }
806
+
807
+ logLevel := zapcore.InfoLevel
808
+ if status >= 500 {
809
+ logLevel = zapcore.ErrorLevel
810
+ }
811
+
812
+ var fields []zapcore.Field
813
for _, logger := range loggers {
797
- logAtLevel := logger.Info
798
- if wrec.Status() >= 500 {
799
- logAtLevel = logger.Error
814
+ c := logger.Check(logLevel, message)
815
+ if c == nil {
816
+ continue
817
}
801
- message := "handled request"
802
- if nop, ok := GetVar(r.Context(), "unhandled").(bool); ok && nop {
803
- message = "NOP"
818
+
819
+ if fields == nil {
820
+
821
+ userID, _ := repl.GetString("http.auth.user.id")
822
+
823
+ reqBodyLength := 0
824
+ if bodyReader != nil {
825
+ reqBodyLength = bodyReader.Length
826
+ }
827
+
828
+ extra := r.Context().Value(ExtraLogFieldsCtxKey).(*ExtraLogFields)
829
+
830
+ fieldCount := 6
831
+ fields = make([]zapcore.Field, 0, fieldCount+len(extra.fields))
832
+ fields = append(fields,
833
+ zap.Int("bytes_read", reqBodyLength),
834
+ zap.String("user_id", userID),
835
+ zap.Duration("duration", *duration),
836
+ zap.Int("size", size),
837
+ zap.Int("status", status),
838
+ zap.Object("resp_headers", LoggableHTTPHeader{
839
+ Header: wrec.Header(),
840
+ ShouldLogCredentials: shouldLogCredentials,
841
+ }),
842
+ )
843
+ fields = append(fields, extra.fields...)
844
}
805
- logAtLevel(message, fields...)
845
+
846
+ c.Write(fields...)
847
}
848
}
849
modules/caddyhttp/server_test.go
+23
@@ -121,6 +121,29 @@ func BenchmarkServer_LogRequest(b *testing.B) {
121
}
122
}
123
124
+func BenchmarkServer_LogRequest_NopLogger(b *testing.B) {
125
+ s := &Server{}
126
+
127
+ extra := new(ExtraLogFields)
128
+ ctx := context.WithValue(context.Background(), ExtraLogFieldsCtxKey, extra)
129
+
130
+ req := httptest.NewRequest(http.MethodGet, "/", nil).WithContext(ctx)
131
+ rec := httptest.NewRecorder()
132
+ wrec := NewResponseRecorder(rec, nil, nil)
133
+
134
+ duration := 50 * time.Millisecond
135
+ repl := NewTestReplacer(req)
136
+ bodyReader := &lengthReader{Source: req.Body}
137
+
138
+ accLog := zap.NewNop()
139
+
140
+ b.ResetTimer()
141
+
142
+ for i := 0; i < b.N; i++ {
143
+ s.logRequest(accLog, req, wrec, &duration, repl, bodyReader, false)
144
+ }
145
+}
146
+
147
func BenchmarkServer_LogRequest_WithTraceID(b *testing.B) {
148
s := &Server{}
149
modules/caddyhttp/tracing/tracerprovider.go
+4
-1
@@ -7,6 +7,7 @@ import (
7
8
sdktrace "go.opentelemetry.io/otel/sdk/trace"
9
"go.uber.org/zap"
10
+ "go.uber.org/zap/zapcore"
11
)
12
13
// globalTracerProvider stores global tracer provider and is responsible for graceful shutdown when nobody is using it.
@@ -47,7 +48,9 @@ func (t *tracerProvider) cleanupTracerProvider(logger *zap.Logger) error {
48
if t.tracerProvider != nil {
49
// tracerProvider.ForceFlush SHOULD be invoked according to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#forceflush
50
if err := t.tracerProvider.ForceFlush(context.Background()); err != nil {
50
- logger.Error("forcing flush", zap.Error(err))
51
+ if c := logger.Check(zapcore.ErrorLevel, "forcing flush"); c != nil {
52
+ c.Write(zap.Error(err))
53
+ }
54
}
55
56
// tracerProvider.Shutdown MUST be invoked according to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#shutdown
modules/caddypki/acmeserver/acmeserver.go
+10
-3
@@ -35,6 +35,7 @@ import (
35
"github.com/smallstep/certificates/db"
36
"github.com/smallstep/nosql"
37
"go.uber.org/zap"
38
+ "go.uber.org/zap/zapcore"
39
40
"github.com/caddyserver/caddy/v2"
41
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
@@ -243,10 +244,14 @@ func (ash Handler) Cleanup() error {
244
key := ash.getDatabaseKey()
245
deleted, err := databasePool.Delete(key)
246
if deleted {
246
- ash.logger.Debug("unloading unused CA database", zap.String("db_key", key))
247
+ if c := ash.logger.Check(zapcore.DebugLevel, "unloading unused CA database"); c != nil {
248
+ c.Write(zap.String("db_key", key))
249
+ }
250
}
251
if err != nil {
249
- ash.logger.Error("closing CA database", zap.String("db_key", key), zap.Error(err))
252
+ if c := ash.logger.Check(zapcore.ErrorLevel, "closing CA database"); c != nil {
253
+ c.Write(zap.String("db_key", key), zap.Error(err))
254
+ }
255
}
256
return err
257
}
@@ -271,7 +276,9 @@ func (ash Handler) openDatabase() (*db.AuthDB, error) {
276
})
277
278
if loaded {
274
- ash.logger.Debug("loaded preexisting CA database", zap.String("db_key", key))
279
+ if c := ash.logger.Check(zapcore.DebugLevel, "loaded preexisting CA database"); c != nil {
280
+ c.Write(zap.String("db_key", key))
281
+ }
282
}
283
284
return database.(databaseCloser).DB, err
modules/caddytls/acmeissuer.go
+4
-1
@@ -30,6 +30,7 @@ import (
30
"github.com/caddyserver/zerossl"
31
"github.com/mholt/acmez/v2/acme"
32
"go.uber.org/zap"
33
+ "go.uber.org/zap/zapcore"
34
35
"github.com/caddyserver/caddy/v2"
36
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -321,7 +322,9 @@ func (iss *ACMEIssuer) generateZeroSSLEABCredentials(ctx context.Context, acct a
322
return nil, acct, fmt.Errorf("failed getting EAB credentials: HTTP %d", resp.StatusCode)
323
}
324
324
- iss.logger.Info("generated EAB credentials", zap.String("key_id", result.EABKID))
325
+ if c := iss.logger.Check(zapcore.InfoLevel, "generated EAB credentials"); c != nil {
326
+ c.Write(zap.String("key_id", result.EABKID))
327
+ }
328
329
return &acme.EAB{
330
KeyID: result.EABKID,
modules/caddytls/automation.go
+19
-9
@@ -26,6 +26,7 @@ import (
26
"github.com/caddyserver/certmagic"
27
"github.com/mholt/acmez/v2"
28
"go.uber.org/zap"
29
+ "go.uber.org/zap/zapcore"
30
31
"github.com/caddyserver/caddy/v2"
32
)
@@ -292,21 +293,30 @@ func (ap *AutomationPolicy) Provision(tlsApp *TLS) error {
293
remoteIP, _, _ = net.SplitHostPort(remote.String())
294
}
295
}
295
- tlsApp.logger.Debug("asking for permission for on-demand certificate",
296
- zap.String("remote_ip", remoteIP),
297
- zap.String("domain", name))
296
+ if c := tlsApp.logger.Check(zapcore.DebugLevel, "asking for permission for on-demand certificate"); c != nil {
297
+ c.Write(
298
+ zap.String("remote_ip", remoteIP),
299
+ zap.String("domain", name),
300
+ )
301
+ }
302
303
// ask the permission module if this cert is allowed
304
if err := tlsApp.Automation.OnDemand.permission.CertificateAllowed(ctx, name); err != nil {
305
// distinguish true errors from denials, because it's important to elevate actual errors
306
if errors.Is(err, ErrPermissionDenied) {
303
- tlsApp.logger.Debug("on-demand certificate issuance denied",
304
- zap.String("domain", name),
305
- zap.Error(err))
307
+ if c := tlsApp.logger.Check(zapcore.DebugLevel, "on-demand certificate issuance denied"); c != nil {
308
+ c.Write(
309
+ zap.String("domain", name),
310
+ zap.Error(err),
311
+ )
312
+ }
313
} else {
307
- tlsApp.logger.Error("failed to get permission for on-demand certificate",
308
- zap.String("domain", name),
309
- zap.Error(err))
314
+ if c := tlsApp.logger.Check(zapcore.ErrorLevel, "failed to get permission for on-demand certificate"); c != nil {
315
+ c.Write(
316
+ zap.String("domain", name),
317
+ zap.Error(err),
318
+ )
319
+ }
320
}
321
return err
322
}
modules/caddytls/certmanagers.go
+4
-1
@@ -12,6 +12,7 @@ import (
12
"github.com/caddyserver/certmagic"
13
"github.com/tailscale/tscert"
14
"go.uber.org/zap"
15
+ "go.uber.org/zap/zapcore"
16
17
"github.com/caddyserver/caddy/v2"
18
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -46,7 +47,9 @@ func (ts Tailscale) GetCertificate(ctx context.Context, hello *tls.ClientHelloIn
47
return nil, nil // pass-thru: Tailscale can't offer a cert for this name
48
}
49
if err != nil {
49
- ts.logger.Warn("could not get status; will try to get certificate anyway", zap.Error(err))
50
+ if c := ts.logger.Check(zapcore.WarnLevel, "could not get status; will try to get certificate anyway"); c != nil {
51
+ c.Write(zap.Error(err))
52
+ }
53
}
54
return tscert.GetCertificateWithContext(ctx, hello)
55
}
modules/caddytls/connpolicy.go
+4
-2
@@ -28,6 +28,7 @@ import (
28
29
"github.com/mholt/acmez/v2"
30
"go.uber.org/zap"
31
+ "go.uber.org/zap/zapcore"
32
33
"github.com/caddyserver/caddy/v2"
34
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -338,8 +339,9 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error {
339
340
cfg.KeyLogWriter = logFile.(io.Writer)
341
341
- tlsApp.logger.Warn("TLS SECURITY COMPROMISED: secrets logging is enabled!",
342
- zap.String("log_filename", filename))
342
+ if c := tlsApp.logger.Check(zapcore.WarnLevel, "TLS SECURITY COMPROMISED: secrets logging is enabled!"); c != nil {
343
+ c.Write(zap.String("log_filename", filename))
344
+ }
345
}
346
347
setDefaultTLSParams(cfg)
modules/caddytls/matchers.go
+7
-2
@@ -25,6 +25,7 @@ import (
25
26
"github.com/caddyserver/certmagic"
27
"go.uber.org/zap"
28
+ "go.uber.org/zap/zapcore"
29
30
"github.com/caddyserver/caddy/v2"
31
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -291,7 +292,9 @@ func (m MatchRemoteIP) Match(hello *tls.ClientHelloInfo) bool {
292
}
293
ipAddr, err := netip.ParseAddr(ipStr)
294
if err != nil {
294
- m.logger.Error("invalid client IP address", zap.String("ip", ipStr))
295
+ if c := m.logger.Check(zapcore.ErrorLevel, "invalid client IP address"); c != nil {
296
+ c.Write(zap.String("ip", ipStr))
297
+ }
298
return false
299
}
300
return (len(m.cidrs) == 0 || m.matches(ipAddr, m.cidrs)) &&
@@ -408,7 +411,9 @@ func (m MatchLocalIP) Match(hello *tls.ClientHelloInfo) bool {
411
}
412
ipAddr, err := netip.ParseAddr(ipStr)
413
if err != nil {
411
- m.logger.Error("invalid local IP address", zap.String("ip", ipStr))
414
+ if c := m.logger.Check(zapcore.ErrorLevel, "invalid local IP address"); c != nil {
415
+ c.Write(zap.String("ip", ipStr))
416
+ }
417
return false
418
}
419
return (len(m.cidrs) == 0 || m.matches(ipAddr, m.cidrs))
modules/caddytls/ondemand.go
+16
-9
@@ -26,6 +26,7 @@ import (
26
27
"github.com/caddyserver/certmagic"
28
"go.uber.org/zap"
29
+ "go.uber.org/zap/zapcore"
30
31
"github.com/caddyserver/caddy/v2"
32
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -156,10 +157,13 @@ func (p PermissionByHTTP) CertificateAllowed(ctx context.Context, name string) e
157
remote = chi.Conn.RemoteAddr().String()
158
}
159
159
- p.logger.Debug("asking permission endpoint",
160
- zap.String("remote", remote),
161
- zap.String("domain", name),
162
- zap.String("url", askURLString))
160
+ if c := p.logger.Check(zapcore.DebugLevel, "asking permission endpoint"); c != nil {
161
+ c.Write(
162
+ zap.String("remote", remote),
163
+ zap.String("domain", name),
164
+ zap.String("url", askURLString),
165
+ )
166
+ }
167
168
resp, err := onDemandAskClient.Get(askURLString)
169
if err != nil {
@@ -168,11 +172,14 @@ func (p PermissionByHTTP) CertificateAllowed(ctx context.Context, name string) e
172
}
173
resp.Body.Close()
174
171
- p.logger.Debug("response from permission endpoint",
172
- zap.String("remote", remote),
173
- zap.String("domain", name),
174
- zap.String("url", askURLString),
175
- zap.Int("status", resp.StatusCode))
175
+ if c := p.logger.Check(zapcore.DebugLevel, "response from permission endpoint"); c != nil {
176
+ c.Write(
177
+ zap.String("remote", remote),
178
+ zap.String("domain", name),
179
+ zap.String("url", askURLString),
180
+ zap.Int("status", resp.StatusCode),
181
+ )
182
+ }
183
184
if resp.StatusCode < 200 || resp.StatusCode > 299 {
185
return fmt.Errorf("%s: %w %s - non-2xx status code %d", name, ErrPermissionDenied, askEndpoint, resp.StatusCode)
modules/caddytls/tls.go
+19
-8
@@ -27,6 +27,7 @@ import (
27
28
"github.com/caddyserver/certmagic"
29
"go.uber.org/zap"
30
+ "go.uber.org/zap/zapcore"
31
32
"github.com/caddyserver/caddy/v2"
33
"github.com/caddyserver/caddy/v2/modules/caddyevents"
@@ -323,8 +324,9 @@ func (t *TLS) Start() error {
324
if t.Automation.OnDemand == nil || (t.Automation.OnDemand.Ask == "" && t.Automation.OnDemand.permission == nil) {
325
for _, ap := range t.Automation.Policies {
326
if ap.OnDemand && ap.isWildcardOrDefault() {
326
- t.logger.Warn("YOUR SERVER MAY BE VULNERABLE TO ABUSE: on-demand TLS is enabled, but no protections are in place",
327
- zap.String("docs", "https://caddyserver.com/docs/automatic-https#on-demand-tls"))
327
+ if c := t.logger.Check(zapcore.WarnLevel, "YOUR SERVER MAY BE VULNERABLE TO ABUSE: on-demand TLS is enabled, but no protections are in place"); c != nil {
328
+ c.Write(zap.String("docs", "https://caddyserver.com/docs/automatic-https#on-demand-tls"))
329
+ }
330
break
331
}
332
}
@@ -408,9 +410,12 @@ func (t *TLS) Cleanup() error {
410
// give the new TLS app a "kick" to manage certs that it is configured for
411
// with its own configuration instead of the one we just evicted
412
if err := nextTLSApp.Manage(reManage); err != nil {
411
- t.logger.Error("re-managing unloaded certificates with new config",
412
- zap.Strings("subjects", reManage),
413
- zap.Error(err))
413
+ if c := t.logger.Check(zapcore.ErrorLevel, "re-managing unloaded certificates with new config"); c != nil {
414
+ c.Write(
415
+ zap.Strings("subjects", reManage),
416
+ zap.Error(err),
417
+ )
418
+ }
419
}
420
} else {
421
// no more TLS app running, so delete in-memory cert cache
@@ -653,7 +658,9 @@ func (t *TLS) cleanStorageUnits() {
658
659
id, err := caddy.InstanceID()
660
if err != nil {
656
- t.logger.Warn("unable to get instance ID; storage clean stamps will be incomplete", zap.Error(err))
661
+ if c := t.logger.Check(zapcore.WarnLevel, "unable to get instance ID; storage clean stamps will be incomplete"); c != nil {
662
+ c.Write(zap.Error(err))
663
+ }
664
}
665
options := certmagic.CleanStorageOptions{
666
Logger: t.logger,
@@ -669,7 +676,9 @@ func (t *TLS) cleanStorageUnits() {
676
if err != nil {
677
// probably don't want to return early, since we should still
678
// see if any other storages can get cleaned up
672
- t.logger.Error("could not clean default/global storage", zap.Error(err))
679
+ if c := t.logger.Check(zapcore.ErrorLevel, "could not clean default/global storage"); c != nil {
680
+ c.Write(zap.Error(err))
681
+ }
682
}
683
684
// then clean each storage defined in ACME automation policies
@@ -679,7 +688,9 @@ func (t *TLS) cleanStorageUnits() {
688
continue
689
}
690
if err := certmagic.CleanStorage(t.ctx, ap.storage, options); err != nil {
682
- t.logger.Error("could not clean storage configured in automation policy", zap.Error(err))
691
+ if c := t.logger.Check(zapcore.ErrorLevel, "could not clean storage configured in automation policy"); c != nil {
692
+ c.Write(zap.Error(err))
693
+ }
694
}
695
}
696
}