From ebc278ec98bb24f2852b61fde2a9bf2e3d83818b Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Wed, 30 Dec 2020 13:44:02 -0500 Subject: metrics: allow disabling OpenMetrics negotiation (#3944) * metrics: allow disabling OpenMetrics negotiation Signed-off-by: Dave Henderson * fixup! metrics: allow disabling OpenMetrics negotiation --- modules/metrics/adminmetrics.go | 2 +- modules/metrics/metrics.go | 23 +++++++++++++++++---- modules/metrics/metrics_test.go | 45 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 modules/metrics/metrics_test.go (limited to 'modules/metrics') diff --git a/modules/metrics/adminmetrics.go b/modules/metrics/adminmetrics.go index f6a55e8..1cf398e 100644 --- a/modules/metrics/adminmetrics.go +++ b/modules/metrics/adminmetrics.go @@ -41,7 +41,7 @@ func (AdminMetrics) CaddyModule() caddy.ModuleInfo { // Routes returns a route for the /metrics endpoint. func (m *AdminMetrics) Routes() []caddy.AdminRoute { - metricsHandler := createMetricsHandler(nil) + metricsHandler := createMetricsHandler(nil, false) h := caddy.AdminHandlerFunc(func(w http.ResponseWriter, r *http.Request) error { metricsHandler.ServeHTTP(w, r) return nil diff --git a/modules/metrics/metrics.go b/modules/metrics/metrics.go index eff364e..e6d4345 100644 --- a/modules/metrics/metrics.go +++ b/modules/metrics/metrics.go @@ -38,6 +38,10 @@ func init() { // unlike AdminMetrics. type Metrics struct { metricsHandler http.Handler + + // Disable OpenMetrics negotiation, enabled by default. May be necessary if + // the produced metrics cannot be parsed by the service scraping metrics. + DisableOpenMetrics bool `json:"disable_openmetrics,omitempty"` } // CaddyModule returns the Caddy module information. @@ -59,7 +63,7 @@ func (l *zapLogger) Println(v ...interface{}) { // Provision sets up m. func (m *Metrics) Provision(ctx caddy.Context) error { log := ctx.Logger(m) - m.metricsHandler = createMetricsHandler(&zapLogger{log}) + m.metricsHandler = createMetricsHandler(&zapLogger{log}, !m.DisableOpenMetrics) return nil } @@ -71,7 +75,9 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) // UnmarshalCaddyfile sets up the handler from Caddyfile tokens. Syntax: // -// metrics +// metrics [] { +// disable_openmetrics +// } // func (m *Metrics) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { for d.Next() { @@ -79,6 +85,15 @@ func (m *Metrics) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { if len(args) > 0 { return d.ArgErr() } + + for d.NextBlock(0) { + switch d.Val() { + case "disable_openmetrics": + m.DisableOpenMetrics = true + default: + return d.Errf("unrecognized subdirective %q", d.Val()) + } + } } return nil } @@ -95,7 +110,7 @@ var ( _ caddyfile.Unmarshaler = (*Metrics)(nil) ) -func createMetricsHandler(logger promhttp.Logger) http.Handler { +func createMetricsHandler(logger promhttp.Logger, enableOpenMetrics bool) http.Handler { return promhttp.InstrumentMetricHandler(prometheus.DefaultRegisterer, promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{ // will only log errors if logger is non-nil @@ -103,7 +118,7 @@ func createMetricsHandler(logger promhttp.Logger) http.Handler { // Allow OpenMetrics format to be negotiated - largely compatible, // except quantile/le label values always have a decimal. - EnableOpenMetrics: true, + EnableOpenMetrics: enableOpenMetrics, }), ) } diff --git a/modules/metrics/metrics_test.go b/modules/metrics/metrics_test.go new file mode 100644 index 0000000..d5bdf50 --- /dev/null +++ b/modules/metrics/metrics_test.go @@ -0,0 +1,45 @@ +package metrics + +import ( + "testing" + + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" +) + +func TestMetricsUnmarshalCaddyfile(t *testing.T) { + m := &Metrics{} + d := caddyfile.NewTestDispenser(`metrics bogus`) + err := m.UnmarshalCaddyfile(d) + if err == nil { + t.Errorf("expected error") + } + + m = &Metrics{} + d = caddyfile.NewTestDispenser(`metrics`) + err = m.UnmarshalCaddyfile(d) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if m.DisableOpenMetrics != false { + t.Errorf("DisableOpenMetrics should've been false: %v", m.DisableOpenMetrics) + } + + m = &Metrics{} + d = caddyfile.NewTestDispenser(`metrics { disable_openmetrics }`) + err = m.UnmarshalCaddyfile(d) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if m.DisableOpenMetrics != true { + t.Errorf("DisableOpenMetrics should've been true: %v", m.DisableOpenMetrics) + } + + m = &Metrics{} + d = caddyfile.NewTestDispenser(`metrics { bogus }`) + err = m.UnmarshalCaddyfile(d) + if err == nil { + t.Errorf("expected error: %v", err) + } +} -- cgit v1.2.3