Add router metrics

This commit is contained in:
Jorge Arco 2021-04-30 10:22:04 +02:00 committed by GitHub
parent dc8d5ef744
commit 080cf98e51
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 756 additions and 217 deletions

View file

@ -253,7 +253,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
accessLog := setupAccessLog(staticConfiguration.AccessLog) accessLog := setupAccessLog(staticConfiguration.AccessLog)
chainBuilder := middleware.NewChainBuilder(*staticConfiguration, metricsRegistry, accessLog) chainBuilder := middleware.NewChainBuilder(*staticConfiguration, metricsRegistry, accessLog)
routerFactory := server.NewRouterFactory(*staticConfiguration, managerFactory, tlsManager, chainBuilder, pluginBuilder) routerFactory := server.NewRouterFactory(*staticConfiguration, managerFactory, tlsManager, chainBuilder, pluginBuilder, metricsRegistry)
// Watcher // Watcher

View file

@ -59,6 +59,27 @@ metrics:
```bash tab="CLI" ```bash tab="CLI"
--metrics.datadog.addEntryPointsLabels=true --metrics.datadog.addEntryPointsLabels=true
``` ```
#### `AddRoutersLabels`
_Optional, Default=false_
Enable metrics on routers.
```toml tab="File (TOML)"
[metrics]
[metrics.datadog]
addRoutersLabels = true
```
```yaml tab="File (YAML)"
metrics:
datadog:
addRoutersLabels: true
```
```bash tab="CLI"
--metrics.datadog.addrouterslabels=true
```
#### `addServicesLabels` #### `addServicesLabels`

View file

@ -170,6 +170,28 @@ metrics:
--metrics.influxdb.addEntryPointsLabels=true --metrics.influxdb.addEntryPointsLabels=true
``` ```
#### `AddRoutersLabels`
_Optional, Default=false_
Enable metrics on routers.
```toml tab="File (TOML)"
[metrics]
[metrics.influxDB]
addRoutersLabels = true
```
```yaml tab="File (YAML)"
metrics:
influxDB:
addRoutersLabels: true
```
```bash tab="CLI"
--metrics.influxdb.addrouterslabels=true
```
#### `addServicesLabels` #### `addServicesLabels`
_Optional, Default=true_ _Optional, Default=true_

View file

@ -64,6 +64,28 @@ metrics:
--metrics.prometheus.addEntryPointsLabels=true --metrics.prometheus.addEntryPointsLabels=true
``` ```
#### `AddRoutersLabels`
_Optional, Default=false_
Enable metrics on routers.
```toml tab="File (TOML)"
[metrics]
[metrics.prometheus]
addRoutersLabels = true
```
```yaml tab="File (YAML)"
metrics:
prometheus:
addRoutersLabels: true
```
```bash tab="CLI"
--metrics.prometheus.addrouterslabels=true
```
#### `addServicesLabels` #### `addServicesLabels`
_Optional, Default=true_ _Optional, Default=true_

View file

@ -60,6 +60,28 @@ metrics:
--metrics.statsd.addEntryPointsLabels=true --metrics.statsd.addEntryPointsLabels=true
``` ```
#### `AddRoutersLabels`
_Optional, Default=false_
Enable metrics on entry points.
```toml tab="File (TOML)"
[metrics]
[metrics.statsD]
addRoutersLabels = true
```
```yaml tab="File (YAML)"
metrics:
statsD:
addRoutersLabels: true
```
```bash tab="CLI"
--metrics.statsd.addrouterslabels=true
```
#### `addServicesLabels` #### `addServicesLabels`
_Optional, Default=true_ _Optional, Default=true_
@ -124,4 +146,4 @@ metrics:
```bash tab="CLI" ```bash tab="CLI"
--metrics.statsd.prefix="traefik" --metrics.statsd.prefix="traefik"
``` ```

View file

@ -231,6 +231,9 @@ Enable metrics on entry points. (Default: ```true```)
`--metrics.datadog.address`: `--metrics.datadog.address`:
Datadog's address. (Default: ```localhost:8125```) Datadog's address. (Default: ```localhost:8125```)
`--metrics.datadog.addrouterslabels`:
Enable metrics on routers. (Default: ```false```)
`--metrics.datadog.addserviceslabels`: `--metrics.datadog.addserviceslabels`:
Enable metrics on services. (Default: ```true```) Enable metrics on services. (Default: ```true```)
@ -246,6 +249,9 @@ Enable metrics on entry points. (Default: ```true```)
`--metrics.influxdb.address`: `--metrics.influxdb.address`:
InfluxDB address. (Default: ```localhost:8089```) InfluxDB address. (Default: ```localhost:8089```)
`--metrics.influxdb.addrouterslabels`:
Enable metrics on routers. (Default: ```false```)
`--metrics.influxdb.addserviceslabels`: `--metrics.influxdb.addserviceslabels`:
Enable metrics on services. (Default: ```true```) Enable metrics on services. (Default: ```true```)
@ -273,6 +279,9 @@ Prometheus metrics exporter type. (Default: ```false```)
`--metrics.prometheus.addentrypointslabels`: `--metrics.prometheus.addentrypointslabels`:
Enable metrics on entry points. (Default: ```true```) Enable metrics on entry points. (Default: ```true```)
`--metrics.prometheus.addrouterslabels`:
Enable metrics on routers. (Default: ```false```)
`--metrics.prometheus.addserviceslabels`: `--metrics.prometheus.addserviceslabels`:
Enable metrics on services. (Default: ```true```) Enable metrics on services. (Default: ```true```)
@ -294,6 +303,9 @@ Enable metrics on entry points. (Default: ```true```)
`--metrics.statsd.address`: `--metrics.statsd.address`:
StatsD address. (Default: ```localhost:8125```) StatsD address. (Default: ```localhost:8125```)
`--metrics.statsd.addrouterslabels`:
Enable metrics on routers. (Default: ```false```)
`--metrics.statsd.addserviceslabels`: `--metrics.statsd.addserviceslabels`:
Enable metrics on services. (Default: ```true```) Enable metrics on services. (Default: ```true```)

View file

@ -231,6 +231,9 @@ Enable metrics on entry points. (Default: ```true```)
`TRAEFIK_METRICS_DATADOG_ADDRESS`: `TRAEFIK_METRICS_DATADOG_ADDRESS`:
Datadog's address. (Default: ```localhost:8125```) Datadog's address. (Default: ```localhost:8125```)
`TRAEFIK_METRICS_DATADOG_ADDROUTERSLABELS`:
Enable metrics on routers. (Default: ```false```)
`TRAEFIK_METRICS_DATADOG_ADDSERVICESLABELS`: `TRAEFIK_METRICS_DATADOG_ADDSERVICESLABELS`:
Enable metrics on services. (Default: ```true```) Enable metrics on services. (Default: ```true```)
@ -246,6 +249,9 @@ Enable metrics on entry points. (Default: ```true```)
`TRAEFIK_METRICS_INFLUXDB_ADDRESS`: `TRAEFIK_METRICS_INFLUXDB_ADDRESS`:
InfluxDB address. (Default: ```localhost:8089```) InfluxDB address. (Default: ```localhost:8089```)
`TRAEFIK_METRICS_INFLUXDB_ADDROUTERSLABELS`:
Enable metrics on routers. (Default: ```false```)
`TRAEFIK_METRICS_INFLUXDB_ADDSERVICESLABELS`: `TRAEFIK_METRICS_INFLUXDB_ADDSERVICESLABELS`:
Enable metrics on services. (Default: ```true```) Enable metrics on services. (Default: ```true```)
@ -273,6 +279,9 @@ Prometheus metrics exporter type. (Default: ```false```)
`TRAEFIK_METRICS_PROMETHEUS_ADDENTRYPOINTSLABELS`: `TRAEFIK_METRICS_PROMETHEUS_ADDENTRYPOINTSLABELS`:
Enable metrics on entry points. (Default: ```true```) Enable metrics on entry points. (Default: ```true```)
`TRAEFIK_METRICS_PROMETHEUS_ADDROUTERSLABELS`:
Enable metrics on routers. (Default: ```false```)
`TRAEFIK_METRICS_PROMETHEUS_ADDSERVICESLABELS`: `TRAEFIK_METRICS_PROMETHEUS_ADDSERVICESLABELS`:
Enable metrics on services. (Default: ```true```) Enable metrics on services. (Default: ```true```)
@ -294,6 +303,9 @@ Enable metrics on entry points. (Default: ```true```)
`TRAEFIK_METRICS_STATSD_ADDRESS`: `TRAEFIK_METRICS_STATSD_ADDRESS`:
StatsD address. (Default: ```localhost:8125```) StatsD address. (Default: ```localhost:8125```)
`TRAEFIK_METRICS_STATSD_ADDROUTERSLABELS`:
Enable metrics on routers. (Default: ```false```)
`TRAEFIK_METRICS_STATSD_ADDSERVICESLABELS`: `TRAEFIK_METRICS_STATSD_ADDSERVICESLABELS`:
Enable metrics on services. (Default: ```true```) Enable metrics on services. (Default: ```true```)

View file

@ -235,6 +235,7 @@
[metrics.prometheus] [metrics.prometheus]
buckets = [42.0, 42.0] buckets = [42.0, 42.0]
addEntryPointsLabels = true addEntryPointsLabels = true
addRoutersLabels = true
addServicesLabels = true addServicesLabels = true
entryPoint = "foobar" entryPoint = "foobar"
manualRouting = true manualRouting = true
@ -242,11 +243,13 @@
address = "foobar" address = "foobar"
pushInterval = "42s" pushInterval = "42s"
addEntryPointsLabels = true addEntryPointsLabels = true
addRoutersLabels = true
addServicesLabels = true addServicesLabels = true
[metrics.statsD] [metrics.statsD]
address = "foobar" address = "foobar"
pushInterval = "42s" pushInterval = "42s"
addEntryPointsLabels = true addEntryPointsLabels = true
addRoutersLabels = true
addServicesLabels = true addServicesLabels = true
prefix = "foobar" prefix = "foobar"
[metrics.influxDB] [metrics.influxDB]
@ -258,6 +261,7 @@
username = "foobar" username = "foobar"
password = "foobar" password = "foobar"
addEntryPointsLabels = true addEntryPointsLabels = true
addRoutersLabels = true
addServicesLabels = true addServicesLabels = true
[ping] [ping]

View file

@ -257,6 +257,7 @@ metrics:
- 42 - 42
- 42 - 42
addEntryPointsLabels: true addEntryPointsLabels: true
addRoutersLabels: true
addServicesLabels: true addServicesLabels: true
entryPoint: foobar entryPoint: foobar
manualRouting: true manualRouting: true
@ -264,11 +265,13 @@ metrics:
address: foobar address: foobar
pushInterval: 42 pushInterval: 42
addEntryPointsLabels: true addEntryPointsLabels: true
addRoutersLabels: true
addServicesLabels: true addServicesLabels: true
statsD: statsD:
address: foobar address: foobar
pushInterval: 42 pushInterval: 42
addEntryPointsLabels: true addEntryPointsLabels: true
addRoutersLabels: true
addServicesLabels: true addServicesLabels: true
prefix: foobar prefix: foobar
influxDB: influxDB:
@ -280,6 +283,7 @@ metrics:
username: foobar username: foobar
password: foobar password: foobar
addEntryPointsLabels: true addEntryPointsLabels: true
addRoutersLabels: true
addServicesLabels: true addServicesLabels: true
ping: ping:
entryPoint: foobar entryPoint: foobar

View file

@ -3,6 +3,7 @@ whoami1:
labels: labels:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.router1.rule=PathPrefix("/whoami") - traefik.http.routers.router1.rule=PathPrefix("/whoami")
- traefik.http.routers.router2.rule=PathPrefix("/whoami2")
whoami2: whoami2:
image: traefik/whoami image: traefik/whoami

View file

