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, 07:00 UTC
metrics: move `metrics` up, outside `servers` (#6606)
* metrics: move `metrics` up, outside `servers` This change moves the metrics configuration from per-server level to a single config knob within the `http` app. Enabling `metrics` in any of the configured servers inside `http` enables metrics for all servers. Fix #6604 Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com> * normalize domain name --------- Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>
Mohammed Al Sahaf committed
Oct 18, 2024 at 18:54 UTC
388c7e898c6cbcddd2c59e8a902238a0b4f06857
8 files changed
+102
-13
caddyconfig/httpcaddyfile/httptype.go
+14
@@ -15,6 +15,7 @@
15
package httpcaddyfile
16
17
import (
18
+ "cmp"
19
"encoding/json"
20
"fmt"
21
"net"
@@ -186,12 +187,25 @@ func (st ServerType) Setup(
187
return nil, warnings, err
188
}
189
190
+ // hoist the metrics config from per-server to global
191
+ metrics, _ := options["metrics"].(*caddyhttp.Metrics)
192
+ for _, s := range servers {
193
+ if s.Metrics != nil {
194
+ metrics = cmp.Or[*caddyhttp.Metrics](metrics, &caddyhttp.Metrics{})
195
+ metrics = &caddyhttp.Metrics{
196
+ PerHost: metrics.PerHost || s.Metrics.PerHost,
197
+ }
198
+ s.Metrics = nil // we don't need it anymore
199
+ }
200
+ }
201
+
202
// now that each server is configured, make the HTTP app
203
httpApp := caddyhttp.App{
204
HTTPPort: tryInt(options["http_port"], &warnings),
205
HTTPSPort: tryInt(options["https_port"], &warnings),
206
GracePeriod: tryDuration(options["grace_period"], &warnings),
207
ShutdownDelay: tryDuration(options["shutdown_delay"], &warnings),
208
+ Metrics: metrics,
209
Servers: servers,
210
}
211
caddyconfig/httpcaddyfile/options.go
+20
@@ -24,6 +24,7 @@ import (
24
"github.com/caddyserver/caddy/v2"
25
"github.com/caddyserver/caddy/v2/caddyconfig"
26
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
27
+ "github.com/caddyserver/caddy/v2/modules/caddyhttp"
28
"github.com/caddyserver/caddy/v2/modules/caddytls"
29
)
30
@@ -53,6 +54,7 @@ func init() {
54
RegisterGlobalOption("local_certs", parseOptTrue)
55
RegisterGlobalOption("key_type", parseOptSingleString)
56
RegisterGlobalOption("auto_https", parseOptAutoHTTPS)
57
+ RegisterGlobalOption("metrics", parseMetricsOptions)
58
RegisterGlobalOption("servers", parseServerOptions)
59
RegisterGlobalOption("ocsp_stapling", parseOCSPStaplingOptions)
60
RegisterGlobalOption("cert_lifetime", parseOptDuration)
@@ -446,6 +448,24 @@ func parseOptAutoHTTPS(d *caddyfile.Dispenser, _ any) (any, error) {
448
return val, nil
449
}
450
451
+func unmarshalCaddyfileMetricsOptions(d *caddyfile.Dispenser) (any, error) {
452
+ d.Next() // consume option name
453
+ metrics := new(caddyhttp.Metrics)
454
+ for d.NextBlock(0) {
455
+ switch d.Val() {
456
+ case "per_host":
457
+ metrics.PerHost = true
458
+ default:
459
+ return nil, d.Errf("unrecognized servers option '%s'", d.Val())
460
+ }
461
+ }
462
+ return metrics, nil
463
+}
464
+
465
+func parseMetricsOptions(d *caddyfile.Dispenser, _ any) (any, error) {
466
+ return unmarshalCaddyfileMetricsOptions(d)
467
+}
468
+
469
func parseServerOptions(d *caddyfile.Dispenser, _ any) (any, error) {
470
return unmarshalCaddyfileServerOptions(d)
471
}
caddyconfig/httpcaddyfile/serveroptions.go
+1
@@ -240,6 +240,7 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
240
}
241
242
case "metrics":
243
+ caddy.Log().Warn("The nested 'metrics' option inside `servers` is deprecated and will be removed in the next major version. Use the global 'metrics' option instead.")
244
serverOpts.Metrics = new(caddyhttp.Metrics)
245
for nesting := d.Nesting(); d.NextBlock(nesting); {
246
switch d.Val() {
caddytest/integration/caddyfile_adapt/metrics_merge_options.caddyfiletest
new
+39
@@ -0,0 +1,39 @@
1
+{
2
+ metrics
3
+ servers :80 {
4
+ metrics {
5
+ per_host
6
+ }
7
+ }
8
+}
9
+:80 {
10
+ respond "Hello"
11
+}
12
+
13
+----------
14
+{
15
+ "apps": {
16
+ "http": {
17
+ "servers": {
18
+ "srv0": {
19
+ "listen": [
20
+ ":80"
21
+ ],
22
+ "routes": [
23
+ {
24
+ "handle": [
25
+ {
26
+ "body": "Hello",
27
+ "handler": "static_response"
28
+ }
29
+ ]
30
+ }
31
+ ]
32
+ }
33
+ },
34
+ "metrics": {
35
+ "per_host": true
36
+ }
37
+ }
38
+ }
39
+}
\ No newline at end of file
caddytest/integration/caddyfile_adapt/metrics_perhost.caddyfiletest
+4
-4
@@ -26,11 +26,11 @@
26
}
27
]
28
}
29
- ],
30
- "metrics": {
31
- "per_host": true
32
- }
29
+ ]
30
}
31
+ },
32
+ "metrics": {
33
+ "per_host": true
34
}
35
}
36
}
modules/caddyhttp/app.go
+20
-7
@@ -15,6 +15,7 @@
15
package caddyhttp
16
17
import (
18
+ "cmp"
19
"context"
20
"crypto/tls"
21
"fmt"
@@ -142,6 +143,10 @@ type App struct {
143
// affect functionality.
144
Servers map[string]*Server `json:"servers,omitempty"`
145
146
+ // If set, metrics observations will be enabled.
147
+ // This setting is EXPERIMENTAL and subject to change.
148
+ Metrics *Metrics `json:"metrics,omitempty"`
149
+
150
ctx caddy.Context
151
logger *zap.Logger
152
tlsApp *caddytls.TLS
@@ -184,6 +189,10 @@ func (app *App) Provision(ctx caddy.Context) error {
189
return err
190
}
191
192
+ if app.Metrics != nil {
193
+ app.Metrics.init = sync.Once{}
194
+ app.Metrics.httpMetrics = &httpMetrics{}
195
+ }
196
// prepare each server
197
oldContext := ctx.Context
198
for srvName, srv := range app.Servers {
@@ -196,6 +205,15 @@ func (app *App) Provision(ctx caddy.Context) error {
205
srv.errorLogger = app.logger.Named("log.error")
206
srv.shutdownAtMu = new(sync.RWMutex)
207
208
+ if srv.Metrics != nil {
209
+ srv.logger.Warn("per-server 'metrics' is deprecated; use 'metrics' in the root 'http' app instead")
210
+ app.Metrics = cmp.Or[*Metrics](app.Metrics, &Metrics{
211
+ init: sync.Once{},
212
+ httpMetrics: &httpMetrics{},
213
+ })
214
+ app.Metrics.PerHost = app.Metrics.PerHost || srv.Metrics.PerHost
215
+ }
216
+
217
// only enable access logs if configured
218
if srv.Logs != nil {
219
srv.accessLogger = app.logger.Named("log.access")
@@ -342,16 +360,11 @@ func (app *App) Provision(ctx caddy.Context) error {
360
srv.listenerWrappers = append([]caddy.ListenerWrapper{new(tlsPlaceholderWrapper)}, srv.listenerWrappers...)
361
}
362
}
345
-
363
// pre-compile the primary handler chain, and be sure to wrap it in our
364
// route handler so that important security checks are done, etc.
365
primaryRoute := emptyHandler
366
if srv.Routes != nil {
350
- if srv.Metrics != nil {
351
- srv.Metrics.init = sync.Once{}
352
- srv.Metrics.httpMetrics = &httpMetrics{}
353
- }
354
- err := srv.Routes.ProvisionHandlers(ctx, srv.Metrics)
367
+ err := srv.Routes.ProvisionHandlers(ctx, app.Metrics)
368
if err != nil {
369
return fmt.Errorf("server %s: setting up route handlers: %v", srvName, err)
370
}
@@ -370,7 +383,7 @@ func (app *App) Provision(ctx caddy.Context) error {
383
384
// provision the named routes (they get compiled at runtime)
385
for name, route := range srv.NamedRoutes {
373
- err := route.Provision(ctx, srv.Metrics)
386
+ err := route.Provision(ctx, app.Metrics)
387
if err != nil {
388
return fmt.Errorf("server %s: setting up named route '%s' handlers: %v", name, srvName, err)
389
}
modules/caddyhttp/metrics.go
+3
-2
@@ -4,6 +4,7 @@ import (
4
"context"
5
"errors"
6
"net/http"
7
+ "strings"
8
"sync"
9
"time"
10
@@ -133,8 +134,8 @@ func (h *metricsInstrumentedHandler) ServeHTTP(w http.ResponseWriter, r *http.Re
134
statusLabels := prometheus.Labels{"server": server, "handler": h.handler, "method": method, "code": ""}
135
136
if h.metrics.PerHost {
136
- labels["host"] = r.Host
137
- statusLabels["host"] = r.Host
137
+ labels["host"] = strings.ToLower(r.Host)
138
+ statusLabels["host"] = strings.ToLower(r.Host)
139
}
140
141
inFlight := h.metrics.httpMetrics.requestInFlight.With(labels)
modules/caddyhttp/server.go
+1
@@ -226,6 +226,7 @@ type Server struct {
226
227
// If set, metrics observations will be enabled.
228
// This setting is EXPERIMENTAL and subject to change.
229
+ // DEPRECATED: Use the app-level `metrics` field.
230
Metrics *Metrics `json:"metrics,omitempty"`
231
232
name string