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, 12:00 UTC
caddyhttp: Trace individual middleware handlers (#6313)
* caddyhttp: Trace individual middleware handlers * Fix typo
Matt Holt committed
May 18, 2024 at 14:48 UTC
9ba999141b5ca5adaf45893992f4889629f77a9d
5 files changed
+41
-35
caddyconfig/httpcaddyfile/serveroptions.go
+13
-33
@@ -50,6 +50,7 @@ type serverOptions struct {
50
ClientIPHeaders []string
51
ShouldLogCredentials bool
52
Metrics *caddyhttp.Metrics
53
+ Trace bool // TODO: EXPERIMENTAL
54
}
55
56
func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
@@ -246,39 +247,11 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
247
}
248
serverOpts.Metrics = new(caddyhttp.Metrics)
249
249
- // TODO: DEPRECATED. (August 2022)
250
- case "protocol":
251
- caddy.Log().Named("caddyfile").Warn("DEPRECATED: protocol sub-option will be removed soon")
252
-
253
- for nesting := d.Nesting(); d.NextBlock(nesting); {
254
- switch d.Val() {
255
- case "allow_h2c":
256
- caddy.Log().Named("caddyfile").Warn("DEPRECATED: allow_h2c will be removed soon; use protocols option instead")
257
-
258
- if d.NextArg() {
259
- return nil, d.ArgErr()
260
- }
261
- if sliceContains(serverOpts.Protocols, "h2c") {
262
- return nil, d.Errf("protocol h2c already specified")
263
- }
264
- serverOpts.Protocols = append(serverOpts.Protocols, "h2c")
265
-
266
- case "strict_sni_host":
267
- caddy.Log().Named("caddyfile").Warn("DEPRECATED: protocol > strict_sni_host in this position will be removed soon; move up to the servers block instead")
268
-
269
- if d.NextArg() && d.Val() != "insecure_off" && d.Val() != "on" {
270
- return nil, d.Errf("strict_sni_host only supports 'on' or 'insecure_off', got '%s'", d.Val())
271
- }
272
- boolVal := true
273
- if d.Val() == "insecure_off" {
274
- boolVal = false
275
- }
276
- serverOpts.StrictSNIHost = &boolVal
277
-
278
- default:
279
- return nil, d.Errf("unrecognized protocol option '%s'", d.Val())
280
- }
250
+ case "trace":
251
+ if d.NextArg() {
252
+ return nil, d.ArgErr()
253
}
254
+ serverOpts.Trace = true
255
256
default:
257
return nil, d.Errf("unrecognized servers option '%s'", d.Val())
@@ -351,10 +324,17 @@ func applyServerOptions(
324
server.Metrics = opts.Metrics
325
if opts.ShouldLogCredentials {
326
if server.Logs == nil {
354
- server.Logs = &caddyhttp.ServerLogConfig{}
327
+ server.Logs = new(caddyhttp.ServerLogConfig)
328
}
329
server.Logs.ShouldLogCredentials = opts.ShouldLogCredentials
330
}
331
+ if opts.Trace {
332
+ // TODO: THIS IS EXPERIMENTAL (MAY 2024)
333
+ if server.Logs == nil {
334
+ server.Logs = new(caddyhttp.ServerLogConfig)
335
+ }
336
+ server.Logs.Trace = opts.Trace
337
+ }
338
339
if opts.Name != "" {
340
nameReplacements[key] = opts.Name
modules/caddyhttp/app.go
+3
@@ -198,6 +198,9 @@ func (app *App) Provision(ctx caddy.Context) error {
198
// only enable access logs if configured
199
if srv.Logs != nil {
200
srv.accessLogger = app.logger.Named("log.access")
201
+ if srv.Logs.Trace {
202
+ srv.traceLogger = app.logger.Named("log.trace")
203
+ }
204
}
205
206
// the Go standard library does not let us serve only HTTP/2 using
modules/caddyhttp/logging.go
+11
@@ -65,6 +65,17 @@ type ServerLogConfig struct {
65
// and this includes some request and response headers, i.e `Cookie`,
66
// `Set-Cookie`, `Authorization`, and `Proxy-Authorization`.
67
ShouldLogCredentials bool `json:"should_log_credentials,omitempty"`
68
+
69
+ // Log each individual handler that is invoked.
70
+ // Requires that the log emit at DEBUG level.
71
+ //
72
+ // NOTE: This may log the configuration of your
73
+ // HTTP handler modules; do not enable this in
74
+ // insecure contexts when there is sensitive
75
+ // data in the configuration.
76
+ //
77
+ // EXPERIMENTAL: Subject to change or removal.
78
+ Trace bool `json:"trace,omitempty"`
79
}
80
81
// wrapLogger wraps logger in one or more logger named
modules/caddyhttp/routes.go
+4
-2
@@ -326,8 +326,10 @@ func wrapMiddleware(_ caddy.Context, mh MiddlewareHandler, metrics *Metrics) Mid
326
nextCopy := next
327
328
return HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
329
- // TODO: This is where request tracing could be implemented
330
- // TODO: see what the std lib gives us in terms of stack tracing too
329
+ // EXPERIMENTAL: Trace each module that gets invoked
330
+ if server, ok := r.Context().Value(ServerCtxKey).(*Server); ok && server != nil {
331
+ server.logTrace(handlerToUse)
332
+ }
333
return handlerToUse.ServeHTTP(w, r, nextCopy)
334
})
335
}
modules/caddyhttp/server.go
+10
@@ -234,6 +234,7 @@ type Server struct {
234
logger *zap.Logger
235
accessLogger *zap.Logger
236
errorLogger *zap.Logger
237
+ traceLogger *zap.Logger
238
ctx caddy.Context
239
240
server *http.Server
@@ -738,6 +739,15 @@ func (s *Server) shouldLogRequest(r *http.Request) bool {
739
return !s.Logs.SkipUnmappedHosts
740
}
741
742
+// logTrace will log that this middleware handler is being invoked.
743
+// It emits at DEBUG level.
744
+func (s *Server) logTrace(mh MiddlewareHandler) {
745
+ if s.Logs == nil || !s.Logs.Trace {
746
+ return
747
+ }
748
+ s.traceLogger.Debug(caddy.GetModuleName(mh), zap.Any("module", mh))
749
+}
750
+
751
// logRequest logs the request to access logs, unless skipped.
752
func (s *Server) logRequest(
753
accLog *zap.Logger, r *http.Request, wrec ResponseRecorder, duration *time.Duration,