@ -287,7 +287,7 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntryPoint(c *check.C) {
s.createComposeProject(c, "base") s.createComposeProject(c, "base")
s.composeProject.Start(c) s.composeProject.Start(c)
cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--api.insecure", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--providers.docker", "--log.level=DEBUG") cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--api.insecure", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--providers.docker", "--metrics.prometheus.addrouterslabels=true", "--log.level=DEBUG")
defer output(c) defer output(c)
err := cmd.Start() err := cmd.Start()
@ -302,6 +302,52 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntryPoint(c *check.C) {
err = try.GetRequest("http://127.0.0.1:8080/metrics", 1*time.Second, try.StatusCodeIs(http.StatusOK)) err = try.GetRequest("http://127.0.0.1:8080/metrics", 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8080/metrics", 1*time.Second, try.BodyContains("_router_"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8080/metrics", 1*time.Second, try.BodyContains("_entrypoint_"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8080/metrics", 1*time.Second, try.BodyContains("_service_"))
c.Assert(err, checker.IsNil)
}
func (s *SimpleSuite) TestMetricsPrometheusTwoRoutersOneService(c *check.C) {
s.createComposeProject(c, "base")
s.composeProject.Start(c)
cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--api.insecure", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--providers.docker", "--metrics.prometheus.addentrypointslabels=false", "--metrics.prometheus.addrouterslabels=true", "--log.level=DEBUG")
defer output(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("PathPrefix"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/whoami2", 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
request, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/metrics", nil)
c.Assert(err, checker.IsNil)
response, err := http.DefaultClient.Do(request)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
body, err := io.ReadAll(response.Body)
c.Assert(err, checker.IsNil)
// Reqs count of 1 for both routers
c.Assert(string(body), checker.Contains, "traefik_router_requests_total{code=\"200\",method=\"GET\",protocol=\"http\",router=\"router1@docker\",service=\"whoami1-integrationtestbase\"} 1")
c.Assert(string(body), checker.Contains, "traefik_router_requests_total{code=\"200\",method=\"GET\",protocol=\"http\",router=\"router2@docker\",service=\"whoami1-integrationtestbase\"} 1")
// Reqs count of 2 for service behind both routers
c.Assert(string(body), checker.Contains, "traefik_service_requests_total{code=\"200\",method=\"GET\",protocol=\"http\",service=\"whoami1-integrationtestbase@docker\"} 2")
} }
func (s *SimpleSuite) TestMultipleProviderSameBackendName(c *check.C) { func (s *SimpleSuite) TestMultipleProviderSameBackendName(c *check.C) {

View file

@ -20,19 +20,28 @@ var datadogTicker *time.Ticker
// Metric names consistent with https://github.com/DataDog/integrations-extras/pull/64 // Metric names consistent with https://github.com/DataDog/integrations-extras/pull/64
const ( const (
ddMetricsServiceReqsName = "service.request.total"
ddMetricsServiceLatencyName = "service.request.duration"
ddRetriesTotalName = "service.retries.total"
ddConfigReloadsName = "config.reload.total" ddConfigReloadsName = "config.reload.total"
ddConfigReloadsFailureTagName = "failure" ddConfigReloadsFailureTagName = "failure"
ddLastConfigReloadSuccessName = "config.reload.lastSuccessTimestamp" ddLastConfigReloadSuccessName = "config.reload.lastSuccessTimestamp"
ddLastConfigReloadFailureName = "config.reload.lastFailureTimestamp" ddLastConfigReloadFailureName = "config.reload.lastFailureTimestamp"
ddEntryPointReqsName = "entrypoint.request.total"
ddEntryPointReqDurationName = "entrypoint.request.duration"
ddEntryPointOpenConnsName = "entrypoint.connections.open"
ddOpenConnsName = "service.connections.open"
ddServerUpName = "service.server.up"
ddTLSCertsNotAfterTimestampName = "tls.certs.notAfterTimestamp" ddTLSCertsNotAfterTimestampName = "tls.certs.notAfterTimestamp"
ddEntryPointReqsName = "entrypoint.request.total"
ddEntryPointReqsTLSName = "entrypoint.request.tls.total"
ddEntryPointReqDurationName = "entrypoint.request.duration"
ddEntryPointOpenConnsName = "entrypoint.connections.open"
ddMetricsRouterReqsName = "router.request.total"
ddMetricsRouterReqsTLSName = "router.request.tls.total"
ddMetricsRouterReqsDurationName = "router.request.duration"
ddRouterOpenConnsName = "router.connections.open"
ddMetricsServiceReqsName = "service.request.total"
ddMetricsServiceReqsTLSName = "service.request.tls.total"
ddMetricsServiceReqsDurationName = "service.request.duration"
ddRetriesTotalName = "service.retries.total"
ddOpenConnsName = "service.connections.open"
ddServerUpName = "service.server.up"
) )
// RegisterDatadog registers the metrics pusher if this didn't happen yet and creates a datadog Registry instance. // RegisterDatadog registers the metrics pusher if this didn't happen yet and creates a datadog Registry instance.
@ -52,14 +61,24 @@ func RegisterDatadog(ctx context.Context, config *types.Datadog) Registry {
if config.AddEntryPointsLabels { if config.AddEntryPointsLabels {
registry.epEnabled = config.AddEntryPointsLabels registry.epEnabled = config.AddEntryPointsLabels
registry.entryPointReqsCounter = datadogClient.NewCounter(ddEntryPointReqsName, 1.0) registry.entryPointReqsCounter = datadogClient.NewCounter(ddEntryPointReqsName, 1.0)
registry.entryPointReqsTLSCounter = datadogClient.NewCounter(ddEntryPointReqsTLSName, 1.0)
registry.entryPointReqDurationHistogram, _ = NewHistogramWithScale(datadogClient.NewHistogram(ddEntryPointReqDurationName, 1.0), time.Second) registry.entryPointReqDurationHistogram, _ = NewHistogramWithScale(datadogClient.NewHistogram(ddEntryPointReqDurationName, 1.0), time.Second)
registry.entryPointOpenConnsGauge = datadogClient.NewGauge(ddEntryPointOpenConnsName) registry.entryPointOpenConnsGauge = datadogClient.NewGauge(ddEntryPointOpenConnsName)
} }
if config.AddRoutersLabels {
registry.routerEnabled = config.AddRoutersLabels
registry.routerReqsCounter = datadogClient.NewCounter(ddMetricsRouterReqsName, 1.0)
registry.routerReqsTLSCounter = datadogClient.NewCounter(ddMetricsRouterReqsTLSName, 1.0)
registry.routerReqDurationHistogram, _ = NewHistogramWithScale(datadogClient.NewHistogram(ddMetricsRouterReqsDurationName, 1.0), time.Second)
registry.routerOpenConnsGauge = datadogClient.NewGauge(ddRouterOpenConnsName)
}
if config.AddServicesLabels { if config.AddServicesLabels {
registry.svcEnabled = config.AddServicesLabels registry.svcEnabled = config.AddServicesLabels
registry.serviceReqsCounter = datadogClient.NewCounter(ddMetricsServiceReqsName, 1.0) registry.serviceReqsCounter = datadogClient.NewCounter(ddMetricsServiceReqsName, 1.0)
registry.serviceReqDurationHistogram, _ = NewHistogramWithScale(datadogClient.NewHistogram(ddMetricsServiceLatencyName, 1.0), time.Second) registry.serviceReqsTLSCounter = datadogClient.NewCounter(ddMetricsServiceReqsTLSName, 1.0)
registry.serviceReqDurationHistogram, _ = NewHistogramWithScale(datadogClient.NewHistogram(ddMetricsServiceReqsDurationName, 1.0), time.Second)
registry.serviceRetriesCounter = datadogClient.NewCounter(ddRetriesTotalName, 1.0) registry.serviceRetriesCounter = datadogClient.NewCounter(ddRetriesTotalName, 1.0)
registry.serviceOpenConnsGauge = datadogClient.NewGauge(ddOpenConnsName) registry.serviceOpenConnsGauge = datadogClient.NewGauge(ddOpenConnsName)
registry.serviceServerUpGauge = datadogClient.NewGauge(ddServerUpName) registry.serviceServerUpGauge = datadogClient.NewGauge(ddServerUpName)

View file

@ -17,40 +17,68 @@ func TestDatadog(t *testing.T) {
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond // This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
udp.Timeout = 5 * time.Second udp.Timeout = 5 * time.Second
datadogRegistry := RegisterDatadog(context.Background(), &types.Datadog{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddServicesLabels: true}) datadogRegistry := RegisterDatadog(context.Background(), &types.Datadog{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
defer StopDatadog() defer StopDatadog()
if !datadogRegistry.IsEpEnabled() || !datadogRegistry.IsSvcEnabled() { if !datadogRegistry.IsEpEnabled() || !datadogRegistry.IsRouterEnabled() || !datadogRegistry.IsSvcEnabled() {
t.Errorf("DatadogRegistry should return true for IsEnabled()") t.Errorf("DatadogRegistry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()")
} }
expected := []string{ expected := []string{
// We are only validating counts, as it is nearly impossible to validate latency, since it varies every run
"traefik.service.request.total:1.000000|c|#service:test,code:404,method:GET\n",
"traefik.service.request.total:1.000000|c|#service:test,code:200,method:GET\n",
"traefik.service.retries.total:2.000000|c|#service:test\n",
"traefik.service.request.duration:10000.000000|h|#service:test,code:200\n",
"traefik.config.reload.total:1.000000|c\n", "traefik.config.reload.total:1.000000|c\n",
"traefik.config.reload.total:1.000000|c|#failure:true\n", "traefik.config.reload.total:1.000000|c|#failure:true\n",
"traefik.config.reload.lastSuccessTimestamp:1.000000|g\n",
"traefik.config.reload.lastFailureTimestamp:1.000000|g\n",
"traefik.tls.certs.notAfterTimestamp:1.000000|g|#key:value\n",
"traefik.entrypoint.request.total:1.000000|c|#entrypoint:test\n", "traefik.entrypoint.request.total:1.000000|c|#entrypoint:test\n",
"traefik.entrypoint.request.tls.total:1.000000|c|#entrypoint:test,tls_version:foo,tls_cipher:bar\n",
"traefik.entrypoint.request.duration:10000.000000|h|#entrypoint:test\n", "traefik.entrypoint.request.duration:10000.000000|h|#entrypoint:test\n",
"traefik.entrypoint.connections.open:1.000000|g|#entrypoint:test\n", "traefik.entrypoint.connections.open:1.000000|g|#entrypoint:test\n",
"traefik.router.request.total:1.000000|c|#router:demo,service:test,code:404,method:GET\n",
"traefik.router.request.total:1.000000|c|#router:demo,service:test,code:200,method:GET\n",
"traefik.router.request.tls.total:1.000000|c|#router:demo,service:test,tls_version:foo,tls_cipher:bar\n",
"traefik.router.request.duration:10000.000000|h|#router:demo,service:test,code:200\n",
"traefik.router.connections.open:1.000000|g|#router:demo,service:test\n",
"traefik.service.request.total:1.000000|c|#service:test,code:404,method:GET\n",
"traefik.service.request.total:1.000000|c|#service:test,code:200,method:GET\n",
"traefik.service.request.tls.total:1.000000|c|#service:test,tls_version:foo,tls_cipher:bar\n",
"traefik.service.request.duration:10000.000000|h|#service:test,code:200\n",
"traefik.service.connections.open:1.000000|g|#service:test\n",
"traefik.service.retries.total:2.000000|c|#service:test\n",
"traefik.service.request.duration:10000.000000|h|#service:test,code:200\n",
"traefik.service.server.up:1.000000|g|#service:test,url:http://127.0.0.1,one:two\n", "traefik.service.server.up:1.000000|g|#service:test,url:http://127.0.0.1,one:two\n",
"traefik.tls.certs.notAfterTimestamp:1.000000|g|#key:value\n",
} }
udp.ShouldReceiveAll(t, expected, func() { udp.ShouldReceiveAll(t, expected, func() {
datadogRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
datadogRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
datadogRegistry.ServiceReqDurationHistogram().With("service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
datadogRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
datadogRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
datadogRegistry.ConfigReloadsCounter().Add(1) datadogRegistry.ConfigReloadsCounter().Add(1)
datadogRegistry.ConfigReloadsFailureCounter().Add(1) datadogRegistry.ConfigReloadsFailureCounter().Add(1)
datadogRegistry.LastConfigReloadSuccessGauge().Add(1)
datadogRegistry.LastConfigReloadFailureGauge().Add(1)
datadogRegistry.TLSCertsNotAfterTimestampGauge().With("key", "value").Set(1)
datadogRegistry.EntryPointReqsCounter().With("entrypoint", "test").Add(1) datadogRegistry.EntryPointReqsCounter().With("entrypoint", "test").Add(1)
datadogRegistry.EntryPointReqsTLSCounter().With("entrypoint", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
datadogRegistry.EntryPointReqDurationHistogram().With("entrypoint", "test").Observe(10000) datadogRegistry.EntryPointReqDurationHistogram().With("entrypoint", "test").Observe(10000)
datadogRegistry.EntryPointOpenConnsGauge().With("entrypoint", "test").Set(1) datadogRegistry.EntryPointOpenConnsGauge().With("entrypoint", "test").Set(1)
datadogRegistry.RouterReqsCounter().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
datadogRegistry.RouterReqsCounter().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
datadogRegistry.RouterReqsTLSCounter().With("router", "demo", "service", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
datadogRegistry.RouterReqDurationHistogram().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
datadogRegistry.RouterOpenConnsGauge().With("router", "demo", "service", "test").Set(1)
datadogRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
datadogRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
datadogRegistry.ServiceReqsTLSCounter().With("service", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
datadogRegistry.ServiceReqDurationHistogram().With("service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
datadogRegistry.ServiceOpenConnsGauge().With("service", "test").Set(1)
datadogRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
datadogRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
datadogRegistry.ServiceServerUpGauge().With("service", "test", "url", "http://127.0.0.1", "one", "two").Set(1) datadogRegistry.ServiceServerUpGauge().With("service", "test", "url", "http://127.0.0.1", "one", "two").Set(1)
datadogRegistry.TLSCertsNotAfterTimestampGauge().With("key", "value").Set(1)
}) })
} }

View file

@ -26,19 +26,29 @@ type influxDBWriter struct {
var influxDBTicker *time.Ticker var influxDBTicker *time.Ticker
const ( const (
influxDBMetricsServiceReqsName = "traefik.service.requests.total" influxDBConfigReloadsName = "traefik.config.reload.total"
influxDBMetricsServiceLatencyName = "traefik.service.request.duration" influxDBConfigReloadsFailureName = influxDBConfigReloadsName + ".failure"
influxDBRetriesTotalName = "traefik.service.retries.total" influxDBLastConfigReloadSuccessName = "traefik.config.reload.lastSuccessTimestamp"
influxDBConfigReloadsName = "traefik.config.reload.total" influxDBLastConfigReloadFailureName = "traefik.config.reload.lastFailureTimestamp"
influxDBConfigReloadsFailureName = influxDBConfigReloadsName + ".failure"
influxDBLastConfigReloadSuccessName = "traefik.config.reload.lastSuccessTimestamp"
influxDBLastConfigReloadFailureName = "traefik.config.reload.lastFailureTimestamp"
influxDBEntryPointReqsName = "traefik.entrypoint.requests.total"
influxDBEntryPointReqDurationName = "traefik.entrypoint.request.duration"
influxDBEntryPointOpenConnsName = "traefik.entrypoint.connections.open"
influxDBOpenConnsName = "traefik.service.connections.open"
influxDBServerUpName = "traefik.service.server.up"
influxDBTLSCertsNotAfterTimestampName = "traefik.tls.certs.notAfterTimestamp" influxDBTLSCertsNotAfterTimestampName = "traefik.tls.certs.notAfterTimestamp"
influxDBEntryPointReqsName = "traefik.entrypoint.requests.total"
influxDBEntryPointReqsTLSName = "traefik.entrypoint.requests.tls.total"
influxDBEntryPointReqDurationName = "traefik.entrypoint.request.duration"
influxDBEntryPointOpenConnsName = "traefik.entrypoint.connections.open"
influxDBRouterReqsName = "traefik.router.requests.total"
influxDBRouterReqsTLSName = "traefik.router.requests.tls.total"
influxDBRouterReqsDurationName = "traefik.router.request.duration"
influxDBORouterOpenConnsName = "traefik.router.connections.open"
influxDBServiceReqsName = "traefik.service.requests.total"
influxDBServiceReqsTLSName = "traefik.service.requests.tls.total"
influxDBServiceReqsDurationName = "traefik.service.request.duration"
influxDBServiceRetriesTotalName = "traefik.service.retries.total"
influxDBServiceOpenConnsName = "traefik.service.connections.open"
influxDBServiceServerUpName = "traefik.service.server.up"
) )
const ( const (
@ -66,17 +76,27 @@ func RegisterInfluxDB(ctx context.Context, config *types.InfluxDB) Registry {
if config.AddEntryPointsLabels { if config.AddEntryPointsLabels {
registry.epEnabled = config.AddEntryPointsLabels registry.epEnabled = config.AddEntryPointsLabels
registry.entryPointReqsCounter = influxDBClient.NewCounter(influxDBEntryPointReqsName) registry.entryPointReqsCounter = influxDBClient.NewCounter(influxDBEntryPointReqsName)
registry.entryPointReqsTLSCounter = influxDBClient.NewCounter(influxDBEntryPointReqsTLSName)
registry.entryPointReqDurationHistogram, _ = NewHistogramWithScale(influxDBClient.NewHistogram(influxDBEntryPointReqDurationName), time.Second) registry.entryPointReqDurationHistogram, _ = NewHistogramWithScale(influxDBClient.NewHistogram(influxDBEntryPointReqDurationName), time.Second)
registry.entryPointOpenConnsGauge = influxDBClient.NewGauge(influxDBEntryPointOpenConnsName) registry.entryPointOpenConnsGauge = influxDBClient.NewGauge(influxDBEntryPointOpenConnsName)
} }
if config.AddRoutersLabels {
registry.routerEnabled = config.AddRoutersLabels
registry.routerReqsCounter = influxDBClient.NewCounter(influxDBRouterReqsName)
registry.routerReqsTLSCounter = influxDBClient.NewCounter(influxDBRouterReqsTLSName)
registry.routerReqDurationHistogram, _ = NewHistogramWithScale(influxDBClient.NewHistogram(influxDBRouterReqsDurationName), time.Second)
registry.routerOpenConnsGauge = influxDBClient.NewGauge(influxDBORouterOpenConnsName)
}
if config.AddServicesLabels { if config.AddServicesLabels {
registry.svcEnabled = config.AddServicesLabels registry.svcEnabled = config.AddServicesLabels
registry.serviceReqsCounter = influxDBClient.NewCounter(influxDBMetricsServiceReqsName) registry.serviceReqsCounter = influxDBClient.NewCounter(influxDBServiceReqsName)
registry.serviceReqDurationHistogram, _ = NewHistogramWithScale(influxDBClient.NewHistogram(influxDBMetricsServiceLatencyName), time.Second) registry.serviceReqsTLSCounter = influxDBClient.NewCounter(influxDBServiceReqsTLSName)
registry.serviceRetriesCounter = influxDBClient.NewCounter(influxDBRetriesTotalName) registry.serviceReqDurationHistogram, _ = NewHistogramWithScale(influxDBClient.NewHistogram(influxDBServiceReqsDurationName), time.Second)
registry.serviceOpenConnsGauge = influxDBClient.NewGauge(influxDBOpenConnsName) registry.serviceRetriesCounter = influxDBClient.NewCounter(influxDBServiceRetriesTotalName)
registry.serviceServerUpGauge = influxDBClient.NewGauge(influxDBServerUpName) registry.serviceOpenConnsGauge = influxDBClient.NewGauge(influxDBServiceOpenConnsName)
registry.serviceServerUpGauge = influxDBClient.NewGauge(influxDBServiceServerUpName)
} }
return registry return registry

View file

@ -21,49 +21,28 @@ func TestInfluxDB(t *testing.T) {
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond // This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
udp.Timeout = 5 * time.Second udp.Timeout = 5 * time.Second
influxDBRegistry := RegisterInfluxDB(context.Background(), &types.InfluxDB{Address: ":8089", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddServicesLabels: true}) influxDBRegistry := RegisterInfluxDB(context.Background(), &types.InfluxDB{Address: ":8089", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
defer StopInfluxDB() defer StopInfluxDB()
if !influxDBRegistry.IsEpEnabled() || !influxDBRegistry.IsSvcEnabled() { if !influxDBRegistry.IsEpEnabled() || !influxDBRegistry.IsRouterEnabled() || !influxDBRegistry.IsSvcEnabled() {
t.Fatalf("InfluxDB registry must be epEnabled") t.Fatalf("InfluxDBRegistry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()")
} }
expectedService := []string{ expectedServer := []string{
`(traefik\.service\.requests\.total,code=200,method=GET,service=test count=1) [\d]{19}`, `(traefik\.config\.reload\.total count=1) [\d]{19}`,
`(traefik\.service\.requests\.total,code=404,method=GET,service=test count=1) [\d]{19}`, `(traefik\.config\.reload\.total\.failure count=1) [\d]{19}`,
`(traefik\.service\.request\.duration,code=200,service=test p50=10000,p90=10000,p95=10000,p99=10000) [\d]{19}`, `(traefik\.config\.reload\.lastSuccessTimestamp value=1) [\d]{19}`,
`(traefik\.service\.retries\.total(?:,code=[\d]{3},method=GET)?,service=test count=2) [\d]{19}`, `(traefik\.config\.reload\.lastFailureTimestamp value=1) [\d]{19}`,
`(traefik\.config\.reload\.total(?:[a-z=0-9A-Z,]+)? count=1) [\d]{19}`,
`(traefik\.config\.reload\.total\.failure(?:[a-z=0-9A-Z,]+)? count=1) [\d]{19}`,
`(traefik\.service\.server\.up,service=test(?:[a-z=0-9A-Z,]+)?,url=http://127.0.0.1 value=1) [\d]{19}`,
} }
msgService := udp.ReceiveString(t, func() { msgServer := udp.ReceiveString(t, func() {
influxDBRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
influxDBRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
influxDBRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
influxDBRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
influxDBRegistry.ServiceReqDurationHistogram().With("service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
influxDBRegistry.ConfigReloadsCounter().Add(1) influxDBRegistry.ConfigReloadsCounter().Add(1)
influxDBRegistry.ConfigReloadsFailureCounter().Add(1) influxDBRegistry.ConfigReloadsFailureCounter().Add(1)
influxDBRegistry.ServiceServerUpGauge().With("service", "test", "url", "http://127.0.0.1").Set(1) influxDBRegistry.LastConfigReloadSuccessGauge().Set(1)
influxDBRegistry.LastConfigReloadFailureGauge().Set(1)
}) })
assertMessage(t, msgService, expectedService) assertMessage(t, msgServer, expectedServer)
expectedEntrypoint := []string{
`(traefik\.entrypoint\.requests\.total,entrypoint=test(?:[a-z=0-9A-Z,:/.]+)? count=1) [\d]{19}`,
`(traefik\.entrypoint\.request\.duration(?:,code=[\d]{3})?,entrypoint=test(?:[a-z=0-9A-Z,:/.]+)? p50=10000,p90=10000,p95=10000,p99=10000) [\d]{19}`,
`(traefik\.entrypoint\.connections\.open,entrypoint=test value=1) [\d]{19}`,
}
msgEntrypoint := udp.ReceiveString(t, func() {
influxDBRegistry.EntryPointReqsCounter().With("entrypoint", "test").Add(1)
influxDBRegistry.EntryPointReqDurationHistogram().With("entrypoint", "test").Observe(10000)
influxDBRegistry.EntryPointOpenConnsGauge().With("entrypoint", "test").Set(1)
})
assertMessage(t, msgEntrypoint, expectedEntrypoint)
expectedTLS := []string{ expectedTLS := []string{
`(traefik\.tls\.certs\.notAfterTimestamp,key=value value=1) [\d]{19}`, `(traefik\.tls\.certs\.notAfterTimestamp,key=value value=1) [\d]{19}`,
@ -74,6 +53,63 @@ func TestInfluxDB(t *testing.T) {
}) })
assertMessage(t, msgTLS, expectedTLS) assertMessage(t, msgTLS, expectedTLS)
expectedEntrypoint := []string{
`(traefik\.entrypoint\.requests\.total,code=200,entrypoint=test,method=GET count=1) [\d]{19}`,
`(traefik\.entrypoint\.requests\.tls\.total,entrypoint=test,tls_cipher=bar,tls_version=foo count=1) [\d]{19}`,
`(traefik\.entrypoint\.request\.duration(?:,code=[\d]{3})?,entrypoint=test p50=10000,p90=10000,p95=10000,p99=10000) [\d]{19}`,
`(traefik\.entrypoint\.connections\.open,entrypoint=test value=1) [\d]{19}`,
}
msgEntrypoint := udp.ReceiveString(t, func() {
influxDBRegistry.EntryPointReqsCounter().With("entrypoint", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
influxDBRegistry.EntryPointReqsTLSCounter().With("entrypoint", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
influxDBRegistry.EntryPointReqDurationHistogram().With("entrypoint", "test").Observe(10000)
influxDBRegistry.EntryPointOpenConnsGauge().With("entrypoint", "test").Set(1)
})
assertMessage(t, msgEntrypoint, expectedEntrypoint)
expectedRouter := []string{
`(traefik\.router\.requests\.total,code=200,method=GET,router=demo,service=test count=1) [\d]{19}`,
`(traefik\.router\.requests\.total,code=404,method=GET,router=demo,service=test count=1) [\d]{19}`,
`(traefik\.router\.requests\.tls\.total,router=demo,service=test,tls_cipher=bar,tls_version=foo count=1) [\d]{19}`,
`(traefik\.router\.request\.duration,code=200,router=demo,service=test p50=10000,p90=10000,p95=10000,p99=10000) [\d]{19}`,
`(traefik\.router\.connections\.open,router=demo,service=test value=1) [\d]{19}`,
}
msgRouter := udp.ReceiveString(t, func() {
influxDBRegistry.RouterReqsCounter().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
influxDBRegistry.RouterReqsCounter().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
influxDBRegistry.RouterReqsTLSCounter().With("router", "demo", "service", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
influxDBRegistry.RouterReqDurationHistogram().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
influxDBRegistry.RouterOpenConnsGauge().With("router", "demo", "service", "test").Set(1)
})
assertMessage(t, msgRouter, expectedRouter)
expectedService := []string{
`(traefik\.service\.requests\.total,code=200,method=GET,service=test count=1) [\d]{19}`,
`(traefik\.service\.requests\.total,code=404,method=GET,service=test count=1) [\d]{19}`,
`(traefik\.service\.requests\.tls\.total,service=test,tls_cipher=bar,tls_version=foo count=1) [\d]{19}`,
`(traefik\.service\.request\.duration,code=200,service=test p50=10000,p90=10000,p95=10000,p99=10000) [\d]{19}`,
`(traefik\.service\.retries\.total(?:,code=[\d]{3},method=GET)?,service=test count=2) [\d]{19}`,
`(traefik\.service\.server\.up,service=test,url=http://127.0.0.1 value=1) [\d]{19}`,
`(traefik\.service\.connections\.open,service=test value=1) [\d]{19}`,
}
msgService := udp.ReceiveString(t, func() {
influxDBRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
influxDBRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
influxDBRegistry.ServiceReqsTLSCounter().With("service", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
influxDBRegistry.ServiceReqDurationHistogram().With("service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
influxDBRegistry.ServiceOpenConnsGauge().With("service", "test").Set(1)
influxDBRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
influxDBRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
influxDBRegistry.ServiceServerUpGauge().With("service", "test", "url", "http://127.0.0.1").Set(1)
})
assertMessage(t, msgService, expectedService)
} }
func TestInfluxDBHTTP(t *testing.T) { func TestInfluxDBHTTP(t *testing.T) {
@ -90,47 +126,27 @@ func TestInfluxDBHTTP(t *testing.T) {
})) }))
defer ts.Close() defer ts.Close()
influxDBRegistry := RegisterInfluxDB(context.Background(), &types.InfluxDB{Address: ts.URL, Protocol: "http", PushInterval: ptypes.Duration(time.Second), Database: "test", RetentionPolicy: "autogen", AddEntryPointsLabels: true, AddServicesLabels: true}) influxDBRegistry := RegisterInfluxDB(context.Background(), &types.InfluxDB{Address: ts.URL, Protocol: "http", PushInterval: ptypes.Duration(time.Second), Database: "test", RetentionPolicy: "autogen", AddEntryPointsLabels: true, AddServicesLabels: true, AddRoutersLabels: true})
defer StopInfluxDB() defer StopInfluxDB()
if !influxDBRegistry.IsEpEnabled() || !influxDBRegistry.IsSvcEnabled() { if !influxDBRegistry.IsEpEnabled() || !influxDBRegistry.IsRouterEnabled() || !influxDBRegistry.IsSvcEnabled() {
t.Fatalf("InfluxDB registry must be epEnabled") t.Fatalf("InfluxDB registry must be epEnabled")
} }
expectedService := []string{ expectedServer := []string{
`(traefik\.service\.requests\.total,code=200,method=GET,service=test count=1) [\d]{19}`, `(traefik\.config\.reload\.total count=1) [\d]{19}`,
`(traefik\.service\.requests\.total,code=404,method=GET,service=test count=1) [\d]{19}`, `(traefik\.config\.reload\.total\.failure count=1) [\d]{19}`,
`(traefik\.service\.request\.duration,code=200,service=test p50=10000,p90=10000,p95=10000,p99=10000) [\d]{19}`, `(traefik\.config\.reload\.lastSuccessTimestamp value=1) [\d]{19}`,
`(traefik\.service\.retries\.total(?:,code=[\d]{3},method=GET)?,service=test count=2) [\d]{19}`, `(traefik\.config\.reload\.lastFailureTimestamp value=1) [\d]{19}`,
`(traefik\.config\.reload\.total(?:[a-z=0-9A-Z,]+)? count=1) [\d]{19}`,
`(traefik\.config\.reload\.total\.failure(?:[a-z=0-9A-Z,]+)? count=1) [\d]{19}`,
`(traefik\.service\.server\.up,service=test(?:[a-z=0-9A-Z,]+)?,url=http://127.0.0.1 value=1) [\d]{19}`,
} }
influxDBRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
influxDBRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
influxDBRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
influxDBRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
influxDBRegistry.ServiceReqDurationHistogram().With("service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
influxDBRegistry.ConfigReloadsCounter().Add(1) influxDBRegistry.ConfigReloadsCounter().Add(1)
influxDBRegistry.ConfigReloadsFailureCounter().Add(1) influxDBRegistry.ConfigReloadsFailureCounter().Add(1)
influxDBRegistry.ServiceServerUpGauge().With("service", "test", "url", "http://127.0.0.1").Set(1) influxDBRegistry.LastConfigReloadSuccessGauge().Set(1)
msgService := <-c influxDBRegistry.LastConfigReloadFailureGauge().Set(1)
msgServer := <-c
assertMessage(t, *msgService, expectedService) assertMessage(t, *msgServer, expectedServer)
expectedEntrypoint := []string{
`(traefik\.entrypoint\.requests\.total,entrypoint=test(?:[a-z=0-9A-Z,:/.]+)? count=1) [\d]{19}`,
`(traefik\.entrypoint\.request\.duration(?:,code=[\d]{3})?,entrypoint=test(?:[a-z=0-9A-Z,:/.]+)? p50=10000,p90=10000,p95=10000,p99=10000) [\d]{19}`,
`(traefik\.entrypoint\.connections\.open,entrypoint=test value=1) [\d]{19}`,
}
influxDBRegistry.EntryPointReqsCounter().With("entrypoint", "test").Add(1)
influxDBRegistry.EntryPointReqDurationHistogram().With("entrypoint", "test").Observe(10000)
influxDBRegistry.EntryPointOpenConnsGauge().With("entrypoint", "test").Set(1)
msgEntrypoint := <-c
assertMessage(t, *msgEntrypoint, expectedEntrypoint)
expectedTLS := []string{ expectedTLS := []string{
`(traefik\.tls\.certs\.notAfterTimestamp,key=value value=1) [\d]{19}`, `(traefik\.tls\.certs\.notAfterTimestamp,key=value value=1) [\d]{19}`,
@ -140,6 +156,60 @@ func TestInfluxDBHTTP(t *testing.T) {
msgTLS := <-c msgTLS := <-c
assertMessage(t, *msgTLS, expectedTLS) assertMessage(t, *msgTLS, expectedTLS)
expectedEntrypoint := []string{
`(traefik\.entrypoint\.requests\.total,code=200,entrypoint=test,method=GET count=1) [\d]{19}`,
`(traefik\.entrypoint\.requests\.tls\.total,entrypoint=test,tls_cipher=bar,tls_version=foo count=1) [\d]{19}`,
`(traefik\.entrypoint\.request\.duration(?:,code=[\d]{3})?,entrypoint=test p50=10000,p90=10000,p95=10000,p99=10000) [\d]{19}`,
`(traefik\.entrypoint\.connections\.open,entrypoint=test value=1) [\d]{19}`,
}
influxDBRegistry.EntryPointReqsCounter().With("entrypoint", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
influxDBRegistry.EntryPointReqsTLSCounter().With("entrypoint", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
influxDBRegistry.EntryPointReqDurationHistogram().With("entrypoint", "test").Observe(10000)
influxDBRegistry.EntryPointOpenConnsGauge().With("entrypoint", "test").Set(1)
msgEntrypoint := <-c
assertMessage(t, *msgEntrypoint, expectedEntrypoint)
expectedRouter := []string{
`(traefik\.router\.requests\.total,code=200,method=GET,router=demo,service=test count=1) [\d]{19}`,
`(traefik\.router\.requests\.total,code=404,method=GET,router=demo,service=test count=1) [\d]{19}`,
`(traefik\.router\.requests\.tls\.total,router=demo,service=test,tls_cipher=bar,tls_version=foo count=1) [\d]{19}`,
`(traefik\.router\.request\.duration,code=200,router=demo,service=test p50=10000,p90=10000,p95=10000,p99=10000) [\d]{19}`,
`(traefik\.router\.connections\.open,router=demo,service=test value=1) [\d]{19}`,
}
influxDBRegistry.RouterReqsCounter().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
influxDBRegistry.RouterReqsCounter().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
influxDBRegistry.RouterReqsTLSCounter().With("router", "demo", "service", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
influxDBRegistry.RouterReqDurationHistogram().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
influxDBRegistry.RouterOpenConnsGauge().With("router", "demo", "service", "test").Set(1)
msgRouter := <-c
assertMessage(t, *msgRouter, expectedRouter)
expectedService := []string{
`(traefik\.service\.requests\.total,code=200,method=GET,service=test count=1) [\d]{19}`,
`(traefik\.service\.requests\.total,code=404,method=GET,service=test count=1) [\d]{19}`,
`(traefik\.service\.requests\.tls\.total,service=test,tls_cipher=bar,tls_version=foo count=1) [\d]{19}`,
`(traefik\.service\.request\.duration,code=200,service=test p50=10000,p90=10000,p95=10000,p99=10000) [\d]{19}`,
`(traefik\.service\.retries\.total(?:,code=[\d]{3},method=GET)?,service=test count=2) [\d]{19}`,
`(traefik\.service\.server\.up,service=test,url=http://127.0.0.1 value=1) [\d]{19}`,
`(traefik\.service\.connections\.open,service=test value=1) [\d]{19}`,
}
influxDBRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
influxDBRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
influxDBRegistry.ServiceReqsTLSCounter().With("service", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
influxDBRegistry.ServiceReqDurationHistogram().With("service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
influxDBRegistry.ServiceOpenConnsGauge().With("service", "test").Set(1)
influxDBRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
influxDBRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
influxDBRegistry.ServiceServerUpGauge().With("service", "test", "url", "http://127.0.0.1").Set(1)
msgService := <-c
assertMessage(t, *msgService, expectedService)
} }
func assertMessage(t *testing.T, msg string, patterns []string) { func assertMessage(t *testing.T, msg string, patterns []string) {

View file

@ -12,6 +12,8 @@ import (
type Registry interface { type Registry interface {
// IsEpEnabled shows whether metrics instrumentation is enabled on entry points. // IsEpEnabled shows whether metrics instrumentation is enabled on entry points.
IsEpEnabled() bool IsEpEnabled() bool
// IsRouterEnabled shows whether metrics instrumentation is enabled on routers.
IsRouterEnabled() bool
// IsSvcEnabled shows whether metrics instrumentation is enabled on services. // IsSvcEnabled shows whether metrics instrumentation is enabled on services.
IsSvcEnabled() bool IsSvcEnabled() bool
@ -30,6 +32,12 @@ type Registry interface {
EntryPointReqDurationHistogram() ScalableHistogram EntryPointReqDurationHistogram() ScalableHistogram
EntryPointOpenConnsGauge() metrics.Gauge EntryPointOpenConnsGauge() metrics.Gauge
// router metrics
RouterReqsCounter() metrics.Counter
RouterReqsTLSCounter() metrics.Counter
RouterReqDurationHistogram() ScalableHistogram
RouterOpenConnsGauge() metrics.Gauge
// service metrics // service metrics
ServiceReqsCounter() metrics.Counter ServiceReqsCounter() metrics.Counter
ServiceReqsTLSCounter() metrics.Counter ServiceReqsTLSCounter() metrics.Counter
@ -58,6 +66,10 @@ func NewMultiRegistry(registries []Registry) Registry {
var entryPointReqsTLSCounter []metrics.Counter var entryPointReqsTLSCounter []metrics.Counter
var entryPointReqDurationHistogram []ScalableHistogram var entryPointReqDurationHistogram []ScalableHistogram
var entryPointOpenConnsGauge []metrics.Gauge var entryPointOpenConnsGauge []metrics.Gauge
var routerReqsCounter []metrics.Counter
var routerReqsTLSCounter []metrics.Counter
var routerReqDurationHistogram []ScalableHistogram
var routerOpenConnsGauge []metrics.Gauge
var serviceReqsCounter []metrics.Counter var serviceReqsCounter []metrics.Counter
var serviceReqsTLSCounter []metrics.Counter var serviceReqsTLSCounter []metrics.Counter
var serviceReqDurationHistogram []ScalableHistogram var serviceReqDurationHistogram []ScalableHistogram
@ -93,6 +105,18 @@ func NewMultiRegistry(registries []Registry) Registry {
if r.EntryPointOpenConnsGauge() != nil { if r.EntryPointOpenConnsGauge() != nil {
entryPointOpenConnsGauge = append(entryPointOpenConnsGauge, r.EntryPointOpenConnsGauge()) entryPointOpenConnsGauge = append(entryPointOpenConnsGauge, r.EntryPointOpenConnsGauge())
} }
if r.RouterReqsCounter() != nil {
routerReqsCounter = append(routerReqsCounter, r.RouterReqsCounter())
}
if r.RouterReqsTLSCounter() != nil {
routerReqsTLSCounter = append(routerReqsTLSCounter, r.RouterReqsTLSCounter())
}
if r.RouterReqDurationHistogram() != nil {
routerReqDurationHistogram = append(routerReqDurationHistogram, r.RouterReqDurationHistogram())
}
if r.RouterOpenConnsGauge() != nil {
routerOpenConnsGauge = append(routerOpenConnsGauge, r.RouterOpenConnsGauge())
}
if r.ServiceReqsCounter() != nil { if r.ServiceReqsCounter() != nil {
serviceReqsCounter = append(serviceReqsCounter, r.ServiceReqsCounter()) serviceReqsCounter = append(serviceReqsCounter, r.ServiceReqsCounter())
} }
@ -116,6 +140,7 @@ func NewMultiRegistry(registries []Registry) Registry {
return &standardRegistry{ return &standardRegistry{
epEnabled: len(entryPointReqsCounter) > 0 || len(entryPointReqDurationHistogram) > 0 || len(entryPointOpenConnsGauge) > 0, epEnabled: len(entryPointReqsCounter) > 0 || len(entryPointReqDurationHistogram) > 0 || len(entryPointOpenConnsGauge) > 0,
svcEnabled: len(serviceReqsCounter) > 0 || len(serviceReqDurationHistogram) > 0 || len(serviceOpenConnsGauge) > 0 || len(serviceRetriesCounter) > 0 || len(serviceServerUpGauge) > 0, svcEnabled: len(serviceReqsCounter) > 0 || len(serviceReqDurationHistogram) > 0 || len(serviceOpenConnsGauge) > 0 || len(serviceRetriesCounter) > 0 || len(serviceServerUpGauge) > 0,
routerEnabled: len(routerReqsCounter) > 0 || len(routerReqDurationHistogram) > 0 || len(routerOpenConnsGauge) > 0,
configReloadsCounter: multi.NewCounter(configReloadsCounter...), configReloadsCounter: multi.NewCounter(configReloadsCounter...),
configReloadsFailureCounter: multi.NewCounter(configReloadsFailureCounter...), configReloadsFailureCounter: multi.NewCounter(configReloadsFailureCounter...),
lastConfigReloadSuccessGauge: multi.NewGauge(lastConfigReloadSuccessGauge...), lastConfigReloadSuccessGauge: multi.NewGauge(lastConfigReloadSuccessGauge...),
@ -125,6 +150,10 @@ func NewMultiRegistry(registries []Registry) Registry {
entryPointReqsTLSCounter: multi.NewCounter(entryPointReqsTLSCounter...), entryPointReqsTLSCounter: multi.NewCounter(entryPointReqsTLSCounter...),
entryPointReqDurationHistogram: NewMultiHistogram(entryPointReqDurationHistogram...), entryPointReqDurationHistogram: NewMultiHistogram(entryPointReqDurationHistogram...),
entryPointOpenConnsGauge: multi.NewGauge(entryPointOpenConnsGauge...), entryPointOpenConnsGauge: multi.NewGauge(entryPointOpenConnsGauge...),
routerReqsCounter: multi.NewCounter(routerReqsCounter...),
routerReqsTLSCounter: multi.NewCounter(routerReqsTLSCounter...),
routerReqDurationHistogram: NewMultiHistogram(routerReqDurationHistogram...),
routerOpenConnsGauge: multi.NewGauge(routerOpenConnsGauge...),
serviceReqsCounter: multi.NewCounter(serviceReqsCounter...), serviceReqsCounter: multi.NewCounter(serviceReqsCounter...),
serviceReqsTLSCounter: multi.NewCounter(serviceReqsTLSCounter...), serviceReqsTLSCounter: multi.NewCounter(serviceReqsTLSCounter...),
serviceReqDurationHistogram: NewMultiHistogram(serviceReqDurationHistogram...), serviceReqDurationHistogram: NewMultiHistogram(serviceReqDurationHistogram...),
@ -136,6 +165,7 @@ func NewMultiRegistry(registries []Registry) Registry {
type standardRegistry struct { type standardRegistry struct {
epEnabled bool epEnabled bool
routerEnabled bool
svcEnabled bool svcEnabled bool
configReloadsCounter metrics.Counter configReloadsCounter metrics.Counter
configReloadsFailureCounter metrics.Counter configReloadsFailureCounter metrics.Counter
@ -146,6 +176,10 @@ type standardRegistry struct {
entryPointReqsTLSCounter metrics.Counter entryPointReqsTLSCounter metrics.Counter
entryPointReqDurationHistogram ScalableHistogram entryPointReqDurationHistogram ScalableHistogram
entryPointOpenConnsGauge metrics.Gauge entryPointOpenConnsGauge metrics.Gauge
routerReqsCounter metrics.Counter
routerReqsTLSCounter metrics.Counter
routerReqDurationHistogram ScalableHistogram
routerOpenConnsGauge metrics.Gauge
serviceReqsCounter metrics.Counter serviceReqsCounter metrics.Counter
serviceReqsTLSCounter metrics.Counter serviceReqsTLSCounter metrics.Counter
serviceReqDurationHistogram ScalableHistogram serviceReqDurationHistogram ScalableHistogram
@ -158,6 +192,10 @@ func (r *standardRegistry) IsEpEnabled() bool {
return r.epEnabled return r.epEnabled
} }
func (r *standardRegistry) IsRouterEnabled() bool {
return r.routerEnabled
}
func (r *standardRegistry) IsSvcEnabled() bool { func (r *standardRegistry) IsSvcEnabled() bool {
return r.svcEnabled return r.svcEnabled
} }
@ -198,6 +236,22 @@ func (r *standardRegistry) EntryPointOpenConnsGauge() metrics.Gauge {
return r.entryPointOpenConnsGauge return r.entryPointOpenConnsGauge
} }
func (r *standardRegistry) RouterReqsCounter() metrics.Counter {
return r.routerReqsCounter
}
func (r *standardRegistry) RouterReqsTLSCounter() metrics.Counter {
return r.routerReqsTLSCounter
}
func (r *standardRegistry) RouterReqDurationHistogram() ScalableHistogram {
return r.routerReqDurationHistogram
}
func (r *standardRegistry) RouterOpenConnsGauge() metrics.Gauge {
return r.routerOpenConnsGauge
}
func (r *standardRegistry) ServiceReqsCounter() metrics.Counter { func (r *standardRegistry) ServiceReqsCounter() metrics.Counter {
return r.serviceReqsCounter return r.serviceReqsCounter
} }

View file

@ -40,16 +40,21 @@ const (
entryPointReqDurationName = metricEntryPointPrefix + "request_duration_seconds" entryPointReqDurationName = metricEntryPointPrefix + "request_duration_seconds"
entryPointOpenConnsName = metricEntryPointPrefix + "open_connections" entryPointOpenConnsName = metricEntryPointPrefix + "open_connections"
// service level. // router level.
metricRouterPrefix = MetricNamePrefix + "router_"
routerReqsTotalName = metricRouterPrefix + "requests_total"
routerReqsTLSTotalName = metricRouterPrefix + "requests_tls_total"
routerReqDurationName = metricRouterPrefix + "request_duration_seconds"
routerOpenConnsName = metricRouterPrefix + "open_connections"
// MetricServicePrefix prefix of all service metric names. // service level.
MetricServicePrefix = MetricNamePrefix + "service_" metricServicePrefix = MetricNamePrefix + "service_"
serviceReqsTotalName = MetricServicePrefix + "requests_total" serviceReqsTotalName = metricServicePrefix + "requests_total"
serviceReqsTLSTotalName = MetricServicePrefix + "requests_tls_total" serviceReqsTLSTotalName = metricServicePrefix + "requests_tls_total"
serviceReqDurationName = MetricServicePrefix + "request_duration_seconds" serviceReqDurationName = metricServicePrefix + "request_duration_seconds"
serviceOpenConnsName = MetricServicePrefix + "open_connections" serviceOpenConnsName = metricServicePrefix + "open_connections"
serviceRetriesTotalName = MetricServicePrefix + "retries_total" serviceRetriesTotalName = metricServicePrefix + "retries_total"
serviceServerUpName = MetricServicePrefix + "server_up" serviceServerUpName = metricServicePrefix + "server_up"
) )
// promState holds all metric state internally and acts as the only Collector we register for Prometheus. // promState holds all metric state internally and acts as the only Collector we register for Prometheus.
@ -140,6 +145,7 @@ func initStandardRegistry(config *types.Prometheus) Registry {
reg := &standardRegistry{ reg := &standardRegistry{
epEnabled: config.AddEntryPointsLabels, epEnabled: config.AddEntryPointsLabels,
routerEnabled: config.AddRoutersLabels,
svcEnabled: config.AddServicesLabels, svcEnabled: config.AddServicesLabels,
configReloadsCounter: configReloads, configReloadsCounter: configReloads,
configReloadsFailureCounter: configReloadsFailures, configReloadsFailureCounter: configReloadsFailures,
@ -180,6 +186,37 @@ func initStandardRegistry(config *types.Prometheus) Registry {
reg.entryPointOpenConnsGauge = entryPointOpenConns reg.entryPointOpenConnsGauge = entryPointOpenConns
} }
if config.AddRoutersLabels {
routerReqs := newCounterFrom(promState.collectors, stdprometheus.CounterOpts{
Name: routerReqsTotalName,
Help: "How many HTTP requests are processed on a router, partitioned by service, status code, protocol, and method.",
}, []string{"code", "method", "protocol", "router", "service"})
routerReqsTLS := newCounterFrom(promState.collectors, stdprometheus.CounterOpts{
Name: routerReqsTLSTotalName,
Help: "How many HTTP requests with TLS are processed on a router, partitioned by service, TLS Version, and TLS cipher Used.",
}, []string{"tls_version", "tls_cipher", "router", "service"})
routerReqDurations := newHistogramFrom(promState.collectors, stdprometheus.HistogramOpts{
Name: routerReqDurationName,
Help: "How long it took to process the request on a router, partitioned by service, status code, protocol, and method.",
Buckets: buckets,
}, []string{"code", "method", "protocol", "router", "service"})
routerOpenConns := newGaugeFrom(promState.collectors, stdprometheus.GaugeOpts{
Name: routerOpenConnsName,
Help: "How many open connections exist on a router, partitioned by service, method, and protocol.",
}, []string{"method", "protocol", "router", "service"})
promState.describers = append(promState.describers, []func(chan<- *stdprometheus.Desc){
routerReqs.cv.Describe,
routerReqsTLS.cv.Describe,
routerReqDurations.hv.Describe,
routerOpenConns.gv.Describe,
}...)
reg.routerReqsCounter = routerReqs
reg.routerReqsTLSCounter = routerReqsTLS
reg.routerReqDurationHistogram, _ = NewHistogramWithScale(routerReqDurations, time.Second)
reg.routerOpenConnsGauge = routerOpenConns
}
if config.AddServicesLabels { if config.AddServicesLabels {
serviceReqs := newCounterFrom(promState.collectors, stdprometheus.CounterOpts{ serviceReqs := newCounterFrom(promState.collectors, stdprometheus.CounterOpts{
Name: serviceReqsTotalName, Name: serviceReqsTotalName,

View file

@ -104,11 +104,11 @@ func TestPrometheus(t *testing.T) {
// Reset state of global promState. // Reset state of global promState.
defer promState.reset() defer promState.reset()
prometheusRegistry := RegisterPrometheus(context.Background(), &types.Prometheus{AddEntryPointsLabels: true, AddServicesLabels: true}) prometheusRegistry := RegisterPrometheus(context.Background(), &types.Prometheus{AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
defer promRegistry.Unregister(promState) defer promRegistry.Unregister(promState)
if !prometheusRegistry.IsEpEnabled() || !prometheusRegistry.IsSvcEnabled() { if !prometheusRegistry.IsEpEnabled() || !prometheusRegistry.IsRouterEnabled() || !prometheusRegistry.IsSvcEnabled() {
t.Errorf("PrometheusRegistry should return true for IsEnabled()") t.Errorf("PrometheusRegistry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()")
} }
prometheusRegistry.ConfigReloadsCounter().Add(1) prometheusRegistry.ConfigReloadsCounter().Add(1)
@ -134,10 +134,31 @@ func TestPrometheus(t *testing.T) {
With("method", http.MethodGet, "protocol", "http", "entrypoint", "http"). With("method", http.MethodGet, "protocol", "http", "entrypoint", "http").
Set(1) Set(1)
prometheusRegistry.
RouterReqsCounter().
With("router", "demo", "service", "service1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet, "protocol", "http").
Add(1)
prometheusRegistry.
RouterReqsTLSCounter().
With("router", "demo", "service", "service1", "tls_version", "foo", "tls_cipher", "bar").
Add(1)
prometheusRegistry.
RouterReqDurationHistogram().
With("router", "demo", "service", "service1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet, "protocol", "http").
Observe(10000)
prometheusRegistry.
RouterOpenConnsGauge().
With("router", "demo", "service", "service1", "method", http.MethodGet, "protocol", "http").
Set(1)
prometheusRegistry. prometheusRegistry.
ServiceReqsCounter(). ServiceReqsCounter().
With("service", "service1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet, "protocol", "http"). With("service", "service1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet, "protocol", "http").
Add(1) Add(1)
prometheusRegistry.
ServiceReqsTLSCounter().
With("service", "service1", "tls_version", "foo", "tls_cipher", "bar").
Add(1)
prometheusRegistry. prometheusRegistry.
ServiceReqDurationHistogram(). ServiceReqDurationHistogram().
With("service", "service1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet, "protocol", "http"). With("service", "service1", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet, "protocol", "http").
@ -218,6 +239,48 @@ func TestPrometheus(t *testing.T) {
}, },
assert: buildGaugeAssert(t, entryPointOpenConnsName, 1), assert: buildGaugeAssert(t, entryPointOpenConnsName, 1),
}, },
{
name: routerReqsTotalName,
labels: map[string]string{
"code": "200",
"method": http.MethodGet,
"protocol": "http",
"service": "service1",
"router": "demo",
},
assert: buildCounterAssert(t, routerReqsTotalName, 1),
},
{
name: routerReqsTLSTotalName,
labels: map[string]string{
"service": "service1",
"router": "demo",
"tls_version": "foo",
"tls_cipher": "bar",
},
assert: buildCounterAssert(t, routerReqsTLSTotalName, 1),
},
{
name: routerReqDurationName,
labels: map[string]string{
"code": "200",
"method": http.MethodGet,
"protocol": "http",
"service": "service1",
"router": "demo",
},
assert: buildHistogramAssert(t, routerReqDurationName, 1),
},
{
name: routerOpenConnsName,
labels: map[string]string{
"method": http.MethodGet,
"protocol": "http",
"service": "service1",
"router": "demo",
},
assert: buildGaugeAssert(t, routerOpenConnsName, 1),
},
{ {
name: serviceReqsTotalName, name: serviceReqsTotalName,
labels: map[string]string{ labels: map[string]string{
@ -228,6 +291,15 @@ func TestPrometheus(t *testing.T) {
}, },
assert: buildCounterAssert(t, serviceReqsTotalName, 1), assert: buildCounterAssert(t, serviceReqsTotalName, 1),
}, },
{
name: serviceReqsTLSTotalName,
labels: map[string]string{
"service": "service1",
"tls_version": "foo",
"tls_cipher": "bar",
},
assert: buildCounterAssert(t, serviceReqsTLSTotalName, 1),
},
{ {
name: serviceReqDurationName, name: serviceReqDurationName,
labels: map[string]string{ labels: map[string]string{

View file

@ -17,19 +17,29 @@ var (
) )
const ( const (
statsdMetricsServiceReqsName = "service.request.total" statsdConfigReloadsName = "config.reload.total"
statsdMetricsServiceLatencyName = "service.request.duration" statsdConfigReloadsFailureName = statsdConfigReloadsName + ".failure"
statsdRetriesTotalName = "service.retries.total" statsdLastConfigReloadSuccessName = "config.reload.lastSuccessTimestamp"
statsdConfigReloadsName = "config.reload.total" statsdLastConfigReloadFailureName = "config.reload.lastFailureTimestamp"
statsdConfigReloadsFailureName = statsdConfigReloadsName + ".failure"
statsdLastConfigReloadSuccessName = "config.reload.lastSuccessTimestamp"
statsdLastConfigReloadFailureName = "config.reload.lastFailureTimestamp"
statsdEntryPointReqsName = "entrypoint.request.total"
statsdEntryPointReqDurationName = "entrypoint.request.duration"
statsdEntryPointOpenConnsName = "entrypoint.connections.open"
statsdOpenConnsName = "service.connections.open"
statsdServerUpName = "service.server.up"
statsdTLSCertsNotAfterTimestampName = "tls.certs.notAfterTimestamp" statsdTLSCertsNotAfterTimestampName = "tls.certs.notAfterTimestamp"
statsdEntryPointReqsName = "entrypoint.request.total"
statsdEntryPointReqsTLSName = "entrypoint.request.tls.total"
statsdEntryPointReqDurationName = "entrypoint.request.duration"
statsdEntryPointOpenConnsName = "entrypoint.connections.open"
statsdRouterReqsName = "router.request.total"
statsdRouterReqsTLSName = "router.request.tls.total"
statsdRouterReqsDurationName = "router.request.duration"
statsdRouterOpenConnsName = "router.connections.open"
statsdServiceReqsName = "service.request.total"
statsdServiceReqsTLSName = "service.request.tls.total"
statsdServiceReqsDurationName = "service.request.duration"
statsdServiceRetriesTotalName = "service.retries.total"
statsdServiceServerUpName = "service.server.up"
statsdServiceOpenConnsName = "service.connections.open"
) )
// RegisterStatsd registers the metrics pusher if this didn't happen yet and creates a statsd Registry instance. // RegisterStatsd registers the metrics pusher if this didn't happen yet and creates a statsd Registry instance.
@ -59,17 +69,27 @@ func RegisterStatsd(ctx context.Context, config *types.Statsd) Registry {
if config.AddEntryPointsLabels { if config.AddEntryPointsLabels {
registry.epEnabled = config.AddEntryPointsLabels registry.epEnabled = config.AddEntryPointsLabels
registry.entryPointReqsCounter = statsdClient.NewCounter(statsdEntryPointReqsName, 1.0) registry.entryPointReqsCounter = statsdClient.NewCounter(statsdEntryPointReqsName, 1.0)
registry.entryPointReqsTLSCounter = statsdClient.NewCounter(statsdEntryPointReqsTLSName, 1.0)
registry.entryPointReqDurationHistogram, _ = NewHistogramWithScale(statsdClient.NewTiming(statsdEntryPointReqDurationName, 1.0), time.Millisecond) registry.entryPointReqDurationHistogram, _ = NewHistogramWithScale(statsdClient.NewTiming(statsdEntryPointReqDurationName, 1.0), time.Millisecond)
registry.entryPointOpenConnsGauge = statsdClient.NewGauge(statsdEntryPointOpenConnsName) registry.entryPointOpenConnsGauge = statsdClient.NewGauge(statsdEntryPointOpenConnsName)
} }
if config.AddRoutersLabels {
registry.routerEnabled = config.AddRoutersLabels
registry.routerReqsCounter = statsdClient.NewCounter(statsdRouterReqsName, 1.0)
registry.routerReqsTLSCounter = statsdClient.NewCounter(statsdRouterReqsTLSName, 1.0)
registry.routerReqDurationHistogram, _ = NewHistogramWithScale(statsdClient.NewTiming(statsdRouterReqsDurationName, 1.0), time.Millisecond)
registry.routerOpenConnsGauge = statsdClient.NewGauge(statsdRouterOpenConnsName)
}
if config.AddServicesLabels { if config.AddServicesLabels {
registry.svcEnabled = config.AddServicesLabels registry.svcEnabled = config.AddServicesLabels
registry.serviceReqsCounter = statsdClient.NewCounter(statsdMetricsServiceReqsName, 1.0) registry.serviceReqsCounter = statsdClient.NewCounter(statsdServiceReqsName, 1.0)
registry.serviceReqDurationHistogram, _ = NewHistogramWithScale(statsdClient.NewTiming(statsdMetricsServiceLatencyName, 1.0), time.Millisecond) registry.serviceReqsTLSCounter = statsdClient.NewCounter(statsdServiceReqsTLSName, 1.0)
registry.serviceRetriesCounter = statsdClient.NewCounter(statsdRetriesTotalName, 1.0) registry.serviceReqDurationHistogram, _ = NewHistogramWithScale(statsdClient.NewTiming(statsdServiceReqsDurationName, 1.0), time.Millisecond)
registry.serviceOpenConnsGauge = statsdClient.NewGauge(statsdOpenConnsName) registry.serviceRetriesCounter = statsdClient.NewCounter(statsdServiceRetriesTotalName, 1.0)
registry.serviceServerUpGauge = statsdClient.NewGauge(statsdServerUpName) registry.serviceOpenConnsGauge = statsdClient.NewGauge(statsdServiceOpenConnsName)
registry.serviceServerUpGauge = statsdClient.NewGauge(statsdServiceServerUpName)
} }
return registry return registry

View file

@ -13,85 +13,96 @@ import (
) )
func TestStatsD(t *testing.T) { func TestStatsD(t *testing.T) {
t.Cleanup(func() {
StopStatsd()
})
udp.SetAddr(":18125") udp.SetAddr(":18125")
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond // This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
udp.Timeout = 5 * time.Second udp.Timeout = 5 * time.Second
statsdRegistry := RegisterStatsd(context.Background(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddServicesLabels: true}) statsdRegistry := RegisterStatsd(context.Background(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
defer StopStatsd()
if !statsdRegistry.IsEpEnabled() || !statsdRegistry.IsSvcEnabled() { testRegistry(t, "", statsdRegistry)
t.Errorf("Statsd registry should return true for IsEnabled()")
}
expected := []string{
// We are only validating counts, as it is nearly impossible to validate latency, since it varies every run
"traefik.service.request.total:2.000000|c\n",
"traefik.service.retries.total:2.000000|c\n",
"traefik.service.request.duration:10000.000000|ms",
"traefik.config.reload.total:1.000000|c\n",
"traefik.config.reload.total:1.000000|c\n",
"traefik.entrypoint.request.total:1.000000|c\n",
"traefik.entrypoint.request.duration:10000.000000|ms",
"traefik.entrypoint.connections.open:1.000000|g\n",
"traefik.service.server.up:1.000000|g\n",
"tls.certs.notAfterTimestamp:1.000000|g\n",
}
udp.ShouldReceiveAll(t, expected, func() {
statsdRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
statsdRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
statsdRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
statsdRegistry.ServiceRetriesCounter().With("service", "test").Add(1)
statsdRegistry.ServiceReqDurationHistogram().With("service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
statsdRegistry.ConfigReloadsCounter().Add(1)
statsdRegistry.ConfigReloadsFailureCounter().Add(1)
statsdRegistry.EntryPointReqsCounter().With("entrypoint", "test").Add(1)
statsdRegistry.EntryPointReqDurationHistogram().With("entrypoint", "test").Observe(10000)
statsdRegistry.EntryPointOpenConnsGauge().With("entrypoint", "test").Set(1)
statsdRegistry.ServiceServerUpGauge().With("service:test", "url", "http://127.0.0.1").Set(1)
statsdRegistry.TLSCertsNotAfterTimestampGauge().With("key", "value").Set(1)
})
} }
func TestStatsDWithPrefix(t *testing.T) { func TestStatsDWithPrefix(t *testing.T) {
t.Cleanup(func() {
StopStatsd()
})
udp.SetAddr(":18125") udp.SetAddr(":18125")
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond // This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
udp.Timeout = 5 * time.Second udp.Timeout = 5 * time.Second
statsdRegistry := RegisterStatsd(context.Background(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddServicesLabels: true, Prefix: "testPrefix"}) statsdRegistry := RegisterStatsd(context.Background(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true, Prefix: "testPrefix"})
defer StopStatsd()
if !statsdRegistry.IsEpEnabled() || !statsdRegistry.IsSvcEnabled() { testRegistry(t, "testPrefix", statsdRegistry)
t.Errorf("Statsd registry should return true for IsEnabled()") }
func testRegistry(t *testing.T, metricsPrefix string, registry Registry) {
t.Helper()
if !registry.IsEpEnabled() || !registry.IsRouterEnabled() || !registry.IsSvcEnabled() {
t.Errorf("Statsd registry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()")
}
if metricsPrefix == "" {
metricsPrefix = "traefik"
} }
expected := []string{ expected := []string{
// We are only validating counts, as it is nearly impossible to validate latency, since it varies every run metricsPrefix + ".config.reload.total:1.000000|c\n",
"testPrefix.service.request.total:2.000000|c\n", metricsPrefix + ".config.reload.total.failure:1.000000|c\n",
"testPrefix.service.retries.total:2.000000|c\n", metricsPrefix + ".config.reload.lastSuccessTimestamp:1.000000|g\n",
"testPrefix.service.request.duration:10000.000000|ms", metricsPrefix + ".config.reload.lastFailureTimestamp:1.000000|g\n",
"testPrefix.config.reload.total:1.000000|c\n",
"testPrefix.config.reload.total:1.000000|c\n", metricsPrefix + ".tls.certs.notAfterTimestamp:1.000000|g\n",
"testPrefix.entrypoint.request.total:1.000000|c\n",
"testPrefix.entrypoint.request.duration:10000.000000|ms", metricsPrefix + ".entrypoint.request.total:1.000000|c\n",
"testPrefix.entrypoint.connections.open:1.000000|g\n", metricsPrefix + ".entrypoint.request.tls.total:1.000000|c\n",
"testPrefix.service.server.up:1.000000|g\n", metricsPrefix + ".entrypoint.request.duration:10000.000000|ms",
"tls.certs.notAfterTimestamp:1.000000|g\n", metricsPrefix + ".entrypoint.connections.open:1.000000|g\n",
metricsPrefix + ".router.request.total:2.000000|c\n",
metricsPrefix + ".router.request.tls.total:1.000000|c\n",
metricsPrefix + ".router.request.duration:10000.000000|ms",
metricsPrefix + ".router.connections.open:1.000000|g\n",
metricsPrefix + ".service.request.total:2.000000|c\n",
metricsPrefix + ".service.request.tls.total:1.000000|c\n",
metricsPrefix + ".service.request.duration:10000.000000|ms",
metricsPrefix + ".service.connections.open:1.000000|g\n",
metricsPrefix + ".service.retries.total:2.000000|c\n",
metricsPrefix + ".service.server.up:1.000000|g\n",
} }
udp.ShouldReceiveAll(t, expected, func() { udp.ShouldReceiveAll(t, expected, func() {
statsdRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1) registry.ConfigReloadsCounter().Add(1)
statsdRegistry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1) registry.ConfigReloadsFailureCounter().Add(1)
statsdRegistry.ServiceRetriesCounter().With("service", "test").Add(1) registry.LastConfigReloadSuccessGauge().Set(1)
statsdRegistry.ServiceRetriesCounter().With("service", "test").Add(1) registry.LastConfigReloadFailureGauge().Set(1)
statsdRegistry.ServiceReqDurationHistogram().With("service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
statsdRegistry.ConfigReloadsCounter().Add(1) registry.TLSCertsNotAfterTimestampGauge().With("key", "value").Set(1)
statsdRegistry.ConfigReloadsFailureCounter().Add(1)
statsdRegistry.EntryPointReqsCounter().With("entrypoint", "test").Add(1) registry.EntryPointReqsCounter().With("entrypoint", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
statsdRegistry.EntryPointReqDurationHistogram().With("entrypoint", "test").Observe(10000) registry.EntryPointReqsTLSCounter().With("entrypoint", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
statsdRegistry.EntryPointOpenConnsGauge().With("entrypoint", "test").Set(1) registry.EntryPointReqDurationHistogram().With("entrypoint", "test").Observe(10000)
statsdRegistry.ServiceServerUpGauge().With("service:test", "url", "http://127.0.0.1").Set(1) registry.EntryPointOpenConnsGauge().With("entrypoint", "test").Set(1)
statsdRegistry.TLSCertsNotAfterTimestampGauge().With("key", "value").Set(1)
registry.RouterReqsCounter().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
registry.RouterReqsCounter().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
registry.RouterReqsTLSCounter().With("router", "demo", "service", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
registry.RouterReqDurationHistogram().With("router", "demo", "service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
registry.RouterOpenConnsGauge().With("router", "demo", "service", "test").Set(1)
registry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusOK), "method", http.MethodGet).Add(1)
registry.ServiceReqsCounter().With("service", "test", "code", strconv.Itoa(http.StatusNotFound), "method", http.MethodGet).Add(1)
registry.ServiceReqsTLSCounter().With("service", "test", "tls_version", "foo", "tls_cipher", "bar").Add(1)
registry.ServiceReqDurationHistogram().With("service", "test", "code", strconv.Itoa(http.StatusOK)).Observe(10000)
registry.ServiceOpenConnsGauge().With("service", "test").Set(1)
registry.ServiceRetriesCounter().With("service", "test").Add(1)
registry.ServiceRetriesCounter().With("service", "test").Add(1)
registry.ServiceServerUpGauge().With("service:test", "url", "http://127.0.0.1").Set(1)
}) })
} }

View file

@ -49,6 +49,20 @@ func NewEntryPointMiddleware(ctx context.Context, next http.Handler, registry me
} }
} }
// NewRouterMiddleware creates a new metrics middleware for a Router.
func NewRouterMiddleware(ctx context.Context, next http.Handler, registry metrics.Registry, routerName string, serviceName string) http.Handler {
log.FromContext(middlewares.GetLoggerCtx(ctx, nameEntrypoint, typeName)).Debug("Creating middleware")
return &metricsMiddleware{
next: next,
reqsCounter: registry.RouterReqsCounter(),
reqsTLSCounter: registry.RouterReqsTLSCounter(),
reqDurationHistogram: registry.RouterReqDurationHistogram(),
openConnsGauge: registry.RouterOpenConnsGauge(),
baseLabels: []string{"router", routerName, "service", serviceName},
}
}
// NewServiceMiddleware creates a new metrics middleware for a Service. // NewServiceMiddleware creates a new metrics middleware for a Service.
func NewServiceMiddleware(ctx context.Context, next http.Handler, registry metrics.Registry, serviceName string) http.Handler { func NewServiceMiddleware(ctx context.Context, next http.Handler, registry metrics.Registry, serviceName string) http.Handler {
log.FromContext(middlewares.GetLoggerCtx(ctx, nameService, typeName)).Debug("Creating middleware") log.FromContext(middlewares.GetLoggerCtx(ctx, nameService, typeName)).Debug("Creating middleware")
@ -70,6 +84,13 @@ func WrapEntryPointHandler(ctx context.Context, registry metrics.Registry, entry
} }
} }
// WrapRouterHandler Wraps metrics router to alice.Constructor.
func WrapRouterHandler(ctx context.Context, registry metrics.Registry, routerName string, serviceName string) alice.Constructor {
return func(next http.Handler) (http.Handler, error) {
return NewRouterMiddleware(ctx, next, registry, routerName, serviceName), nil
}
}
// WrapServiceHandler Wraps metrics service to alice.Constructor. // WrapServiceHandler Wraps metrics service to alice.Constructor.
func WrapServiceHandler(ctx context.Context, registry metrics.Registry, serviceName string) alice.Constructor { func WrapServiceHandler(ctx context.Context, registry metrics.Registry, serviceName string) alice.Constructor {
return func(next http.Handler) (http.Handler, error) { return func(next http.Handler) (http.Handler, error) {

View file

@ -8,7 +8,9 @@ import (
"github.com/containous/alice" "github.com/containous/alice"
"github.com/traefik/traefik/v2/pkg/config/runtime" "github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/log" "github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/metrics"
"github.com/traefik/traefik/v2/pkg/middlewares/accesslog" "github.com/traefik/traefik/v2/pkg/middlewares/accesslog"
metricsMiddle "github.com/traefik/traefik/v2/pkg/middlewares/metrics"
"github.com/traefik/traefik/v2/pkg/middlewares/recovery" "github.com/traefik/traefik/v2/pkg/middlewares/recovery"
"github.com/traefik/traefik/v2/pkg/middlewares/tracing" "github.com/traefik/traefik/v2/pkg/middlewares/tracing"
"github.com/traefik/traefik/v2/pkg/rules" "github.com/traefik/traefik/v2/pkg/rules"
@ -29,16 +31,18 @@ type serviceManager interface {
type Manager struct { type Manager struct {
routerHandlers map[string]http.Handler routerHandlers map[string]http.Handler
serviceManager serviceManager serviceManager serviceManager
metricsRegistry metrics.Registry
middlewaresBuilder middlewareBuilder middlewaresBuilder middlewareBuilder
chainBuilder *middleware.ChainBuilder chainBuilder *middleware.ChainBuilder
conf *runtime.Configuration conf *runtime.Configuration
} }
// NewManager Creates a new Manager. // NewManager Creates a new Manager.
func NewManager(conf *runtime.Configuration, serviceManager serviceManager, middlewaresBuilder middlewareBuilder, chainBuilder *middleware.ChainBuilder) *Manager { func NewManager(conf *runtime.Configuration, serviceManager serviceManager, middlewaresBuilder middlewareBuilder, chainBuilder *middleware.ChainBuilder, metricsRegistry metrics.Registry) *Manager {
return &Manager{ return &Manager{
routerHandlers: make(map[string]http.Handler), routerHandlers: make(map[string]http.Handler),
serviceManager: serviceManager, serviceManager: serviceManager,
metricsRegistry: metricsRegistry,
middlewaresBuilder: middlewaresBuilder, middlewaresBuilder: middlewaresBuilder,
chainBuilder: chainBuilder, chainBuilder: chainBuilder,
conf: conf, conf: conf,
@ -177,7 +181,13 @@ func (m *Manager) buildHTTPHandler(ctx context.Context, router *runtime.RouterIn
return tracing.NewForwarder(ctx, routerName, router.Service, next), nil return tracing.NewForwarder(ctx, routerName, router.Service, next), nil
} }
return alice.New().Extend(*mHandler).Append(tHandler).Then(sHandler) chain := alice.New()
if m.metricsRegistry != nil && m.metricsRegistry.IsRouterEnabled() {
chain = chain.Append(metricsMiddle.WrapRouterHandler(ctx, m.metricsRegistry, routerName, router.Service))
}
return chain.Extend(*mHandler).Append(tHandler).Then(sHandler)
} }
// BuildDefaultHTTPRouter creates a default HTTP router. // BuildDefaultHTTPRouter creates a default HTTP router.

View file

@ -13,6 +13,7 @@ import (
"github.com/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/config/runtime" "github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/config/static" "github.com/traefik/traefik/v2/pkg/config/static"
"github.com/traefik/traefik/v2/pkg/metrics"
"github.com/traefik/traefik/v2/pkg/middlewares/accesslog" "github.com/traefik/traefik/v2/pkg/middlewares/accesslog"
"github.com/traefik/traefik/v2/pkg/middlewares/requestdecorator" "github.com/traefik/traefik/v2/pkg/middlewares/requestdecorator"
"github.com/traefik/traefik/v2/pkg/server/middleware" "github.com/traefik/traefik/v2/pkg/server/middleware"
@ -316,7 +317,7 @@ func TestRouterManager_Get(t *testing.T) {
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil) middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil) chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder) routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry())
handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false) handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false)
@ -422,7 +423,7 @@ func TestAccessLog(t *testing.T) {
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil) middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil) chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder) routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry())
handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false) handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false)
@ -711,7 +712,7 @@ func TestRuntimeConfiguration(t *testing.T) {
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil) middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil) chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder) routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry())
_ = routerManager.BuildHandlers(context.Background(), entryPoints, false) _ = routerManager.BuildHandlers(context.Background(), entryPoints, false)
@ -794,7 +795,7 @@ func TestProviderOnMiddlewares(t *testing.T) {
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil) middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
chainBuilder := middleware.NewChainBuilder(staticCfg, nil, nil) chainBuilder := middleware.NewChainBuilder(staticCfg, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder) routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry())
_ = routerManager.BuildHandlers(context.Background(), entryPoints, false) _ = routerManager.BuildHandlers(context.Background(), entryPoints, false)
@ -862,7 +863,7 @@ func BenchmarkRouterServe(b *testing.B) {
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil) middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil) chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder) routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry())
handlers := routerManager.BuildHandlers(context.Background(), entryPoints, false) handlers := routerManager.BuildHandlers(context.Background(), entryPoints, false)

View file

@ -6,6 +6,7 @@ import (
"github.com/traefik/traefik/v2/pkg/config/runtime" "github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/config/static" "github.com/traefik/traefik/v2/pkg/config/static"
"github.com/traefik/traefik/v2/pkg/log" "github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/metrics"
"github.com/traefik/traefik/v2/pkg/server/middleware" "github.com/traefik/traefik/v2/pkg/server/middleware"
"github.com/traefik/traefik/v2/pkg/server/router" "github.com/traefik/traefik/v2/pkg/server/router"
routertcp "github.com/traefik/traefik/v2/pkg/server/router/tcp" routertcp "github.com/traefik/traefik/v2/pkg/server/router/tcp"
@ -23,7 +24,8 @@ type RouterFactory struct {
entryPointsTCP []string entryPointsTCP []string
entryPointsUDP []string entryPointsUDP []string
managerFactory *service.ManagerFactory managerFactory *service.ManagerFactory
metricsRegistry metrics.Registry
pluginBuilder middleware.PluginsBuilder pluginBuilder middleware.PluginsBuilder
@ -32,7 +34,8 @@ type RouterFactory struct {
} }
// NewRouterFactory creates a new RouterFactory. // NewRouterFactory creates a new RouterFactory.
func NewRouterFactory(staticConfiguration static.Configuration, managerFactory *service.ManagerFactory, tlsManager *tls.Manager, chainBuilder *middleware.ChainBuilder, pluginBuilder middleware.PluginsBuilder) *RouterFactory { func NewRouterFactory(staticConfiguration static.Configuration, managerFactory *service.ManagerFactory, tlsManager *tls.Manager,
chainBuilder *middleware.ChainBuilder, pluginBuilder middleware.PluginsBuilder, metricsRegistry metrics.Registry) *RouterFactory {
var entryPointsTCP, entryPointsUDP []string var entryPointsTCP, entryPointsUDP []string
for name, cfg := range staticConfiguration.EntryPoints { for name, cfg := range staticConfiguration.EntryPoints {
protocol, err := cfg.GetProtocol() protocol, err := cfg.GetProtocol()
@ -49,12 +52,13 @@ func NewRouterFactory(staticConfiguration static.Configuration, managerFactory *
} }
return &RouterFactory{ return &RouterFactory{
entryPointsTCP: entryPointsTCP, entryPointsTCP: entryPointsTCP,
entryPointsUDP: entryPointsUDP, entryPointsUDP: entryPointsUDP,
managerFactory: managerFactory, managerFactory: managerFactory,
tlsManager: tlsManager, metricsRegistry: metricsRegistry,
chainBuilder: chainBuilder, tlsManager: tlsManager,
pluginBuilder: pluginBuilder, chainBuilder: chainBuilder,
pluginBuilder: pluginBuilder,
} }
} }
@ -67,7 +71,7 @@ func (f *RouterFactory) CreateRouters(rtConf *runtime.Configuration) (map[string
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, f.pluginBuilder) middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, f.pluginBuilder)
routerManager := router.NewManager(rtConf, serviceManager, middlewaresBuilder, f.chainBuilder) routerManager := router.NewManager(rtConf, serviceManager, middlewaresBuilder, f.chainBuilder, f.metricsRegistry)
handlersNonTLS := routerManager.BuildHandlers(ctx, f.entryPointsTCP, false) handlersNonTLS := routerManager.BuildHandlers(ctx, f.entryPointsTCP, false)
handlersTLS := routerManager.BuildHandlers(ctx, f.entryPointsTCP, true) handlersTLS := routerManager.BuildHandlers(ctx, f.entryPointsTCP, true)

View file

@ -53,7 +53,7 @@ func TestReuseService(t *testing.T) {
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil) managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
tlsManager := tls.NewManager() tlsManager := tls.NewManager()
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(staticConfig, metrics.NewVoidRegistry(), nil), nil) factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(staticConfig, metrics.NewVoidRegistry(), nil), nil, metrics.NewVoidRegistry())
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: dynamicConfigs})) entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: dynamicConfigs}))
@ -189,7 +189,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil) managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
tlsManager := tls.NewManager() tlsManager := tls.NewManager()
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(staticConfig, metrics.NewVoidRegistry(), nil), nil) factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(staticConfig, metrics.NewVoidRegistry(), nil), nil, metrics.NewVoidRegistry())
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: test.config(testServer.URL)})) entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: test.config(testServer.URL)}))
@ -230,7 +230,9 @@ func TestInternalServices(t *testing.T) {
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil) managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
tlsManager := tls.NewManager() tlsManager := tls.NewManager()
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(staticConfig, metrics.NewVoidRegistry(), nil), nil) voidRegistry := metrics.NewVoidRegistry()
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(staticConfig, voidRegistry, nil), nil, voidRegistry)
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: dynamicConfigs})) entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: dynamicConfigs}))

View file

@ -20,6 +20,7 @@ type Metrics struct {
type Prometheus struct { type Prometheus struct {
Buckets []float64 `description:"Buckets for latency metrics." json:"buckets,omitempty" toml:"buckets,omitempty" yaml:"buckets,omitempty" export:"true"` Buckets []float64 `description:"Buckets for latency metrics." json:"buckets,omitempty" toml:"buckets,omitempty" yaml:"buckets,omitempty" export:"true"`
AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"` AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"`
AddRoutersLabels bool `description:"Enable metrics on routers." json:"addRoutersLabels,omitempty" toml:"addRoutersLabels,omitempty" yaml:"addRoutersLabels,omitempty" export:"true"`
AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"` AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"`
EntryPoint string `description:"EntryPoint" export:"true" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"` EntryPoint string `description:"EntryPoint" export:"true" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
ManualRouting bool `description:"Manual routing" json:"manualRouting,omitempty" toml:"manualRouting,omitempty" yaml:"manualRouting,omitempty" export:"true"` ManualRouting bool `description:"Manual routing" json:"manualRouting,omitempty" toml:"manualRouting,omitempty" yaml:"manualRouting,omitempty" export:"true"`
@ -38,6 +39,7 @@ type Datadog struct {
Address string `description:"Datadog's address." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"` Address string `description:"Datadog's address." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
PushInterval types.Duration `description:"Datadog push interval." json:"pushInterval,omitempty" toml:"pushInterval,omitempty" yaml:"pushInterval,omitempty" export:"true"` PushInterval types.Duration `description:"Datadog push interval." json:"pushInterval,omitempty" toml:"pushInterval,omitempty" yaml:"pushInterval,omitempty" export:"true"`
AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"` AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"`
AddRoutersLabels bool `description:"Enable metrics on routers." json:"addRoutersLabels,omitempty" toml:"addRoutersLabels,omitempty" yaml:"addRoutersLabels,omitempty" export:"true"`
AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"` AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"`
} }
@ -63,6 +65,7 @@ type Statsd struct {
Address string `description:"StatsD address." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"` Address string `description:"StatsD address." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
PushInterval types.Duration `description:"StatsD push interval." json:"pushInterval,omitempty" toml:"pushInterval,omitempty" yaml:"pushInterval,omitempty" export:"true"` PushInterval types.Duration `description:"StatsD push interval." json:"pushInterval,omitempty" toml:"pushInterval,omitempty" yaml:"pushInterval,omitempty" export:"true"`
AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"` AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"`
AddRoutersLabels bool `description:"Enable metrics on routers." json:"addRoutersLabels,omitempty" toml:"addRoutersLabels,omitempty" yaml:"addRoutersLabels,omitempty" export:"true"`
AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"` AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"`
Prefix string `description:"Prefix to use for metrics collection." json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"` Prefix string `description:"Prefix to use for metrics collection." json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"`
} }
@ -86,6 +89,7 @@ type InfluxDB struct {
Username string `description:"InfluxDB username (only with http)." json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty"` Username string `description:"InfluxDB username (only with http)." json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty"`
Password string `description:"InfluxDB password (only with http)." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty"` Password string `description:"InfluxDB password (only with http)." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty"`
AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"` AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"`
AddRoutersLabels bool `description:"Enable metrics on routers." json:"addRoutersLabels,omitempty" toml:"addRoutersLabels,omitempty" yaml:"addRoutersLabels,omitempty" export:"true"`
AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"` AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"`
} }