diff --git a/cmd/mdatagen/internal/samplereceiver/documentation.md b/cmd/mdatagen/internal/samplereceiver/documentation.md index 0e29d896d66..60a79a7941a 100644 --- a/cmd/mdatagen/internal/samplereceiver/documentation.md +++ b/cmd/mdatagen/internal/samplereceiver/documentation.md @@ -42,6 +42,24 @@ The metric will be will be removed soon. | ---- | ----------- | ---------- | ----------------------- | --------- | | s | Sum | Double | Delta | false | +### metric.input_type + +Monotonic cumulative sum int metric with string input_type enabled by default. + +| Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | +| ---- | ----------- | ---------- | ----------------------- | --------- | +| s | Sum | Int | Cumulative | true | + +#### Attributes + +| Name | Description | Values | +| ---- | ----------- | ------ | +| string_attr | Attribute with any string value. | Any Str | +| state | Integer attribute with overridden name. | Any Int | +| enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | +| slice_attr | Attribute with a slice value. | Any Slice | +| map_attr | Attribute with a map value. | Any Map | + ## Optional Metrics The following metrics are not emitted by default. Each of them can be enabled by applying the following configuration: diff --git a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config.go index eb00e302065..512c4c9b083 100644 --- a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config.go @@ -27,6 +27,7 @@ func (ms *MetricConfig) Unmarshal(parser *confmap.Conf) error { type MetricsConfig struct { DefaultMetric MetricConfig `mapstructure:"default.metric"` DefaultMetricToBeRemoved MetricConfig `mapstructure:"default.metric.to_be_removed"` + MetricInputType MetricConfig `mapstructure:"metric.input_type"` OptionalMetric MetricConfig `mapstructure:"optional.metric"` OptionalMetricEmptyUnit MetricConfig `mapstructure:"optional.metric.empty_unit"` } @@ -39,6 +40,9 @@ func DefaultMetricsConfig() MetricsConfig { DefaultMetricToBeRemoved: MetricConfig{ Enabled: true, }, + MetricInputType: MetricConfig{ + Enabled: true, + }, OptionalMetric: MetricConfig{ Enabled: false, }, diff --git a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config_test.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config_test.go index bfb90940386..0f581b137f7 100644 --- a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config_test.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config_test.go @@ -29,6 +29,7 @@ func TestMetricsBuilderConfig(t *testing.T) { Metrics: MetricsConfig{ DefaultMetric: MetricConfig{Enabled: true}, DefaultMetricToBeRemoved: MetricConfig{Enabled: true}, + MetricInputType: MetricConfig{Enabled: true}, OptionalMetric: MetricConfig{Enabled: true}, OptionalMetricEmptyUnit: MetricConfig{Enabled: true}, }, @@ -50,6 +51,7 @@ func TestMetricsBuilderConfig(t *testing.T) { Metrics: MetricsConfig{ DefaultMetric: MetricConfig{Enabled: false}, DefaultMetricToBeRemoved: MetricConfig{Enabled: false}, + MetricInputType: MetricConfig{Enabled: false}, OptionalMetric: MetricConfig{Enabled: false}, OptionalMetricEmptyUnit: MetricConfig{Enabled: false}, }, diff --git a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go index 13e41059ae9..e038e8443ad 100644 --- a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go @@ -3,6 +3,8 @@ package metadata import ( + "fmt" + "strconv" "time" "go.opentelemetry.io/collector/component" @@ -150,6 +152,63 @@ func newMetricDefaultMetricToBeRemoved(cfg MetricConfig) metricDefaultMetricToBe return m } +type metricMetricInputType struct { + data pmetric.Metric // data buffer for generated metric. + config MetricConfig // metric config provided by user. + capacity int // max observed number of data points added to the metric. +} + +// init fills metric.input_type metric with initial data. +func (m *metricMetricInputType) init() { + m.data.SetName("metric.input_type") + m.data.SetDescription("Monotonic cumulative sum int metric with string input_type enabled by default.") + m.data.SetUnit("s") + m.data.SetEmptySum() + m.data.Sum().SetIsMonotonic(true) + m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) + m.data.Sum().DataPoints().EnsureCapacity(m.capacity) +} + +func (m *metricMetricInputType) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { + if !m.config.Enabled { + return + } + dp := m.data.Sum().DataPoints().AppendEmpty() + dp.SetStartTimestamp(start) + dp.SetTimestamp(ts) + dp.SetIntValue(val) + dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) + dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) + dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) + dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) + dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) +} + +// updateCapacity saves max length of data point slices that will be used for the slice capacity. +func (m *metricMetricInputType) updateCapacity() { + if m.data.Sum().DataPoints().Len() > m.capacity { + m.capacity = m.data.Sum().DataPoints().Len() + } +} + +// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. +func (m *metricMetricInputType) emit(metrics pmetric.MetricSlice) { + if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricMetricInputType(cfg MetricConfig) metricMetricInputType { + m := metricMetricInputType{config: cfg} + if cfg.Enabled { + m.data = pmetric.NewMetric() + m.init() + } + return m +} + type metricOptionalMetric struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. @@ -264,6 +323,7 @@ type MetricsBuilder struct { buildInfo component.BuildInfo // contains version information. metricDefaultMetric metricDefaultMetric metricDefaultMetricToBeRemoved metricDefaultMetricToBeRemoved + metricMetricInputType metricMetricInputType metricOptionalMetric metricOptionalMetric metricOptionalMetricEmptyUnit metricOptionalMetricEmptyUnit } @@ -307,6 +367,7 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.CreateSetting buildInfo: settings.BuildInfo, metricDefaultMetric: newMetricDefaultMetric(mbc.Metrics.DefaultMetric), metricDefaultMetricToBeRemoved: newMetricDefaultMetricToBeRemoved(mbc.Metrics.DefaultMetricToBeRemoved), + metricMetricInputType: newMetricMetricInputType(mbc.Metrics.MetricInputType), metricOptionalMetric: newMetricOptionalMetric(mbc.Metrics.OptionalMetric), metricOptionalMetricEmptyUnit: newMetricOptionalMetricEmptyUnit(mbc.Metrics.OptionalMetricEmptyUnit), } @@ -373,6 +434,7 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { ils.Metrics().EnsureCapacity(mb.metricsCapacity) mb.metricDefaultMetric.emit(ils.Metrics()) mb.metricDefaultMetricToBeRemoved.emit(ils.Metrics()) + mb.metricMetricInputType.emit(ils.Metrics()) mb.metricOptionalMetric.emit(ils.Metrics()) mb.metricOptionalMetricEmptyUnit.emit(ils.Metrics()) @@ -405,6 +467,16 @@ func (mb *MetricsBuilder) RecordDefaultMetricToBeRemovedDataPoint(ts pcommon.Tim mb.metricDefaultMetricToBeRemoved.recordDataPoint(mb.startTime, ts, val) } +// RecordMetricInputTypeDataPoint adds a data point to metric.input_type metric. +func (mb *MetricsBuilder) RecordMetricInputTypeDataPoint(ts pcommon.Timestamp, inputVal string, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) error { + val, err := strconv.ParseInt(inputVal, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse int64 for MetricInputType, value was %s: %w", inputVal, err) + } + mb.metricMetricInputType.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue) + return nil +} + // RecordOptionalMetricDataPoint adds a data point to optional.metric metric. func (mb *MetricsBuilder) RecordOptionalMetricDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { mb.metricOptionalMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue) diff --git a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics_test.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics_test.go index 4860ac1ba2b..ac80e2f6608 100644 --- a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics_test.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics_test.go @@ -92,6 +92,10 @@ func TestMetricsBuilder(t *testing.T) { allMetricsCount++ mb.RecordDefaultMetricToBeRemovedDataPoint(ts, 1) + defaultMetricsCount++ + allMetricsCount++ + mb.RecordMetricInputTypeDataPoint(ts, "1", "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}) + allMetricsCount++ mb.RecordOptionalMetricDataPoint(ts, 1, "string_attr-val", true) @@ -172,6 +176,35 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.Equal(t, float64(1), dp.DoubleValue()) + case "metric.input_type": + assert.False(t, validatedMetrics["metric.input_type"], "Found a duplicate in the metrics slice: metric.input_type") + validatedMetrics["metric.input_type"] = true + assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) + assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) + assert.Equal(t, "Monotonic cumulative sum int metric with string input_type enabled by default.", ms.At(i).Description()) + assert.Equal(t, "s", ms.At(i).Unit()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) + dp := ms.At(i).Sum().DataPoints().At(0) + assert.Equal(t, start, dp.StartTimestamp()) + assert.Equal(t, ts, dp.Timestamp()) + assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) + assert.Equal(t, int64(1), dp.IntValue()) + attrVal, ok := dp.Attributes().Get("string_attr") + assert.True(t, ok) + assert.EqualValues(t, "string_attr-val", attrVal.Str()) + attrVal, ok = dp.Attributes().Get("state") + assert.True(t, ok) + assert.EqualValues(t, 19, attrVal.Int()) + attrVal, ok = dp.Attributes().Get("enum_attr") + assert.True(t, ok) + assert.EqualValues(t, "red", attrVal.Str()) + attrVal, ok = dp.Attributes().Get("slice_attr") + assert.True(t, ok) + assert.EqualValues(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) + attrVal, ok = dp.Attributes().Get("map_attr") + assert.True(t, ok) + assert.EqualValues(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) case "optional.metric": assert.False(t, validatedMetrics["optional.metric"], "Found a duplicate in the metrics slice: optional.metric") validatedMetrics["optional.metric"] = true diff --git a/cmd/mdatagen/internal/samplereceiver/internal/metadata/testdata/config.yaml b/cmd/mdatagen/internal/samplereceiver/internal/metadata/testdata/config.yaml index 8283dc2dd70..e0cc02f5ff7 100644 --- a/cmd/mdatagen/internal/samplereceiver/internal/metadata/testdata/config.yaml +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/testdata/config.yaml @@ -5,6 +5,8 @@ all_set: enabled: true default.metric.to_be_removed: enabled: true + metric.input_type: + enabled: true optional.metric: enabled: true optional.metric.empty_unit: @@ -32,6 +34,8 @@ none_set: enabled: false default.metric.to_be_removed: enabled: false + metric.input_type: + enabled: false optional.metric: enabled: false optional.metric.empty_unit: diff --git a/cmd/mdatagen/internal/samplereceiver/metadata.yaml b/cmd/mdatagen/internal/samplereceiver/metadata.yaml index 3bca2833712..802010ebc3f 100644 --- a/cmd/mdatagen/internal/samplereceiver/metadata.yaml +++ b/cmd/mdatagen/internal/samplereceiver/metadata.yaml @@ -137,3 +137,14 @@ metrics: aggregation_temporality: delta warnings: if_enabled: This metric is deprecated and will be removed soon. + + metric.input_type: + enabled: true + description: Monotonic cumulative sum int metric with string input_type enabled by default. + unit: s + sum: + value_type: int + input_type: string + monotonic: true + aggregation_temporality: cumulative + attributes: [ string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr ] diff --git a/cmd/mdatagen/loader_test.go b/cmd/mdatagen/loader_test.go index 677288258d2..98da3801ae4 100644 --- a/cmd/mdatagen/loader_test.go +++ b/cmd/mdatagen/loader_test.go @@ -217,6 +217,18 @@ func TestLoadMetadata(t *testing.T) { Mono: Mono{Monotonic: false}, }, }, + "metric.input_type": { + Enabled: true, + Description: "Monotonic cumulative sum int metric with string input_type enabled by default.", + Unit: strPtr("s"), + Sum: &sum{ + MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeInt}, + MetricInputType: MetricInputType{InputType: "string"}, + AggregationTemporality: AggregationTemporality{Aggregation: pmetric.AggregationTemporalityCumulative}, + Mono: Mono{Monotonic: true}, + }, + Attributes: []attributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr"}, + }, }, ScopeName: "go.opentelemetry.io/collector/internal/receiver/samplereceiver", ShortFolderName: "sample",