Skip to content

Commit

Permalink
metrics: move metrics up, outside servers
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
mohammed90 committed Oct 5, 2024
1 parent 2ae58ac commit d5c6e6c
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 11 deletions.
14 changes: 14 additions & 0 deletions caddyconfig/httpcaddyfile/httptype.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package httpcaddyfile

import (
"cmp"
"encoding/json"
"fmt"
"net"
Expand Down Expand Up @@ -186,12 +187,25 @@ func (st ServerType) Setup(
return nil, warnings, err
}

// hoist the metrics config from per-server to global
metrics, _ := options["metrics"].(*caddyhttp.Metrics)
for _, s := range servers {
if s.Metrics != nil {
metrics = cmp.Or[*caddyhttp.Metrics](metrics, &caddyhttp.Metrics{})
metrics = &caddyhttp.Metrics{
PerHost: metrics.PerHost || s.Metrics.PerHost,
}
s.Metrics = nil // we don't need it anymore
}
}

// now that each server is configured, make the HTTP app
httpApp := caddyhttp.App{
HTTPPort: tryInt(options["http_port"], &warnings),
HTTPSPort: tryInt(options["https_port"], &warnings),
GracePeriod: tryDuration(options["grace_period"], &warnings),
ShutdownDelay: tryDuration(options["shutdown_delay"], &warnings),
Metrics: metrics,
Servers: servers,
}

Expand Down
20 changes: 20 additions & 0 deletions caddyconfig/httpcaddyfile/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"github.com/caddyserver/caddy/v2/modules/caddytls"
)

Expand Down Expand Up @@ -53,6 +54,7 @@ func init() {
RegisterGlobalOption("local_certs", parseOptTrue)
RegisterGlobalOption("key_type", parseOptSingleString)
RegisterGlobalOption("auto_https", parseOptAutoHTTPS)
RegisterGlobalOption("metrics", parseMetricsOptions)
RegisterGlobalOption("servers", parseServerOptions)
RegisterGlobalOption("ocsp_stapling", parseOCSPStaplingOptions)
RegisterGlobalOption("cert_lifetime", parseOptDuration)
Expand Down Expand Up @@ -472,6 +474,24 @@ func parseOptAutoHTTPS(d *caddyfile.Dispenser, _ any) (any, error) {
return val, nil
}

func unmarshalCaddyfileMetricsOptions(d *caddyfile.Dispenser) (any, error) {
d.Next() // consume option name
metrics := new(caddyhttp.Metrics)
for d.NextBlock(0) {
switch d.Val() {
case "per_host":
metrics.PerHost = true
default:
return nil, d.Errf("unrecognized servers option '%s'", d.Val())
}
}
return metrics, nil
}

func parseMetricsOptions(d *caddyfile.Dispenser, _ any) (any, error) {
return unmarshalCaddyfileMetricsOptions(d)
}

func parseServerOptions(d *caddyfile.Dispenser, _ any) (any, error) {
return unmarshalCaddyfileServerOptions(d)
}
Expand Down
1 change: 1 addition & 0 deletions caddyconfig/httpcaddyfile/serveroptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
}

case "metrics":
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.")
serverOpts.Metrics = new(caddyhttp.Metrics)
for nesting := d.Nesting(); d.NextBlock(nesting); {
switch d.Val() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
metrics
servers :80 {
metrics {
per_host
}
}
}
:80 {
respond "Hello"
}

----------
{
"apps": {
"http": {
"servers": {
"srv0": {
"listen": [
":80"
],
"routes": [
{
"handle": [
{
"body": "Hello",
"handler": "static_response"
}
]
}
]
}
},
"metrics": {
"per_host": true
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
}
]
}
],
"metrics": {
"per_host": true
}
]
}
},
"metrics": {
"per_host": true
}
}
}
Expand Down
27 changes: 20 additions & 7 deletions modules/caddyhttp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package caddyhttp

import (
"cmp"
"context"
"crypto/tls"
"fmt"
Expand Down Expand Up @@ -142,6 +143,10 @@ type App struct {
// affect functionality.
Servers map[string]*Server `json:"servers,omitempty"`

// If set, metrics observations will be enabled.
// This setting is EXPERIMENTAL and subject to change.
Metrics *Metrics `json:"metrics,omitempty"`

ctx caddy.Context
logger *zap.Logger
tlsApp *caddytls.TLS
Expand Down Expand Up @@ -184,6 +189,10 @@ func (app *App) Provision(ctx caddy.Context) error {
return err
}

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

if srv.Metrics != nil {
srv.logger.Warn("per-server 'metrics' is deprecated; use 'metrics' in the root 'http' app instead")
app.Metrics = cmp.Or[*Metrics](app.Metrics, &Metrics{
init: sync.Once{},
httpMetrics: &httpMetrics{},
})
app.Metrics.PerHost = app.Metrics.PerHost || srv.Metrics.PerHost
}

// only enable access logs if configured
if srv.Logs != nil {
srv.accessLogger = app.logger.Named("log.access")
Expand Down Expand Up @@ -342,16 +360,11 @@ func (app *App) Provision(ctx caddy.Context) error {
srv.listenerWrappers = append([]caddy.ListenerWrapper{new(tlsPlaceholderWrapper)}, srv.listenerWrappers...)
}
}

// pre-compile the primary handler chain, and be sure to wrap it in our
// route handler so that important security checks are done, etc.
primaryRoute := emptyHandler
if srv.Routes != nil {
if srv.Metrics != nil {
srv.Metrics.init = sync.Once{}
srv.Metrics.httpMetrics = &httpMetrics{}
}
err := srv.Routes.ProvisionHandlers(ctx, srv.Metrics)
err := srv.Routes.ProvisionHandlers(ctx, app.Metrics)
if err != nil {
return fmt.Errorf("server %s: setting up route handlers: %v", srvName, err)
}
Expand All @@ -370,7 +383,7 @@ func (app *App) Provision(ctx caddy.Context) error {

// provision the named routes (they get compiled at runtime)
for name, route := range srv.NamedRoutes {
err := route.Provision(ctx, srv.Metrics)
err := route.Provision(ctx, app.Metrics)
if err != nil {
return fmt.Errorf("server %s: setting up named route '%s' handlers: %v", name, srvName, err)
}
Expand Down
1 change: 1 addition & 0 deletions modules/caddyhttp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ type Server struct {

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

name string
Expand Down

0 comments on commit d5c6e6c

Please sign in to comment.