From 5a7c16a8d6511535d815d50d974ca26f4e99524a Mon Sep 17 00:00:00 2001 From: Irina Date: Wed, 25 Oct 2023 19:37:31 +0100 Subject: [PATCH] otelcol.exporter.prometheus add_metrics_suffixes option (#5568) * otelcol.exporter.prometheus add add_metrics_suffixes option * otelcol.exporter.prometheus add add_metrics_suffixes option. Add tests * otelcol.exporter.prometheus add add_metrics_suffixes option. Update docs * otelcol.exporter.prometheus add add_metrics_suffixes option. Added changelog, fixed readme * otelcol.exporter.prometheus add add_metric_suffixes option. Fix option name * otelcol.exporter.prometheus add add_metric_suffixes option. Add more tests * otelcol.exporter.prometheus add add_metric_suffixes option. Added convertArgumentsToConvertOptions * otelcol.exporter.prometheus add add_metric_suffixes option. Fix changelog message --- CHANGELOG.md | 3 + .../prometheus/internal/convert/convert.go | 11 +- .../internal/convert/convert_test.go | 454 +++++++++++++++++- .../otelcol/exporter/prometheus/prometheus.go | 20 +- .../exporter/prometheus/prometheus_test.go | 75 +++ .../components/otelcol.exporter.prometheus.md | 13 +- 6 files changed, 556 insertions(+), 20 deletions(-) create mode 100644 component/otelcol/exporter/prometheus/prometheus_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index e9e10e3953c7..9de220b898cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,6 +88,9 @@ Main (unreleased) - `otelcol.receiver.kafka` has a new `version` argument to change the version of the SASL Protocol for SASL authentication. +- Added an `add_metric_suffixes` option to `otelcol.exporter.prometheus` in flow mode, + which configures whether to add type and unit suffixes to metrics names. (@mar4uk) + v0.37.2 (2023-10-16) ----------------- diff --git a/component/otelcol/exporter/prometheus/internal/convert/convert.go b/component/otelcol/exporter/prometheus/internal/convert/convert.go index ef76e73337fc..3e2a2578c5a4 100644 --- a/component/otelcol/exporter/prometheus/internal/convert/convert.go +++ b/component/otelcol/exporter/prometheus/internal/convert/convert.go @@ -63,6 +63,8 @@ type Options struct { // IncludeScopeLabels includes the otel_scope_name and otel_scope_version // labels from the scope in the metrics. IncludeScopeLabels bool + // AddMetricSuffixes controls whether suffixes are added to metric names. Defaults to true. + AddMetricSuffixes bool } var _ consumer.Metrics = (*Converter)(nil) @@ -286,8 +288,7 @@ func (conv *Converter) consumeMetric(app storage.Appender, memResource *memorySe } func (conv *Converter) consumeGauge(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric) { - // TODO: should we make the param addMetricSuffixes configurable? For now we set the default value (true) to keep the same behavior as before - metricName := prometheus.BuildCompliantName(m, "", true) + metricName := prometheus.BuildCompliantName(m, "", conv.opts.AddMetricSuffixes) metricMD := conv.createOrUpdateMetadata(metricName, metadata.Metadata{ Type: textparse.MetricTypeGauge, @@ -389,7 +390,7 @@ func getNumberDataPointValue(dp pmetric.NumberDataPoint) float64 { } func (conv *Converter) consumeSum(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric) { - metricName := prometheus.BuildCompliantName(m, "", true) + metricName := prometheus.BuildCompliantName(m, "", conv.opts.AddMetricSuffixes) // Excerpt from the spec: // @@ -447,7 +448,7 @@ func (conv *Converter) consumeSum(app storage.Appender, memResource *memorySerie } func (conv *Converter) consumeHistogram(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric) { - metricName := prometheus.BuildCompliantName(m, "", true) + metricName := prometheus.BuildCompliantName(m, "", conv.opts.AddMetricSuffixes) if m.Histogram().AggregationTemporality() != pmetric.AggregationTemporalityCumulative { // Drop non-cumulative histograms for now, which is permitted by the spec. @@ -606,7 +607,7 @@ func (conv *Converter) convertExemplar(otelExemplar pmetric.Exemplar, ts time.Ti } func (conv *Converter) consumeSummary(app storage.Appender, memResource *memorySeries, memScope *memorySeries, m pmetric.Metric) { - metricName := prometheus.BuildCompliantName(m, "", true) + metricName := prometheus.BuildCompliantName(m, "", conv.opts.AddMetricSuffixes) metricMD := conv.createOrUpdateMetadata(metricName, metadata.Metadata{ Type: textparse.MetricTypeSummary, diff --git a/component/otelcol/exporter/prometheus/internal/convert/convert_test.go b/component/otelcol/exporter/prometheus/internal/convert/convert_test.go index e52a7d7015df..80a6bce1a55b 100644 --- a/component/otelcol/exporter/prometheus/internal/convert/convert_test.go +++ b/component/otelcol/exporter/prometheus/internal/convert/convert_test.go @@ -22,6 +22,8 @@ func TestConverter(t *testing.T) { includeTargetInfo bool includeScopeInfo bool includeScopeLabels bool + addMetricSuffixes bool + enableOpenMetrics bool }{ { name: "Gauge", @@ -45,6 +47,7 @@ func TestConverter(t *testing.T) { # TYPE test_metric_seconds gauge test_metric_seconds 1234.56 `, + enableOpenMetrics: true, }, { name: "Monotonic sum", @@ -78,6 +81,7 @@ func TestConverter(t *testing.T) { # TYPE test_metric_seconds counter test_metric_seconds_total 15.0 # {span_id="aaaaaaaaaaaaaaaa",trace_id="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"} 0.3 `, + enableOpenMetrics: true, }, { name: "Non-monotonic sum", @@ -103,6 +107,7 @@ func TestConverter(t *testing.T) { # TYPE test_metric_seconds gauge test_metric_seconds 15.0 `, + enableOpenMetrics: true, }, { name: "Histogram", @@ -156,6 +161,7 @@ func TestConverter(t *testing.T) { test_metric_seconds_sum 100.0 test_metric_seconds_count 333 `, + enableOpenMetrics: true, }, { name: "Histogram out-of-order bounds", @@ -189,6 +195,7 @@ func TestConverter(t *testing.T) { test_metric_seconds_sum 100.0 test_metric_seconds_count 333 `, + enableOpenMetrics: true, }, { name: "Summary", @@ -226,6 +233,7 @@ func TestConverter(t *testing.T) { test_metric_seconds_sum 100.0 test_metric_seconds_count 333 `, + enableOpenMetrics: true, }, { name: "Timestamps", @@ -250,6 +258,7 @@ func TestConverter(t *testing.T) { # TYPE test_metric_seconds gauge test_metric_seconds 1234.56 1.0 `, + enableOpenMetrics: true, }, { name: "Labels from resource attributes", @@ -283,6 +292,7 @@ func TestConverter(t *testing.T) { # TYPE test_metric_seconds gauge test_metric_seconds{instance="instance",job="myservice"} 1234.56 `, + enableOpenMetrics: true, }, { name: "Labels from scope name and version", @@ -315,6 +325,7 @@ func TestConverter(t *testing.T) { # TYPE test_metric_seconds gauge test_metric_seconds 1234.56 `, + enableOpenMetrics: true, }, { name: "Labels from data point", @@ -349,6 +360,7 @@ func TestConverter(t *testing.T) { # TYPE test_metric_seconds gauge test_metric_seconds{otel_scope_name="a-name",otel_scope_version="a-version",foo="bar"} 1234.56 `, + enableOpenMetrics: true, }, { name: "Target info metric", @@ -386,6 +398,445 @@ func TestConverter(t *testing.T) { # TYPE test_metric_seconds gauge test_metric_seconds{instance="instance",job="myservice"} 1234.56 `, + enableOpenMetrics: true, + }, + { + name: "Gauge: add_metric_suffixes = false", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric", + "unit": "seconds", + "gauge": { + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "as_double": 1234.56 + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric gauge + test_metric 1234.56 + `, + enableOpenMetrics: true, + }, + { + name: "Gauge: add_metric_suffixes = true", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric", + "unit": "seconds", + "gauge": { + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "as_double": 1234.56 + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric_seconds gauge + test_metric_seconds 1234.56 + `, + addMetricSuffixes: true, + enableOpenMetrics: true, + }, + { + name: "Monotonic sum: add_metric_suffixes = false", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric_total", + "unit": "seconds", + "sum": { + "aggregation_temporality": 2, + "is_monotonic": true, + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "as_double": 15, + "exemplars":[ + { + "time_unix_nano": 1000000001, + "as_double": 0.3, + "span_id": "aaaaaaaaaaaaaaaa", + "trace_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + ] + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric counter + test_metric_total 15.0 # {span_id="aaaaaaaaaaaaaaaa",trace_id="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"} 0.3 + `, + enableOpenMetrics: true, + }, + { + name: "Monotonic sum: add_metric_suffixes = true", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric_total", + "unit": "seconds", + "sum": { + "aggregation_temporality": 2, + "is_monotonic": true, + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "as_double": 15, + "exemplars":[ + { + "time_unix_nano": 1000000001, + "as_double": 0.3, + "span_id": "aaaaaaaaaaaaaaaa", + "trace_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + ] + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric_seconds counter + test_metric_seconds_total 15.0 # {span_id="aaaaaaaaaaaaaaaa",trace_id="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"} 0.3 + `, + addMetricSuffixes: true, + enableOpenMetrics: true, + }, + { + name: "Monotonic sum: add_metric_suffixes = false, don't convert to open metrics", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric", + "unit": "seconds", + "sum": { + "aggregation_temporality": 2, + "is_monotonic": true, + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "as_double": 15, + "exemplars":[ + { + "time_unix_nano": 1000000001, + "as_double": 0.3, + "span_id": "aaaaaaaaaaaaaaaa", + "trace_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + ] + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric counter + test_metric 15 + `, + enableOpenMetrics: false, + }, + { + name: "Monotonic sum: add_metric_suffixes = true, don't convert to open metrics", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric", + "unit": "seconds", + "sum": { + "aggregation_temporality": 2, + "is_monotonic": true, + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "as_double": 15, + "exemplars":[ + { + "time_unix_nano": 1000000001, + "as_double": 0.3, + "span_id": "aaaaaaaaaaaaaaaa", + "trace_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + ] + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric_seconds_total counter + test_metric_seconds_total 15 + `, + addMetricSuffixes: true, + enableOpenMetrics: false, + }, + { + name: "Non-monotonic sum: add_metric_suffixes = false", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric", + "unit": "seconds", + "sum": { + "aggregation_temporality": 2, + "is_monotonic": false, + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "as_double": 15 + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric gauge + test_metric 15.0 + `, + enableOpenMetrics: true, + }, + { + name: "Non-monotonic sum: add_metric_suffixes = true", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric", + "unit": "seconds", + "sum": { + "aggregation_temporality": 2, + "is_monotonic": false, + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "as_double": 15 + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric_seconds gauge + test_metric_seconds 15.0 + `, + addMetricSuffixes: true, + enableOpenMetrics: true, + }, + { + name: "Histogram: add_metric_suffixes = false", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric", + "unit": "seconds", + "histogram": { + "aggregation_temporality": 2, + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "count": 333, + "sum": 100, + "bucket_counts": [0, 111, 0, 222], + "explicit_bounds": [0.25, 0.5, 0.75, 1.0], + "exemplars":[ + { + "time_unix_nano": 1000000001, + "as_double": 0.3, + "span_id": "aaaaaaaaaaaaaaaa", + "trace_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }, + { + "time_unix_nano": 1000000003, + "as_double": 1.5, + "span_id": "cccccccccccccccc", + "trace_id": "cccccccccccccccccccccccccccccccc" + }, + { + "time_unix_nano": 1000000002, + "as_double": 0.5, + "span_id": "bbbbbbbbbbbbbbbb", + "trace_id": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + } + ] + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric histogram + test_metric_bucket{le="0.25"} 0 + test_metric_bucket{le="0.5"} 111 # {span_id="aaaaaaaaaaaaaaaa",trace_id="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"} 0.3 + test_metric_bucket{le="0.75"} 111 # {span_id="bbbbbbbbbbbbbbbb",trace_id="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"} 0.5 + test_metric_bucket{le="1.0"} 333 + test_metric_bucket{le="+Inf"} 333 # {span_id="cccccccccccccccc",trace_id="cccccccccccccccccccccccccccccccc"} 1.5 + test_metric_sum 100.0 + test_metric_count 333 + `, + enableOpenMetrics: true, + }, + { + name: "Histogram: add_metric_suffixes = true", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric", + "unit": "seconds", + "histogram": { + "aggregation_temporality": 2, + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "count": 333, + "sum": 100, + "bucket_counts": [0, 111, 0, 222], + "explicit_bounds": [0.25, 0.5, 0.75, 1.0], + "exemplars":[ + { + "time_unix_nano": 1000000001, + "as_double": 0.3, + "span_id": "aaaaaaaaaaaaaaaa", + "trace_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }, + { + "time_unix_nano": 1000000003, + "as_double": 1.5, + "span_id": "cccccccccccccccc", + "trace_id": "cccccccccccccccccccccccccccccccc" + }, + { + "time_unix_nano": 1000000002, + "as_double": 0.5, + "span_id": "bbbbbbbbbbbbbbbb", + "trace_id": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + } + ] + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric_seconds histogram + test_metric_seconds_bucket{le="0.25"} 0 + test_metric_seconds_bucket{le="0.5"} 111 # {span_id="aaaaaaaaaaaaaaaa",trace_id="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"} 0.3 + test_metric_seconds_bucket{le="0.75"} 111 # {span_id="bbbbbbbbbbbbbbbb",trace_id="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"} 0.5 + test_metric_seconds_bucket{le="1.0"} 333 + test_metric_seconds_bucket{le="+Inf"} 333 # {span_id="cccccccccccccccc",trace_id="cccccccccccccccccccccccccccccccc"} 1.5 + test_metric_seconds_sum 100.0 + test_metric_seconds_count 333 + `, + addMetricSuffixes: true, + enableOpenMetrics: true, + }, + { + name: "Summary: add_metric_suffixes = false", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric", + "unit": "seconds", + "summary": { + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "count": 333, + "sum": 100, + "quantile_values": [ + { "quantile": 0, "value": 100 }, + { "quantile": 0.25, "value": 200 }, + { "quantile": 0.5, "value": 300 }, + { "quantile": 0.75, "value": 400 }, + { "quantile": 1, "value": 500 } + ] + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric summary + test_metric{quantile="0.0"} 100.0 + test_metric{quantile="0.25"} 200.0 + test_metric{quantile="0.5"} 300.0 + test_metric{quantile="0.75"} 400.0 + test_metric{quantile="1.0"} 500.0 + test_metric_sum 100.0 + test_metric_count 333 + `, + enableOpenMetrics: true, + }, + { + name: "Summary: add_metric_suffixes = true", + input: `{ + "resource_metrics": [{ + "scope_metrics": [{ + "metrics": [{ + "name": "test_metric", + "unit": "seconds", + "summary": { + "data_points": [{ + "start_time_unix_nano": 1000000000, + "time_unix_nano": 1000000000, + "count": 333, + "sum": 100, + "quantile_values": [ + { "quantile": 0, "value": 100 }, + { "quantile": 0.25, "value": 200 }, + { "quantile": 0.5, "value": 300 }, + { "quantile": 0.75, "value": 400 }, + { "quantile": 1, "value": 500 } + ] + }] + } + }] + }] + }] + }`, + expect: ` + # TYPE test_metric_seconds summary + test_metric_seconds{quantile="0.0"} 100.0 + test_metric_seconds{quantile="0.25"} 200.0 + test_metric_seconds{quantile="0.5"} 300.0 + test_metric_seconds{quantile="0.75"} 400.0 + test_metric_seconds{quantile="1.0"} 500.0 + test_metric_seconds_sum 100.0 + test_metric_seconds_count 333 + `, + addMetricSuffixes: true, + enableOpenMetrics: true, }, } @@ -403,13 +854,14 @@ func TestConverter(t *testing.T) { IncludeTargetInfo: tc.includeTargetInfo, IncludeScopeInfo: tc.includeScopeInfo, IncludeScopeLabels: tc.includeScopeLabels, + AddMetricSuffixes: tc.addMetricSuffixes, }) require.NoError(t, conv.ConsumeMetrics(context.Background(), payload)) families, err := app.MetricFamilies() require.NoError(t, err) - c := testappender.Comparer{OpenMetrics: true} + c := testappender.Comparer{OpenMetrics: tc.enableOpenMetrics} require.NoError(t, c.Compare(families, tc.expect)) }) } diff --git a/component/otelcol/exporter/prometheus/prometheus.go b/component/otelcol/exporter/prometheus/prometheus.go index 54079b5bd63b..0dd9ef49e69f 100644 --- a/component/otelcol/exporter/prometheus/prometheus.go +++ b/component/otelcol/exporter/prometheus/prometheus.go @@ -36,6 +36,7 @@ type Arguments struct { IncludeScopeLabels bool `river:"include_scope_labels,attr,optional"` GCFrequency time.Duration `river:"gc_frequency,attr,optional"` ForwardTo []storage.Appendable `river:"forward_to,attr"` + AddMetricSuffixes bool `river:"add_metric_suffixes,attr,optional"` } // DefaultArguments holds defaults values. @@ -44,6 +45,7 @@ var DefaultArguments = Arguments{ IncludeScopeInfo: false, IncludeScopeLabels: true, GCFrequency: 5 * time.Minute, + AddMetricSuffixes: true, } // SetToDefault implements river.Defaulter. @@ -83,10 +85,7 @@ func New(o component.Options, c Arguments) (*Component, error) { ls := service.(labelstore.LabelStore) fanout := prometheus.NewFanout(nil, o.ID, o.Registerer, ls) - converter := convert.New(o.Logger, fanout, convert.Options{ - IncludeTargetInfo: true, - IncludeScopeInfo: false, - }) + converter := convert.New(o.Logger, fanout, convertArgumentsToConvertOptions(c)) res := &Component{ log: o.Logger, @@ -139,10 +138,7 @@ func (c *Component) Update(newConfig component.Arguments) error { c.cfg = cfg c.fanout.UpdateChildren(cfg.ForwardTo) - c.converter.UpdateOptions(convert.Options{ - IncludeTargetInfo: cfg.IncludeTargetInfo, - IncludeScopeInfo: cfg.IncludeScopeInfo, - }) + c.converter.UpdateOptions(convertArgumentsToConvertOptions(cfg)) // If our forward_to argument changed, we need to flush the metadata cache to // ensure the new children have all the metadata they need. @@ -152,3 +148,11 @@ func (c *Component) Update(newConfig component.Arguments) error { c.converter.FlushMetadata() return nil } + +func convertArgumentsToConvertOptions(args Arguments) convert.Options { + return convert.Options{ + IncludeTargetInfo: args.IncludeTargetInfo, + IncludeScopeInfo: args.IncludeScopeInfo, + AddMetricSuffixes: args.AddMetricSuffixes, + } +} diff --git a/component/otelcol/exporter/prometheus/prometheus_test.go b/component/otelcol/exporter/prometheus/prometheus_test.go new file mode 100644 index 000000000000..2939c8962346 --- /dev/null +++ b/component/otelcol/exporter/prometheus/prometheus_test.go @@ -0,0 +1,75 @@ +package prometheus_test + +import ( + "testing" + "time" + + "github.com/grafana/agent/component/otelcol/exporter/prometheus" + "github.com/grafana/river" + "github.com/prometheus/prometheus/storage" + "github.com/stretchr/testify/require" +) + +func TestArguments_UnmarshalRiver(t *testing.T) { + tests := []struct { + testName string + cfg string + expected prometheus.Arguments + errorMsg string + }{ + { + testName: "Defaults", + cfg: ` + forward_to = [] + `, + expected: prometheus.Arguments{ + IncludeTargetInfo: true, + IncludeScopeInfo: false, + IncludeScopeLabels: true, + GCFrequency: 5 * time.Minute, + AddMetricSuffixes: true, + ForwardTo: []storage.Appendable{}, + }, + }, + { + testName: "ExplicitValues", + cfg: ` + include_target_info = false + include_scope_info = true + include_scope_labels = false + gc_frequency = "1s" + add_metric_suffixes = false + forward_to = [] + `, + expected: prometheus.Arguments{ + IncludeTargetInfo: false, + IncludeScopeInfo: true, + IncludeScopeLabels: false, + GCFrequency: 1 * time.Second, + AddMetricSuffixes: false, + ForwardTo: []storage.Appendable{}, + }, + }, + { + testName: "Zero GCFrequency", + cfg: ` + gc_frequency = "0s" + forward_to = [] + `, + errorMsg: "gc_frequency must be greater than 0", + }, + } + + for _, tc := range tests { + t.Run(tc.testName, func(t *testing.T) { + var args prometheus.Arguments + err := river.Unmarshal([]byte(tc.cfg), &args) + if tc.errorMsg != "" { + require.EqualError(t, err, tc.errorMsg) + return + } + require.NoError(t, err) + require.Equal(t, tc.expected, args) + }) + } +} diff --git a/docs/sources/flow/reference/components/otelcol.exporter.prometheus.md b/docs/sources/flow/reference/components/otelcol.exporter.prometheus.md index e2115d056d8b..e3b3c08416a8 100644 --- a/docs/sources/flow/reference/components/otelcol.exporter.prometheus.md +++ b/docs/sources/flow/reference/components/otelcol.exporter.prometheus.md @@ -37,13 +37,14 @@ otelcol.exporter.prometheus "LABEL" { `otelcol.exporter.prometheus` supports the following arguments: -Name | Type | Description | Default | Required ----- | ---- | ----------- | ------- | -------- -`include_target_info` | `boolean` | Whether to include `target_info` metrics. | `true` | no -`include_scope_info` | `boolean` | Whether to include `otel_scope_info` metrics. | `false` | no +Name | Type | Description | Default | Required +---- | ---- |-----------------------------------------------------------| ------- | -------- +`include_target_info` | `boolean` | Whether to include `target_info` metrics. | `true` | no +`include_scope_info` | `boolean` | Whether to include `otel_scope_info` metrics. | `false` | no `include_scope_labels` | `boolean` | Whether to include additional OTLP labels in all metrics. | `true` | no -`gc_frequency` | `duration` | How often to clean up stale metrics from memory. | `"5m"` | no -`forward_to` | `list(receiver)` | Where to forward converted Prometheus metrics. | | yes +`add_metric_suffixes` | `boolean` | Whether to add type and unit suffixes to metrics names. | `true` | no +`gc_frequency` | `duration` | How often to clean up stale metrics from memory. | `"5m"` | no +`forward_to` | `list(receiver)` | Where to forward converted Prometheus metrics. | | yes By default, OpenTelemetry resources are converted into `target_info` metrics. OpenTelemetry instrumentation scopes are converted into `otel_scope_info`