@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 126 lines 3.59 KB
Raw
1 // Copyright 2020 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package metrics
16
17 import (
18 "errors"
19 "net/http"
20
21 "github.com/prometheus/client_golang/prometheus"
22 "github.com/prometheus/client_golang/prometheus/promhttp"
23 "go.uber.org/zap"
24
25 "github.com/caddyserver/caddy/v2"
26 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
27 "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
28 "github.com/caddyserver/caddy/v2/modules/caddyhttp"
29 )
30
31 func init() {
32 caddy.RegisterModule(Metrics{})
33 httpcaddyfile.RegisterHandlerDirective("metrics", parseCaddyfile)
34 }
35
36 // Metrics is a module that serves a /metrics endpoint so that any gathered
37 // metrics can be exposed for scraping. This module is configurable by end-users
38 // unlike AdminMetrics.
39 type Metrics struct {
40 metricsHandler http.Handler
41
42 // Disable OpenMetrics negotiation, enabled by default. May be necessary if
43 // the produced metrics cannot be parsed by the service scraping metrics.
44 DisableOpenMetrics bool `json:"disable_openmetrics,omitempty"`
45 }
46
47 // CaddyModule returns the Caddy module information.
48 func (Metrics) CaddyModule() caddy.ModuleInfo {
49 return caddy.ModuleInfo{
50 ID: "http.handlers.metrics",
51 New: func() caddy.Module { return new(Metrics) },
52 }
53 }
54
55 type zapLogger struct {
56 zl *zap.Logger
57 }
58
59 func (l *zapLogger) Println(v ...any) {
60 l.zl.Sugar().Error(v...)
61 }
62
63 // Provision sets up m.
64 func (m *Metrics) Provision(ctx caddy.Context) error {
65 log := ctx.Logger()
66 registry := ctx.GetMetricsRegistry()
67 if registry == nil {
68 return errors.New("no metrics registry found")
69 }
70 m.metricsHandler = createMetricsHandler(&zapLogger{log}, !m.DisableOpenMetrics, registry)
71 return nil
72 }
73
74 func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
75 var m Metrics
76 err := m.UnmarshalCaddyfile(h.Dispenser)
77 return m, err
78 }
79
80 // UnmarshalCaddyfile sets up the handler from Caddyfile tokens. Syntax:
81 //
82 // metrics [<matcher>] {
83 // disable_openmetrics
84 // }
85 func (m *Metrics) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
86 d.Next() // consume directive name
87 args := d.RemainingArgs()
88 if len(args) > 0 {
89 return d.ArgErr()
90 }
91
92 for d.NextBlock(0) {
93 switch d.Val() {
94 case "disable_openmetrics":
95 m.DisableOpenMetrics = true
96 default:
97 return d.Errf("unrecognized subdirective %q", d.Val())
98 }
99 }
100 return nil
101 }
102
103 func (m Metrics) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
104 m.metricsHandler.ServeHTTP(w, r)
105 return nil
106 }
107
108 // Interface guards
109 var (
110 _ caddy.Provisioner = (*Metrics)(nil)
111 _ caddyhttp.MiddlewareHandler = (*Metrics)(nil)
112 _ caddyfile.Unmarshaler = (*Metrics)(nil)
113 )
114
115 func createMetricsHandler(logger promhttp.Logger, enableOpenMetrics bool, registry *prometheus.Registry) http.Handler {
116 return promhttp.InstrumentMetricHandler(registry,
117 promhttp.HandlerFor(registry, promhttp.HandlerOpts{
118 // will only log errors if logger is non-nil
119 ErrorLog: logger,
120
121 // Allow OpenMetrics format to be negotiated - largely compatible,
122 // except quantile/le label values always have a decimal.
123 EnableOpenMetrics: enableOpenMetrics,
124 }),
125 )
126 }