Skip to content

Commit 388c7e8

Browse files
authored
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 <[email protected]> * normalize domain name --------- Signed-off-by: Mohammed Al Sahaf <[email protected]>
1 parent c6f2979 commit 388c7e8

File tree

8 files changed

+102
-13
lines changed

8 files changed

+102
-13
lines changed

caddyconfig/httpcaddyfile/httptype.go

+14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package httpcaddyfile
1616

1717
import (
18+
"cmp"
1819
"encoding/json"
1920
"fmt"
2021
"net"
@@ -186,12 +187,25 @@ func (st ServerType) Setup(
186187
return nil, warnings, err
187188
}
188189

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+
189202
// now that each server is configured, make the HTTP app
190203
httpApp := caddyhttp.App{
191204
HTTPPort: tryInt(options["http_port"], &warnings),
192205
HTTPSPort: tryInt(options["https_port"], &warnings),
193206
GracePeriod: tryDuration(options["grace_period"], &warnings),
194207
ShutdownDelay: tryDuration(options["shutdown_delay"], &warnings),
208+
Metrics: metrics,
195209
Servers: servers,
196210
}
197211

caddyconfig/httpcaddyfile/options.go

+20
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/caddyserver/caddy/v2"
2525
"github.com/caddyserver/caddy/v2/caddyconfig"
2626
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
27+
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
2728
"github.com/caddyserver/caddy/v2/modules/caddytls"
2829
)
2930

@@ -53,6 +54,7 @@ func init() {
5354
RegisterGlobalOption("local_certs", parseOptTrue)
5455
RegisterGlobalOption("key_type", parseOptSingleString)
5556
RegisterGlobalOption("auto_https", parseOptAutoHTTPS)
57+
RegisterGlobalOption("metrics", parseMetricsOptions)
5658
RegisterGlobalOption("servers", parseServerOptions)
5759
RegisterGlobalOption("ocsp_stapling", parseOCSPStaplingOptions)
5860
RegisterGlobalOption("cert_lifetime", parseOptDuration)
@@ -446,6 +448,24 @@ func parseOptAutoHTTPS(d *caddyfile.Dispenser, _ any) (any, error) {
446448
return val, nil
447449
}
448450

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+
449469
func parseServerOptions(d *caddyfile.Dispenser, _ any) (any, error) {
450470
return unmarshalCaddyfileServerOptions(d)
451471
}

caddyconfig/httpcaddyfile/serveroptions.go

+1
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
240240
}
241241

242242
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.")
243244
serverOpts.Metrics = new(caddyhttp.Metrics)
244245
for nesting := d.Nesting(); d.NextBlock(nesting); {
245246
switch d.Val() {
Original file line numberDiff line numberDiff line change
@@ -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+
}

caddytest/integration/caddyfile_adapt/metrics_perhost.caddyfiletest

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
}
2727
]
2828
}
29-
],
30-
"metrics": {
31-
"per_host": true
32-
}
29+
]
3330
}
31+
},
32+
"metrics": {
33+
"per_host": true
3434
}
3535
}
3636
}

modules/caddyhttp/app.go

+20-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package caddyhttp
1616

1717
import (
18+
"cmp"
1819
"context"
1920
"crypto/tls"
2021
"fmt"
@@ -142,6 +143,10 @@ type App struct {
142143
// affect functionality.
143144
Servers map[string]*Server `json:"servers,omitempty"`
144145

146+
// If set, metrics observations will be enabled.
147+
// This setting is EXPERIMENTAL and subject to change.
148+
Metrics *Metrics `json:"metrics,omitempty"`
149+
145150
ctx caddy.Context
146151
logger *zap.Logger
147152
tlsApp *caddytls.TLS
@@ -184,6 +189,10 @@ func (app *App) Provision(ctx caddy.Context) error {
184189
return err
185190
}
186191

192+
if app.Metrics != nil {
193+
app.Metrics.init = sync.Once{}
194+
app.Metrics.httpMetrics = &httpMetrics{}
195+
}
187196
// prepare each server
188197
oldContext := ctx.Context
189198
for srvName, srv := range app.Servers {
@@ -196,6 +205,15 @@ func (app *App) Provision(ctx caddy.Context) error {
196205
srv.errorLogger = app.logger.Named("log.error")
197206
srv.shutdownAtMu = new(sync.RWMutex)
198207

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+
199217
// only enable access logs if configured
200218
if srv.Logs != nil {
201219
srv.accessLogger = app.logger.Named("log.access")
@@ -342,16 +360,11 @@ func (app *App) Provision(ctx caddy.Context) error {
342360
srv.listenerWrappers = append([]caddy.ListenerWrapper{new(tlsPlaceholderWrapper)}, srv.listenerWrappers...)
343361
}
344362
}
345-
346363
// pre-compile the primary handler chain, and be sure to wrap it in our
347364
// route handler so that important security checks are done, etc.
348365
primaryRoute := emptyHandler
349366
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)
355368
if err != nil {
356369
return fmt.Errorf("server %s: setting up route handlers: %v", srvName, err)
357370
}
@@ -370,7 +383,7 @@ func (app *App) Provision(ctx caddy.Context) error {
370383

371384
// provision the named routes (they get compiled at runtime)
372385
for name, route := range srv.NamedRoutes {
373-
err := route.Provision(ctx, srv.Metrics)
386+
err := route.Provision(ctx, app.Metrics)
374387
if err != nil {
375388
return fmt.Errorf("server %s: setting up named route '%s' handlers: %v", name, srvName, err)
376389
}

modules/caddyhttp/metrics.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"net/http"
7+
"strings"
78
"sync"
89
"time"
910

@@ -133,8 +134,8 @@ func (h *metricsInstrumentedHandler) ServeHTTP(w http.ResponseWriter, r *http.Re
133134
statusLabels := prometheus.Labels{"server": server, "handler": h.handler, "method": method, "code": ""}
134135

135136
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)
138139
}
139140

140141
inFlight := h.metrics.httpMetrics.requestInFlight.With(labels)

modules/caddyhttp/server.go

+1
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ type Server struct {
226226

227227
// If set, metrics observations will be enabled.
228228
// This setting is EXPERIMENTAL and subject to change.
229+
// DEPRECATED: Use the app-level `metrics` field.
229230
Metrics *Metrics `json:"metrics,omitempty"`
230231

231232
name string

0 commit comments

Comments
 (0)