Skip to content

Commit 9778252

Browse files
committed
Update prometheus_client output
Make unregistering collectors a config option (default false to preserve existing behavior) go fmt and add README
1 parent 4e0c8e6 commit 9778252

File tree

3 files changed

+183
-12
lines changed

3 files changed

+183
-12
lines changed

plugins/outputs/prometheus_client/README.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,119 @@ This plugin starts a [Prometheus](https://prometheus.io/) Client, it exposes all
1515
1616
# Expiration interval for each metric. 0 == no expiration
1717
expiration_interval = "60s"
18+
19+
# Unregister internal metrics for prometheus client
20+
# If you plan on using this output along with the prometheus input, this may be necessary to prevent metrics conflicts
21+
unregister_metrics = false
22+
```
23+
24+
## Example
25+
26+
Telegraf inputs values such as:
27+
```
28+
> cpu,cpu=cpu0 usage_user=0,usage_iowait=0,usage_irq=0,usage_guest_nice=0,usage_system=0,usage_idle=100,usage_nice=0,usage_softirq=0,usage_steal=0,usage_guest=0 1507833663000000000
29+
```
30+
will get output in Prometheus exposition format:
31+
```
32+
# HELP cpu_usage_guest Telegraf collected metric
33+
# TYPE cpu_usage_guest gauge
34+
cpu_usage_guest{cpu="cpu0"} 0
35+
# HELP cpu_usage_guest_nice Telegraf collected metric
36+
# TYPE cpu_usage_guest_nice gauge
37+
cpu_usage_guest_nice{cpu="cpu0"} 0
38+
# HELP cpu_usage_idle Telegraf collected metric
39+
# TYPE cpu_usage_idle gauge
40+
cpu_usage_idle{cpu="cpu0"} 99.79939819439636
41+
# HELP cpu_usage_iowait Telegraf collected metric
42+
# TYPE cpu_usage_iowait gauge
43+
cpu_usage_iowait{cpu="cpu0"} 0
44+
# HELP cpu_usage_irq Telegraf collected metric
45+
# TYPE cpu_usage_irq gauge
46+
cpu_usage_irq{cpu="cpu0"} 0
47+
# HELP cpu_usage_nice Telegraf collected metric
48+
# TYPE cpu_usage_nice gauge
49+
cpu_usage_nice{cpu="cpu0"} 0
50+
# HELP cpu_usage_softirq Telegraf collected metric
51+
# TYPE cpu_usage_softirq gauge
52+
cpu_usage_softirq{cpu="cpu0"} 0
53+
# HELP cpu_usage_steal Telegraf collected metric
54+
# TYPE cpu_usage_steal gauge
55+
cpu_usage_steal{cpu="cpu0"} 0
56+
# HELP cpu_usage_system Telegraf collected metric
57+
# TYPE cpu_usage_system gauge
58+
cpu_usage_system{cpu="cpu0"} 0.10030090270831422
59+
# HELP cpu_usage_user Telegraf collected metric
60+
# TYPE cpu_usage_user gauge
61+
cpu_usage_user{cpu="cpu0"} 0.10030090270831422
1862
```
63+
And Telegraf-Prometheus inputs (Prometheus pass through), such as:
64+
(Prometheus)
65+
```
66+
# HELP my_counter This is a counter
67+
# TYPE my_counter counter
68+
my_counter 100
69+
# HELP my_gauge This is a gauge
70+
# TYPE my_gauge gauge
71+
my_gauge 50
72+
# HELP my_histogram This is a histogram
73+
# TYPE my_histogram histogram
74+
my_histogram_bucket{le="0"} 1
75+
my_histogram_bucket{le="1"} 2
76+
my_histogram_bucket{le="2"} 3
77+
my_histogram_bucket{le="3"} 4
78+
my_histogram_bucket{le="+Inf"} 5
79+
my_histogram_count 5
80+
my_histogram_sum 10
81+
# HELP my_summary This is a summary
82+
# TYPE my_summary summary
83+
my_summary{quantile="0"} 1
84+
my_summary{quantile="0.25"} 2
85+
my_summary{quantile="0.5"} 3
86+
my_summary{quantile="0.75"} 4
87+
my_summary{quantile="1"} 5
88+
my_summary_count 5
89+
my_summary_sum 10
90+
```
91+
(Telegraf)
92+
```
93+
> my_counter counter=100 1507833971000000000
94+
> my_gauge gauge=50 1507833971000000000
95+
> my_histogram 1=2,2=3,3=4,+Inf=5,count=5,sum=10,0=1 1507833971000000000
96+
> my_summary 0.75=4,1=5,count=5,sum=10,0=1,0.25=2,0.5=3 1507833971000000000
97+
```
98+
will be formatted as:
99+
```
100+
# HELP my_counter Telegraf collected metric
101+
# TYPE my_counter untyped
102+
my_counter 100
103+
# HELP my_gauge Telegraf collected metric
104+
# TYPE my_gauge untyped
105+
my_gauge 50
106+
# HELP my_histogram_bucket Telegraf collected metric
107+
# TYPE my_histogram_bucket untyped
108+
my_histogram_bucket{le="+Inf"} 5
109+
my_histogram_bucket{le="0"} 1
110+
my_histogram_bucket{le="1"} 2
111+
my_histogram_bucket{le="2"} 3
112+
my_histogram_bucket{le="3"} 4
113+
# HELP my_histogram_count Telegraf collected metric
114+
# TYPE my_histogram_count untyped
115+
my_histogram_count 5
116+
# HELP my_histogram_sum Telegraf collected metric
117+
# TYPE my_histogram_sum untyped
118+
my_histogram_sum 10
119+
# HELP my_summary Telegraf collected metric
120+
# TYPE my_summary untyped
121+
my_summary{quantile="0"} 1
122+
my_summary{quantile="0.25"} 2
123+
my_summary{quantile="0.5"} 3
124+
my_summary{quantile="0.75"} 4
125+
my_summary{quantile="1"} 5
126+
# HELP my_summary_count Telegraf collected metric
127+
# TYPE my_summary_count untyped
128+
my_summary_count 5
129+
# HELP my_summary_sum Telegraf collected metric
130+
# TYPE my_summary_sum untyped
131+
my_summary_sum 10
132+
```
133+

plugins/outputs/prometheus_client/prometheus_client.go

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"log"
77
"net/http"
8+
"os"
89
"regexp"
910
"sort"
1011
"strings"
@@ -15,6 +16,7 @@ import (
1516
"github.com/influxdata/telegraf/internal"
1617
"github.com/influxdata/telegraf/plugins/outputs"
1718
"github.com/prometheus/client_golang/prometheus"
19+
"github.com/prometheus/client_golang/prometheus/promhttp"
1820
)
1921

2022
var invalidNameCharRE = regexp.MustCompile(`[^a-zA-Z0-9_]`)
@@ -46,6 +48,7 @@ type PrometheusClient struct {
4648
Listen string
4749
ExpirationInterval internal.Duration `toml:"expiration_interval"`
4850
Path string `toml:"path"`
51+
UnregisterMetrics bool `toml:"unregister_metrics"`
4952

5053
server *http.Server
5154

@@ -67,6 +70,12 @@ var sampleConfig = `
6770
func (p *PrometheusClient) Start() error {
6871
prometheus.Register(p)
6972

73+
if p.UnregisterMetrics {
74+
// Unregister the collectors automatically added by the prometheus client library
75+
prometheus.Unregister(prometheus.NewProcessCollector(os.Getpid(), ""))
76+
prometheus.Unregister(prometheus.NewGoCollector())
77+
}
78+
7079
if p.Listen == "" {
7180
p.Listen = "localhost:9273"
7281
}
@@ -76,7 +85,7 @@ func (p *PrometheusClient) Start() error {
7685
}
7786

7887
mux := http.NewServeMux()
79-
mux.Handle(p.Path, prometheus.Handler())
88+
mux.Handle(p.Path, promhttp.Handler())
8089

8190
p.server = &http.Server{
8291
Addr: p.Listen,
@@ -212,14 +221,37 @@ func (p *PrometheusClient) Write(metrics []telegraf.Metric) error {
212221

213222
now := p.now()
214223

224+
var histogram, summary, sumpresent, countpresent, infpresent bool
225+
215226
for _, point := range metrics {
216227
tags := point.Tags()
217228
vt := valueType(point.Type())
218-
sampleID := CreateSampleID(tags)
219229

220-
labels := make(map[string]string)
221-
for k, v := range tags {
222-
labels[sanitize(k)] = v
230+
histogram = false
231+
summary = false
232+
sumpresent = false
233+
countpresent = false
234+
infpresent = false
235+
if len(point.Fields()) > 1 {
236+
// Is this a summary, a histogram, or just some other multi-field telegraf input?
237+
for fn, _ := range point.Fields() {
238+
switch fn {
239+
case "+Inf":
240+
infpresent = true
241+
case "sum":
242+
sumpresent = true
243+
case "count":
244+
countpresent = true
245+
}
246+
}
247+
if sumpresent && countpresent {
248+
// We're going to assume it is a summary or histogram
249+
if infpresent {
250+
histogram = true
251+
} else {
252+
summary = true
253+
}
254+
}
223255
}
224256

225257
for fn, fv := range point.Fields() {
@@ -234,19 +266,39 @@ func (p *PrometheusClient) Write(metrics []telegraf.Metric) error {
234266
continue
235267
}
236268

237-
sample := &Sample{
238-
Labels: labels,
239-
Value: value,
240-
Expiration: now.Add(p.ExpirationInterval.Duration),
269+
labels := make(map[string]string)
270+
for k, v := range tags {
271+
labels[sanitize(k)] = v
241272
}
242273

243274
// Special handling of value field; supports passthrough from
244275
// the prometheus input.
245276
var mname string
246-
if fn == "value" {
277+
if fn == "value" || fn == "counter" || fn == "gauge" {
247278
mname = sanitize(point.Name())
248279
} else {
249-
mname = sanitize(fmt.Sprintf("%s_%s", point.Name(), fn))
280+
if summary || histogram {
281+
if fn == "sum" || fn == "count" {
282+
mname = sanitize(fmt.Sprintf("%s_%s", point.Name(), fn))
283+
} else {
284+
// fn is a bucket or quantile
285+
mname = sanitize(point.Name())
286+
if histogram {
287+
labels["le"] = fn
288+
mname = fmt.Sprintf("%s_bucket", mname)
289+
} else {
290+
labels["quantile"] = fn
291+
}
292+
}
293+
} else {
294+
mname = sanitize(fmt.Sprintf("%s_%s", point.Name(), fn))
295+
}
296+
}
297+
298+
sample := &Sample{
299+
Labels: labels,
300+
Value: value,
301+
Expiration: now.Add(p.ExpirationInterval.Duration),
250302
}
251303

252304
var fam *MetricFamily
@@ -280,6 +332,8 @@ func (p *PrometheusClient) Write(metrics []telegraf.Metric) error {
280332
fam.LabelSet[k]++
281333
}
282334

335+
sampleID := CreateSampleID(labels)
336+
283337
fam.Samples[sampleID] = sample
284338
}
285339
}
@@ -292,6 +346,7 @@ func init() {
292346
ExpirationInterval: internal.Duration{Duration: time.Second * 60},
293347
fam: make(map[string]*MetricFamily),
294348
now: time.Now,
349+
UnregisterMetrics: false,
295350
}
296351
})
297352
}

plugins/outputs/prometheus_client/prometheus_client_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ func TestWrite_Sanitize(t *testing.T) {
140140
require.True(t, ok)
141141
require.Equal(t, map[string]int{"tag_with_dash": 1}, fam.LabelSet)
142142

143-
sample1, ok := fam.Samples[CreateSampleID(p1.Tags())]
143+
sanitizedTags := map[string]string{"tag_with_dash": "localhost.local"}
144+
sample1, ok := fam.Samples[CreateSampleID(sanitizedTags)]
144145
require.True(t, ok)
145146

146147
require.Equal(t, map[string]string{

0 commit comments

Comments
 (0)