feat(outputs.loki): Add option for metric name label (#13157)

This commit is contained in:
Joshua Powers 2023-05-04 03:56:19 -06:00 committed by GitHub
parent 1a7c274ddf
commit 8396f1a00d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 27 deletions

View File

@ -52,4 +52,10 @@ to use them.
# tls_ca = "/etc/telegraf/ca.pem"
# tls_cert = "/etc/telegraf/cert.pem"
# tls_key = "/etc/telegraf/key.pem"
## Metric Name Label
## Label to use for the metric name to when sending metrics. If set to an
## empty string, this will not add the label. This is NOT suggested as there
## is no way to differentiate between multiple metrics.
# metric_name_label = "__name"
```

View File

@ -43,6 +43,7 @@ type Loki struct {
TokenURL string `toml:"token_url"`
Scopes []string `toml:"scopes"`
GZipRequest bool `toml:"gzip_request"`
MetricNameLabel string `toml:"metric_name_label"`
url string
client *http.Client
@ -119,7 +120,9 @@ func (l *Loki) Write(metrics []telegraf.Metric) error {
})
for _, m := range metrics {
m.AddTag("__name", m.Name())
if l.MetricNameLabel != "" {
m.AddTag(l.MetricNameLabel, m.Name())
}
tags := m.TagList()
var line string
@ -197,6 +200,8 @@ func (l *Loki) writeMetrics(s Streams) error {
func init() {
outputs.Add("loki", func() telegraf.Output {
return &Loki{}
return &Loki{
MetricNameLabel: "__name",
}
})
}

View File

@ -121,8 +121,7 @@ func TestStatusCode(t *testing.T) {
w.WriteHeader(tt.statusCode)
})
err = tt.plugin.Connect()
require.NoError(t, err)
require.NoError(t, tt.plugin.Connect())
err = tt.plugin.Write([]telegraf.Metric{getMetric()})
tt.errFunc(t, err)
@ -167,8 +166,7 @@ func TestContentType(t *testing.T) {
w.WriteHeader(http.StatusOK)
})
err = tt.plugin.Connect()
require.NoError(t, err)
require.NoError(t, tt.plugin.Connect())
err = tt.plugin.Write([]telegraf.Metric{getMetric()})
require.NoError(t, err)
@ -226,7 +224,7 @@ func TestContentEncodingGzip(t *testing.T) {
require.Len(t, s.Streams, 1)
require.Len(t, s.Streams[0].Logs, 1)
require.Len(t, s.Streams[0].Logs[0], 2)
require.Equal(t, map[string]string{"__name": "log", "key1": "value1"}, s.Streams[0].Labels)
require.Equal(t, map[string]string{"key1": "value1"}, s.Streams[0].Labels)
require.Equal(t, "123000000000", s.Streams[0].Logs[0][0])
require.Contains(t, s.Streams[0].Logs[0][1], "line=\"my log\"")
require.Contains(t, s.Streams[0].Logs[0][1], "field=\"3.14\"")
@ -234,8 +232,7 @@ func TestContentEncodingGzip(t *testing.T) {
w.WriteHeader(http.StatusNoContent)
})
err = tt.plugin.Connect()
require.NoError(t, err)
require.NoError(t, tt.plugin.Connect())
err = tt.plugin.Write([]telegraf.Metric{getMetric()})
require.NoError(t, err)
@ -243,6 +240,56 @@ func TestContentEncodingGzip(t *testing.T) {
}
}
func TestMetricNameLabel(t *testing.T) {
ts := httptest.NewServer(http.NotFoundHandler())
defer ts.Close()
u, err := url.Parse(fmt.Sprintf("http://%s", ts.Listener.Addr().String()))
require.NoError(t, err)
tests := []struct {
name string
metricNameLabel string
}{
{
name: "no label",
metricNameLabel: "",
},
{
name: "custom label",
metricNameLabel: "foobar",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
payload, err := io.ReadAll(r.Body)
require.NoError(t, err)
var s Request
require.NoError(t, json.Unmarshal(payload, &s))
switch tt.metricNameLabel {
case "":
require.Equal(t, map[string]string{"key1": "value1"}, s.Streams[0].Labels)
case "foobar":
require.Equal(t, map[string]string{"foobar": "log", "key1": "value1"}, s.Streams[0].Labels)
}
w.WriteHeader(http.StatusNoContent)
})
l := Loki{
Domain: u.String(),
MetricNameLabel: tt.metricNameLabel,
}
require.NoError(t, l.Connect())
require.NoError(t, l.Write([]telegraf.Metric{getMetric()}))
})
}
}
func TestBasicAuth(t *testing.T) {
ts := httptest.NewServer(http.NotFoundHandler())
defer ts.Close()
@ -349,8 +396,7 @@ func TestOAuthClientCredentialsGrant(t *testing.T) {
}
})
err = tt.plugin.Connect()
require.NoError(t, err)
require.NoError(t, tt.plugin.Connect())
err = tt.plugin.Write([]telegraf.Metric{getMetric()})
require.NoError(t, err)
@ -375,8 +421,7 @@ func TestDefaultUserAgent(t *testing.T) {
Domain: u.String(),
}
err = client.Connect()
require.NoError(t, err)
require.NoError(t, client.Connect())
err = client.Write([]telegraf.Metric{getMetric()})
require.NoError(t, err)
@ -404,7 +449,7 @@ func TestMetricSorting(t *testing.T) {
require.Len(t, s.Streams, 1)
require.Len(t, s.Streams[0].Logs, 2)
require.Len(t, s.Streams[0].Logs[0], 2)
require.Equal(t, map[string]string{"__name": "log", "key1": "value1"}, s.Streams[0].Labels)
require.Equal(t, map[string]string{"key1": "value1"}, s.Streams[0].Labels)
require.Equal(t, "456000000000", s.Streams[0].Logs[0][0])
require.Contains(t, s.Streams[0].Logs[0][1], "line=\"older log\"")
require.Contains(t, s.Streams[0].Logs[0][1], "field=\"3.14\"")
@ -419,8 +464,7 @@ func TestMetricSorting(t *testing.T) {
Domain: u.String(),
}
err = client.Connect()
require.NoError(t, err)
require.NoError(t, client.Connect())
err = client.Write(getOutOfOrderMetrics())
require.NoError(t, err)

View File

@ -23,3 +23,9 @@
# tls_ca = "/etc/telegraf/ca.pem"
# tls_cert = "/etc/telegraf/cert.pem"
# tls_key = "/etc/telegraf/key.pem"
## Metric Name Label
## Label to use for the metric name to when sending metrics. If set to an
## empty string, this will not add the label. This is NOT suggested as there
## is no way to differentiate between multiple metrics.
# metric_name_label = "__name"