diff --git a/CHANGELOG.md b/CHANGELOG.md index c89276666fee..32c52356b2f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ This document contains a historical list of changes between releases. Only changes that impact end-user behavior are listed; changes to documentation or internal API changes are not present. +v0.37.4 (2023-11-06) +----------------- + +### Enhancements + +- 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) + +### Bugfixes + +- Fix a bug where reloading the configuration of a `loki.write` component lead + to a panic. (@tpaschalis) + v0.37.3 (2023-10-26) ----------------- @@ -30,7 +43,7 @@ v0.37.3 (2023-10-26) - `otelcol.receiver.kafka` has a new `header_extraction` block to extract headers from Kafka records. - `otelcol.receiver.kafka` has a new `version` argument to change the version of the SASL Protocol for SASL authentication. - + v0.37.2 (2023-10-16) ----------------- diff --git a/component/common/loki/wal/watcher_metrics.go b/component/common/loki/wal/watcher_metrics.go index 715ae59aaf24..061b9cc0fa17 100644 --- a/component/common/loki/wal/watcher_metrics.go +++ b/component/common/loki/wal/watcher_metrics.go @@ -70,13 +70,23 @@ func NewWatcherMetrics(reg prometheus.Registerer) *WatcherMetrics { } if reg != nil { - reg.MustRegister(m.recordsRead) - reg.MustRegister(m.recordDecodeFails) - reg.MustRegister(m.droppedWriteNotifications) - reg.MustRegister(m.segmentRead) - reg.MustRegister(m.currentSegment) - reg.MustRegister(m.watchersRunning) + m.recordsRead = mustRegisterOrGet(reg, m.recordsRead).(*prometheus.CounterVec) + m.recordDecodeFails = mustRegisterOrGet(reg, m.recordDecodeFails).(*prometheus.CounterVec) + m.droppedWriteNotifications = mustRegisterOrGet(reg, m.droppedWriteNotifications).(*prometheus.CounterVec) + m.segmentRead = mustRegisterOrGet(reg, m.segmentRead).(*prometheus.CounterVec) + m.currentSegment = mustRegisterOrGet(reg, m.currentSegment).(*prometheus.GaugeVec) + m.watchersRunning = mustRegisterOrGet(reg, m.watchersRunning).(*prometheus.GaugeVec) } return m } + +func mustRegisterOrGet(reg prometheus.Registerer, c prometheus.Collector) prometheus.Collector { + if err := reg.Register(c); err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + return are.ExistingCollector + } + panic(err) + } + return c +} diff --git a/component/otelcol/exporter/prometheus/internal/convert/convert.go b/component/otelcol/exporter/prometheus/internal/convert/convert.go index 69569cec5f11..0d0051cc5c57 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 8816d8097b9f..fc4b0ed81cd0 100644 --- a/component/otelcol/exporter/prometheus/prometheus.go +++ b/component/otelcol/exporter/prometheus/prometheus.go @@ -35,6 +35,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. @@ -43,6 +44,7 @@ var DefaultArguments = Arguments{ IncludeScopeInfo: false, IncludeScopeLabels: true, GCFrequency: 5 * time.Minute, + AddMetricSuffixes: true, } // SetToDefault implements river.Defaulter. @@ -77,10 +79,7 @@ var _ component.Component = (*Component)(nil) func New(o component.Options, c Arguments) (*Component, error) { fanout := prometheus.NewFanout(nil, o.ID, o.Registerer) - 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, @@ -133,10 +132,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. @@ -146,3 +142,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/_index.md b/docs/sources/_index.md index 613fff695641..cffd8162ec27 100644 --- a/docs/sources/_index.md +++ b/docs/sources/_index.md @@ -8,7 +8,7 @@ title: Grafana Agent description: Grafana Agent is a flexible, performant, vendor-neutral, telemetry collector weight: 350 cascade: - AGENT_RELEASE: v0.37.3 + AGENT_RELEASE: v0.37.4 OTEL_VERSION: v0.87.0 --- 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` diff --git a/pkg/operator/defaults.go b/pkg/operator/defaults.go index e9907c4a4ae5..68842b412f42 100644 --- a/pkg/operator/defaults.go +++ b/pkg/operator/defaults.go @@ -2,7 +2,7 @@ package operator // Supported versions of the Grafana Agent. var ( - DefaultAgentVersion = "v0.37.3" + DefaultAgentVersion = "v0.37.4" DefaultAgentBaseImage = "grafana/agent" DefaultAgentImage = DefaultAgentBaseImage + ":" + DefaultAgentVersion ) diff --git a/production/kubernetes/agent-bare.yaml b/production/kubernetes/agent-bare.yaml index 668d2b286a73..0ca2da3bc58f 100644 --- a/production/kubernetes/agent-bare.yaml +++ b/production/kubernetes/agent-bare.yaml @@ -83,7 +83,7 @@ spec: valueFrom: fieldRef: fieldPath: spec.nodeName - image: grafana/agent:v0.37.3 + image: grafana/agent:v0.37.4 imagePullPolicy: IfNotPresent name: grafana-agent ports: diff --git a/production/kubernetes/agent-loki.yaml b/production/kubernetes/agent-loki.yaml index dabcbb9f03b4..4eeb798a00d8 100644 --- a/production/kubernetes/agent-loki.yaml +++ b/production/kubernetes/agent-loki.yaml @@ -65,7 +65,7 @@ spec: valueFrom: fieldRef: fieldPath: spec.nodeName - image: grafana/agent:v0.37.3 + image: grafana/agent:v0.37.4 imagePullPolicy: IfNotPresent name: grafana-agent-logs ports: diff --git a/production/kubernetes/agent-traces.yaml b/production/kubernetes/agent-traces.yaml index ee15687e834c..7c2835846b0a 100644 --- a/production/kubernetes/agent-traces.yaml +++ b/production/kubernetes/agent-traces.yaml @@ -114,7 +114,7 @@ spec: valueFrom: fieldRef: fieldPath: spec.nodeName - image: grafana/agent:v0.37.3 + image: grafana/agent:v0.37.4 imagePullPolicy: IfNotPresent name: grafana-agent-traces ports: diff --git a/production/kubernetes/build/lib/version.libsonnet b/production/kubernetes/build/lib/version.libsonnet index b9571fb91726..be3865408074 100644 --- a/production/kubernetes/build/lib/version.libsonnet +++ b/production/kubernetes/build/lib/version.libsonnet @@ -1 +1 @@ -'grafana/agent:v0.37.3' +'grafana/agent:v0.37.4' diff --git a/production/kubernetes/build/templates/operator/main.jsonnet b/production/kubernetes/build/templates/operator/main.jsonnet index e92dfa9ae4d7..dda322bac503 100644 --- a/production/kubernetes/build/templates/operator/main.jsonnet +++ b/production/kubernetes/build/templates/operator/main.jsonnet @@ -23,8 +23,8 @@ local ksm = import 'kube-state-metrics/kube-state-metrics.libsonnet'; local this = self, _images:: { - agent: 'grafana/agent:v0.37.3', - agent_operator: 'grafana/agent-operator:v0.37.3', + agent: 'grafana/agent:v0.37.4', + agent_operator: 'grafana/agent-operator:v0.37.4', ksm: 'registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.5.0', }, diff --git a/production/kubernetes/install-bare.sh b/production/kubernetes/install-bare.sh index ea25968e6bd3..93cc7120af23 100644 --- a/production/kubernetes/install-bare.sh +++ b/production/kubernetes/install-bare.sh @@ -25,7 +25,7 @@ check_installed() { check_installed curl check_installed envsubst -MANIFEST_BRANCH=v0.37.3 +MANIFEST_BRANCH=v0.37.4 MANIFEST_URL=${MANIFEST_URL:-https://raw.githubusercontent.com/grafana/agent/${MANIFEST_BRANCH}/production/kubernetes/agent-bare.yaml} NAMESPACE=${NAMESPACE:-default} diff --git a/production/operator/templates/agent-operator.yaml b/production/operator/templates/agent-operator.yaml index 863585a29b89..797ce35fa972 100644 --- a/production/operator/templates/agent-operator.yaml +++ b/production/operator/templates/agent-operator.yaml @@ -372,7 +372,7 @@ spec: containers: - args: - --kubelet-service=default/kubelet - image: grafana/agent-operator:v0.37.3 + image: grafana/agent-operator:v0.37.4 imagePullPolicy: IfNotPresent name: grafana-agent-operator serviceAccount: grafana-agent-operator @@ -436,7 +436,7 @@ metadata: name: grafana-agent namespace: ${NAMESPACE} spec: - image: grafana/agent:v0.37.3 + image: grafana/agent:v0.37.4 integrations: selector: matchLabels: diff --git a/production/tanka/grafana-agent/v1/main.libsonnet b/production/tanka/grafana-agent/v1/main.libsonnet index c21bb98e03c5..8ff06ab1bf5b 100644 --- a/production/tanka/grafana-agent/v1/main.libsonnet +++ b/production/tanka/grafana-agent/v1/main.libsonnet @@ -15,8 +15,8 @@ local service = k.core.v1.service; (import './lib/traces.libsonnet') + { _images:: { - agent: 'grafana/agent:v0.37.3', - agentctl: 'grafana/agentctl:v0.37.3', + agent: 'grafana/agent:v0.37.4', + agentctl: 'grafana/agentctl:v0.37.4', }, // new creates a new DaemonSet deployment of the grafana-agent. By default, diff --git a/production/tanka/grafana-agent/v2/internal/base.libsonnet b/production/tanka/grafana-agent/v2/internal/base.libsonnet index 16840b40aace..53921bf64aaf 100644 --- a/production/tanka/grafana-agent/v2/internal/base.libsonnet +++ b/production/tanka/grafana-agent/v2/internal/base.libsonnet @@ -11,8 +11,8 @@ function(name='grafana-agent', namespace='') { local this = self, _images:: { - agent: 'grafana/agent:v0.37.3', - agentctl: 'grafana/agentctl:v0.37.3', + agent: 'grafana/agent:v0.37.4', + agentctl: 'grafana/agentctl:v0.37.4', }, _config:: { name: name, diff --git a/production/tanka/grafana-agent/v2/internal/syncer.libsonnet b/production/tanka/grafana-agent/v2/internal/syncer.libsonnet index 35bb6f40a00e..689b14fd87b3 100644 --- a/production/tanka/grafana-agent/v2/internal/syncer.libsonnet +++ b/production/tanka/grafana-agent/v2/internal/syncer.libsonnet @@ -14,7 +14,7 @@ function( ) { local _config = { api: error 'api must be set', - image: 'grafana/agentctl:v0.37.3', + image: 'grafana/agentctl:v0.37.4', schedule: '*/5 * * * *', configs: [], } + config, diff --git a/tools/gen-versioned-files/agent-version.txt b/tools/gen-versioned-files/agent-version.txt index 7c49ad6429e3..f3d8baac63b3 100644 --- a/tools/gen-versioned-files/agent-version.txt +++ b/tools/gen-versioned-files/agent-version.txt @@ -1 +1 @@ -v0.37.3 +v0.37.4