From fd98fb144937a7d83d391d10b55910715ddb4da0 Mon Sep 17 00:00:00 2001
From: Pierre Souchay
Date: Fri, 6 Apr 2018 08:55:49 +0200
Subject: [PATCH] Added support exposing metrics in Prometheus format
---
agent/agent_endpoint.go | 12 ++++++++++++
agent/config/builder.go | 1 +
agent/config/config.go | 1 +
agent/config/runtime.go | 5 +++++
agent/config/runtime_test.go | 4 ++++
command/agent/agent.go | 15 +++++++++++++++
6 files changed, 38 insertions(+)
diff --git a/agent/agent_endpoint.go b/agent/agent_endpoint.go
index 0e2b4b4803..5d8970fabd 100644
--- a/agent/agent_endpoint.go
+++ b/agent/agent_endpoint.go
@@ -19,6 +19,8 @@ import (
"github.com/hashicorp/logutils"
"github.com/hashicorp/serf/coordinate"
"github.com/hashicorp/serf/serf"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
)
type Self struct {
@@ -86,7 +88,17 @@ func (s *HTTPServer) AgentMetrics(resp http.ResponseWriter, req *http.Request) (
if rule != nil && !rule.AgentRead(s.agent.config.NodeName) {
return nil, acl.ErrPermissionDenied
}
+ if format := req.URL.Query().Get("format"); format == "prometheus" {
+ handlerOptions := promhttp.HandlerOpts{
+ ErrorLog: s.agent.logger,
+ ErrorHandling: promhttp.ContinueOnError,
+ DisableCompression: true,
+ }
+ handler := promhttp.HandlerFor(prometheus.DefaultGatherer, handlerOptions)
+ handler.ServeHTTP(resp, req)
+ return nil, nil
+ }
return s.agent.MemSink.DisplayMetrics(resp, req)
}
diff --git a/agent/config/builder.go b/agent/config/builder.go
index e9cb19394c..7659180116 100644
--- a/agent/config/builder.go
+++ b/agent/config/builder.go
@@ -626,6 +626,7 @@ func (b *Builder) Build() (rt RuntimeConfig, err error) {
TelemetryDisableHostname: b.boolVal(c.Telemetry.DisableHostname),
TelemetryDogstatsdAddr: b.stringVal(c.Telemetry.DogstatsdAddr),
TelemetryDogstatsdTags: c.Telemetry.DogstatsdTags,
+ TelemetryPrometheusDisable: b.boolVal(c.Telemetry.PrometheusDisable),
TelemetryFilterDefault: b.boolVal(c.Telemetry.FilterDefault),
TelemetryAllowedPrefixes: telemetryAllowedPrefixes,
TelemetryBlockedPrefixes: telemetryBlockedPrefixes,
diff --git a/agent/config/config.go b/agent/config/config.go
index 2a14abc6b8..a481bbf4c9 100644
--- a/agent/config/config.go
+++ b/agent/config/config.go
@@ -394,6 +394,7 @@ type Telemetry struct {
FilterDefault *bool `json:"filter_default,omitempty" hcl:"filter_default" mapstructure:"filter_default"`
PrefixFilter []string `json:"prefix_filter,omitempty" hcl:"prefix_filter" mapstructure:"prefix_filter"`
MetricsPrefix *string `json:"metrics_prefix,omitempty" hcl:"metrics_prefix" mapstructure:"metrics_prefix"`
+ PrometheusDisable *bool `json:"prometheus_disable,omitempty" hcl:"prometheus_disable" mapstructure:"prometheus_disable"`
StatsdAddr *string `json:"statsd_address,omitempty" hcl:"statsd_address" mapstructure:"statsd_address"`
StatsiteAddr *string `json:"statsite_address,omitempty" hcl:"statsite_address" mapstructure:"statsite_address"`
EnableDeprecatedNames *bool `json:"enable_deprecated_names" hcl:"enable_deprecated_names" mapstructure:"enable_deprecated_names"`
diff --git a/agent/config/runtime.go b/agent/config/runtime.go
index f43fac24f1..e1aa1b2ebf 100644
--- a/agent/config/runtime.go
+++ b/agent/config/runtime.go
@@ -425,6 +425,11 @@ type RuntimeConfig struct {
// hcl: telemetry { dogstatsd_tags = []string }
TelemetryDogstatsdTags []string
+ // TelemetryPrometheusDisable enables prometheus Support for metrics
+ //
+ // hcl: telemetry { prometheus_disable = (true|false) }
+ TelemetryPrometheusDisable bool
+
// TelemetryFilterDefault is the default for whether to allow a metric that's not
// covered by the filter.
//
diff --git a/agent/config/runtime_test.go b/agent/config/runtime_test.go
index da62e0339c..e923a14f68 100644
--- a/agent/config/runtime_test.go
+++ b/agent/config/runtime_test.go
@@ -2589,6 +2589,7 @@ func TestFullConfig(t *testing.T) {
"prefix_filter": [ "+oJotS8XJ","-cazlEhGn" ],
"enable_deprecated_names": true,
"metrics_prefix": "ftO6DySn",
+ "prometheus_disable": true,
"statsd_address": "drce87cy",
"statsite_address": "HpFwKB8R"
},
@@ -3026,6 +3027,7 @@ func TestFullConfig(t *testing.T) {
prefix_filter = [ "+oJotS8XJ","-cazlEhGn" ]
enable_deprecated_names = true
metrics_prefix = "ftO6DySn"
+ prometheus_disable = true
statsd_address = "drce87cy"
statsite_address = "HpFwKB8R"
}
@@ -3588,6 +3590,7 @@ func TestFullConfig(t *testing.T) {
TelemetryAllowedPrefixes: []string{"oJotS8XJ", "consul.consul"},
TelemetryBlockedPrefixes: []string{"cazlEhGn"},
TelemetryMetricsPrefix: "ftO6DySn",
+ TelemetryPrometheusDisable: true,
TelemetryStatsdAddr: "drce87cy",
TelemetryStatsiteAddr: "HpFwKB8R",
TLSCipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
@@ -4140,6 +4143,7 @@ func TestSanitize(t *testing.T) {
"TelemetryDogstatsdTags": [],
"TelemetryFilterDefault": false,
"TelemetryMetricsPrefix": "",
+ "TelemetryPrometheusDisable": false,
"TelemetryStatsdAddr": "",
"TelemetryStatsiteAddr": "",
"TranslateWANAddrs": false,
diff --git a/command/agent/agent.go b/command/agent/agent.go
index 40bfbef20c..9e7867c675 100644
--- a/command/agent/agent.go
+++ b/command/agent/agent.go
@@ -15,6 +15,7 @@ import (
"github.com/armon/go-metrics"
"github.com/armon/go-metrics/circonus"
"github.com/armon/go-metrics/datadog"
+ "github.com/armon/go-metrics/prometheus"
"github.com/hashicorp/consul/agent"
"github.com/hashicorp/consul/agent/config"
"github.com/hashicorp/consul/command/flags"
@@ -208,6 +209,17 @@ func dogstatdSink(config *config.RuntimeConfig, hostname string) (metrics.Metric
return sink, nil
}
+func prometheusSink(config *config.RuntimeConfig, hostname string) (metrics.MetricSink, error) {
+ if config.TelemetryPrometheusDisable {
+ return nil, nil
+ }
+ sink, err := prometheus.NewPrometheusSink()
+ if err != nil {
+ return nil, err
+ }
+ return sink, nil
+}
+
func circonusSink(config *config.RuntimeConfig, hostname string) (metrics.MetricSink, error) {
if config.TelemetryCirconusAPIToken == "" && config.TelemetryCirconusSubmissionURL == "" {
return nil, nil
@@ -284,6 +296,9 @@ func startupTelemetry(conf *config.RuntimeConfig) (*metrics.InmemSink, error) {
if err := addSink("circonus", circonusSink); err != nil {
return nil, err
}
+ if err := addSink("prometheus", prometheusSink); err != nil {
+ return nil, err
+ }
if len(sinks) > 0 {
sinks = append(sinks, memSink)