Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to map measurement names to field name into prometheus input #3407

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions plugins/inputs/prometheus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ in Prometheus format.
## Use bearer token for authorization
# bearer_token = /path/to/bearer/token

# measurement_name_as_field_name = true

## Specify timeout duration for slower prometheus clients (default is 3s)
# response_timeout = "3s"

Expand All @@ -43,6 +45,25 @@ If set, the file specified by the `bearer_token` parameter will be read on
each interval and its contents will be appended to the Bearer string in the
Authorization header.


### Measurement Name as Field Name

If `measurement_name_as_field_name` set, output metric fields will use measurement as name instead of `gauge`,
`counter` etc. This is useful for example in the case when you want to map all
metrics under single measurement using `name_override` and still be able to separate
metrics.

#### Example of output using `measurement_name_as_field_name`
**Source**
```
cpu_usage_user{cpu="cpu3"} 1.5045135406226022
```
**Output**
```
cpu_usage_user,cpu=cpu3,url=http://example.org:9273/metrics cpu_usage_user=1.5228426395944945 1505776751000000000
```


### Usage for Caddy HTTP server

If you want to monitor Caddy, you need to use Caddy with its Prometheus plugin:
Expand Down
23 changes: 17 additions & 6 deletions plugins/inputs/prometheus/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ type Prometheus struct {
// An array of Kubernetes services to scrape metrics from.
KubernetesServices []string

// Use measurment name as field name instead of gauge, counter etc.
MeasurementNameAsFieldName bool `toml:"measurement_name_as_field_name"`

// Bearer Token authorization file path
BearerToken string `toml:"bearer_token"`

Expand Down Expand Up @@ -218,18 +221,26 @@ func (p *Prometheus) gatherURL(url UrlAndAddress, acc telegraf.Accumulator) erro
if url.Address != "" {
tags["address"] = url.Address
}

fields := metric.Fields()
if p.MeasurementNameAsFieldName {
newFields := make(map[string]interface{})
for _, v := range fields {
newFields[metric.Name()] = v
break // fields should only contain one metric as per spec
}
fields = newFields
}
switch metric.Type() {
case telegraf.Counter:
acc.AddCounter(metric.Name(), metric.Fields(), tags, metric.Time())
acc.AddCounter(metric.Name(), fields, tags, metric.Time())
case telegraf.Gauge:
acc.AddGauge(metric.Name(), metric.Fields(), tags, metric.Time())
acc.AddGauge(metric.Name(), fields, tags, metric.Time())
case telegraf.Summary:
acc.AddSummary(metric.Name(), metric.Fields(), tags, metric.Time())
acc.AddSummary(metric.Name(), fields, tags, metric.Time())
case telegraf.Histogram:
acc.AddHistogram(metric.Name(), metric.Fields(), tags, metric.Time())
acc.AddHistogram(metric.Name(), fields, tags, metric.Time())
default:
acc.AddFields(metric.Name(), metric.Fields(), tags, metric.Time())
acc.AddFields(metric.Name(), fields, tags, metric.Time())
}
}

Expand Down
26 changes: 26 additions & 0 deletions plugins/inputs/prometheus/prometheus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,32 @@ func TestPrometheusGeneratesMetricsWithHostNameTag(t *testing.T) {
assert.True(t, acc.TagValue("test_metric", "url") == ts.URL)
}

func TestPrometheusGeneratesMetricsWithHostNameTagAndMeasurementNameAsFieldName(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, sampleTextFormat)
}))
defer ts.Close()

p := &Prometheus{
KubernetesServices: []string{ts.URL},
MeasurementNameAsFieldName: true,
}
u, _ := url.Parse(ts.URL)
tsAddress := u.Hostname()

var acc testutil.Accumulator

err := acc.GatherError(p.Gather)
require.NoError(t, err)

assert.True(t, acc.HasFloatField("go_gc_duration_seconds", "go_gc_duration_seconds"))
assert.True(t, acc.HasFloatField("go_goroutines", "go_goroutines"))
assert.True(t, acc.HasFloatField("test_metric", "test_metric"))
assert.True(t, acc.HasTimestamp("test_metric", time.Unix(1490802350, 0)))
assert.True(t, acc.TagValue("test_metric", "address") == tsAddress)
assert.True(t, acc.TagValue("test_metric", "url") == ts.URL)
}

func TestPrometheusGeneratesMetricsAlthoughFirstDNSFails(t *testing.T) {
if testing.Short() {
t.Skip("Skipping integration test in short mode")
Expand Down