diff --git a/.chloggen/optional-attribute.yaml b/.chloggen/optional-attribute.yaml new file mode 100644 index 00000000000..bbbfa41b9d8 --- /dev/null +++ b/.chloggen/optional-attribute.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: cmd/mdatagen + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add support for optional attribute + +# One or more tracking issues or pull requests related to the change +issues: [12571] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [api] diff --git a/cmd/mdatagen/internal/command.go b/cmd/mdatagen/internal/command.go index 35b0afe057f..e48c2cddd87 100644 --- a/cmd/mdatagen/internal/command.go +++ b/cmd/mdatagen/internal/command.go @@ -14,6 +14,7 @@ import ( "regexp" "runtime/debug" "slices" + "sort" "strings" "text/template" @@ -217,6 +218,40 @@ func templatize(tmplFile string, md Metadata) *template.Template { "attributeInfo": func(an AttributeName) Attribute { return md.Attributes[an] }, + "getEventOptionalAttributes": func(attrs map[AttributeName]Attribute) []AttributeName { + seen := make(map[AttributeName]bool) + used := make([]AttributeName, 0) + + for _, event := range md.Events { + for _, attribute := range event.Attributes { + v, exists := attrs[attribute] + if exists && v.Optional && !seen[attribute] { + used = append(used, attribute) + seen[attribute] = true + } + } + } + sort.Slice(used, func(i, j int) bool { return string(used[i]) < string(used[j]) }) + + return used + }, + "getMetricOptionalAttributes": func(attrs map[AttributeName]Attribute) []AttributeName { + seen := make(map[AttributeName]bool) + used := make([]AttributeName, 0) + + for _, event := range md.Metrics { + for _, attribute := range event.Attributes { + v, exists := attrs[attribute] + if exists && v.Optional && !seen[attribute] { + used = append(used, attribute) + seen[attribute] = true + } + } + } + sort.Slice(used, func(i, j int) bool { return string(used[i]) < string(used[j]) }) + + return used + }, "metricInfo": func(mn MetricName) Metric { return md.Metrics[mn] }, @@ -297,7 +332,7 @@ func templatize(tmplFile string, md Metadata) *template.Template { // which uses the `\` as a special character. // Meaning on windows based machines, the `\` needs to be replaced // with a `/` for it to find the file. - }).ParseFS(TemplateFS, strings.ReplaceAll(tmplFile, "\\", "/"))) + }).ParseFS(TemplateFS, "templates/helper.tmpl", strings.ReplaceAll(tmplFile, "\\", "/"))) } func executeTemplate(tmplFile string, md Metadata, goPackage string) ([]byte, error) { diff --git a/cmd/mdatagen/internal/command_test.go b/cmd/mdatagen/internal/command_test.go index 7e191d172da..0ebd35c96f5 100644 --- a/cmd/mdatagen/internal/command_test.go +++ b/cmd/mdatagen/internal/command_test.go @@ -34,6 +34,7 @@ func TestRunContents(t *testing.T) { yml string wantMetricsGenerated bool wantMetricsContext bool + wantLogsGenerated bool wantConfigGenerated bool wantTelemetryGenerated bool wantResourceAttributesGenerated bool @@ -64,6 +65,7 @@ func TestRunContents(t *testing.T) { wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, + wantLogsGenerated: true, }, { yml: "basic_pkg.yaml", @@ -86,6 +88,7 @@ func TestRunContents(t *testing.T) { wantResourceAttributesGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, + wantLogsGenerated: true, }, { yml: "status_only.yaml", @@ -98,6 +101,7 @@ func TestRunContents(t *testing.T) { wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, + wantLogsGenerated: true, }, { yml: "with_tests_exporter.yaml", @@ -158,6 +162,7 @@ func TestRunContents(t *testing.T) { wantReadmeGenerated: true, wantComponentTestGenerated: true, wantAttributes: []string{"name"}, + wantLogsGenerated: true, }, { yml: "invalid_telemetry_missing_value_type_for_histogram.yaml", @@ -178,6 +183,16 @@ func TestRunContents(t *testing.T) { wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, + wantLogsGenerated: true, + }, + { + yml: "with_optional_attribute.yaml", + wantStatusGenerated: true, + wantReadmeGenerated: true, + wantMetricsGenerated: true, + wantLogsGenerated: true, + wantConfigGenerated: true, + wantComponentTestGenerated: true, }, } for _, tt := range tests { @@ -232,6 +247,14 @@ foo require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_metrics_test.go")) } + if tt.wantLogsGenerated { + require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_logs.go")) + require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_logs_test.go")) + } else { + require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_logs.go")) + require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_logs_test.go")) + } + if tt.wantConfigGenerated { require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_config.go")) require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_config_test.go")) diff --git a/cmd/mdatagen/internal/embedded_templates_test.go b/cmd/mdatagen/internal/embedded_templates_test.go index f2591e65bcc..c3f7c0bcf3c 100644 --- a/cmd/mdatagen/internal/embedded_templates_test.go +++ b/cmd/mdatagen/internal/embedded_templates_test.go @@ -39,6 +39,7 @@ func TestEnsureTemplatesLoaded(t *testing.T) { path.Join(rootDir, "testdata", "config.yaml.tmpl"): {}, path.Join(rootDir, "telemetrytest.go.tmpl"): {}, path.Join(rootDir, "telemetrytest_test.go.tmpl"): {}, + path.Join(rootDir, "helper.tmpl"): {}, } count = 0 ) diff --git a/cmd/mdatagen/internal/event.go b/cmd/mdatagen/internal/event.go index 2bafe97b604..22a7a0ec74c 100644 --- a/cmd/mdatagen/internal/event.go +++ b/cmd/mdatagen/internal/event.go @@ -55,3 +55,12 @@ func (l *Event) Unmarshal(parser *confmap.Conf) error { } return parser.Unmarshal(l) } + +func (l Event) HasOptionalAttribute(attrs map[AttributeName]Attribute) bool { + for _, attr := range l.Attributes { + if v, exists := attrs[attr]; exists && v.Optional { + return true + } + } + return false +} diff --git a/cmd/mdatagen/internal/loader_test.go b/cmd/mdatagen/internal/loader_test.go index a50d7e2487a..6ca9642329c 100644 --- a/cmd/mdatagen/internal/loader_test.go +++ b/cmd/mdatagen/internal/loader_test.go @@ -179,6 +179,22 @@ func TestLoadMetadata(t *testing.T) { }, FullName: "map_attr", }, + "optional_int_attr": { + Description: "An optional attribute with an integer value", + Type: ValueType{ + ValueType: pcommon.ValueTypeInt, + }, + FullName: "optional_int_attr", + Optional: true, + }, + "optional_string_attr": { + Description: "An optional attribute with any string value", + Type: ValueType{ + ValueType: pcommon.ValueTypeStr, + }, + FullName: "optional_string_attr", + Optional: true, + }, }, Metrics: map[MetricName]Metric{ "default.metric": { @@ -194,7 +210,7 @@ func TestLoadMetadata(t *testing.T) { AggregationTemporality: AggregationTemporality{Aggregation: pmetric.AggregationTemporalityCumulative}, Mono: Mono{Monotonic: true}, }, - Attributes: []AttributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr"}, + Attributes: []AttributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr", "optional_int_attr", "optional_string_attr"}, }, "optional.metric": { Enabled: false, @@ -206,7 +222,7 @@ func TestLoadMetadata(t *testing.T) { Gauge: &Gauge{ MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeDouble}, }, - Attributes: []AttributeName{"string_attr", "boolean_attr", "boolean_attr2"}, + Attributes: []AttributeName{"string_attr", "boolean_attr", "boolean_attr2", "optional_string_attr"}, }, "optional.metric.empty_unit": { Enabled: false, @@ -255,7 +271,7 @@ func TestLoadMetadata(t *testing.T) { Warnings: Warnings{ IfEnabledNotSet: "This event will be disabled by default soon.", }, - Attributes: []AttributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr"}, + Attributes: []AttributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr", "optional_int_attr", "optional_string_attr"}, }, "default.event.to_be_renamed": { Enabled: false, @@ -264,7 +280,7 @@ func TestLoadMetadata(t *testing.T) { Warnings: Warnings{ IfConfigured: "This event is deprecated and will be renamed soon.", }, - Attributes: []AttributeName{"string_attr", "boolean_attr", "boolean_attr2"}, + Attributes: []AttributeName{"string_attr", "boolean_attr", "boolean_attr2", "optional_string_attr"}, }, "default.event.to_be_removed": { Enabled: true, diff --git a/cmd/mdatagen/internal/metadata.go b/cmd/mdatagen/internal/metadata.go index 73924e893b7..4f1be295bd8 100644 --- a/cmd/mdatagen/internal/metadata.go +++ b/cmd/mdatagen/internal/metadata.go @@ -304,6 +304,8 @@ type Attribute struct { FullName AttributeName `mapstructure:"-"` // Warnings that will be shown to user under specified conditions. Warnings Warnings `mapstructure:"warnings"` + // Optional defines whether the attribute is required. + Optional bool `mapstructure:"optional"` } // Name returns actual name of the attribute that is set on the metric after applying NameOverride. diff --git a/cmd/mdatagen/internal/metric.go b/cmd/mdatagen/internal/metric.go index 9f0b7a942ad..58c97914e39 100644 --- a/cmd/mdatagen/internal/metric.go +++ b/cmd/mdatagen/internal/metric.go @@ -121,6 +121,15 @@ func (m Metric) Data() MetricData { return nil } +func (m Metric) HasOptionalAttribute(attrs map[AttributeName]Attribute) bool { + for _, attr := range m.Attributes { + if v, exists := attrs[attr]; exists && v.Optional { + return true + } + } + return false +} + // MetricData is generic interface for all metric datatypes. type MetricData interface { Type() string diff --git a/cmd/mdatagen/internal/sampleconnector/documentation.md b/cmd/mdatagen/internal/sampleconnector/documentation.md index f2d0a5a761a..41b2ee61eed 100644 --- a/cmd/mdatagen/internal/sampleconnector/documentation.md +++ b/cmd/mdatagen/internal/sampleconnector/documentation.md @@ -24,13 +24,13 @@ The metric will be become optional soon. #### 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 | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| state | Integer attribute with overridden name. | Any Int | false | +| enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | false | +| slice_attr | Attribute with a slice value. | Any Slice | false | +| map_attr | Attribute with a map value. | Any Map | false | ### default.metric.to_be_removed @@ -52,13 +52,13 @@ Monotonic cumulative sum int metric with string input_type enabled by default. #### 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 | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| state | Integer attribute with overridden name. | Any Int | false | +| enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | false | +| slice_attr | Attribute with a slice value. | Any Slice | false | +| map_attr | Attribute with a map value. | Any Map | false | ## Optional Metrics @@ -80,11 +80,11 @@ metrics: #### Attributes -| Name | Description | Values | -| ---- | ----------- | ------ | -| string_attr | Attribute with any string value. | Any Str | -| boolean_attr | Attribute with a boolean value. | Any Bool | -| boolean_attr2 | Another attribute with a boolean value. | Any Bool | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| boolean_attr | Attribute with a boolean value. | Any Bool | false | +| boolean_attr2 | Another attribute with a boolean value. | Any Bool | false | ### optional.metric.empty_unit @@ -96,10 +96,10 @@ metrics: #### Attributes -| Name | Description | Values | -| ---- | ----------- | ------ | -| string_attr | Attribute with any string value. | Any Str | -| boolean_attr | Attribute with a boolean value. | Any Bool | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| boolean_attr | Attribute with a boolean value. | Any Bool | false | ## Resource Attributes diff --git a/cmd/mdatagen/internal/samplereceiver/documentation.md b/cmd/mdatagen/internal/samplereceiver/documentation.md index b47d8a8ff47..3eaf4b2403f 100644 --- a/cmd/mdatagen/internal/samplereceiver/documentation.md +++ b/cmd/mdatagen/internal/samplereceiver/documentation.md @@ -24,13 +24,15 @@ The metric will be become optional soon. #### 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 | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| state | Integer attribute with overridden name. | Any Int | false | +| enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | false | +| slice_attr | Attribute with a slice value. | Any Slice | false | +| map_attr | Attribute with a map value. | Any Map | false | +| optional_int_attr | An optional attribute with an integer value | Any Int | true | +| optional_string_attr | An optional attribute with any string value | Any Str | true | ### default.metric.to_be_removed @@ -52,13 +54,13 @@ Monotonic cumulative sum int metric with string input_type enabled by default. #### 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 | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| state | Integer attribute with overridden name. | Any Int | false | +| enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | false | +| slice_attr | Attribute with a slice value. | Any Slice | false | +| map_attr | Attribute with a map value. | Any Map | false | ## Optional Metrics @@ -80,11 +82,12 @@ metrics: #### Attributes -| Name | Description | Values | -| ---- | ----------- | ------ | -| string_attr | Attribute with any string value. | Any Str | -| boolean_attr | Attribute with a boolean value. | Any Bool | -| boolean_attr2 | Another attribute with a boolean value. | Any Bool | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| boolean_attr | Attribute with a boolean value. | Any Bool | false | +| boolean_attr2 | Another attribute with a boolean value. | Any Bool | false | +| optional_string_attr | An optional attribute with any string value | Any Str | true | ### optional.metric.empty_unit @@ -96,10 +99,10 @@ metrics: #### Attributes -| Name | Description | Values | -| ---- | ----------- | ------ | -| string_attr | Attribute with any string value. | Any Str | -| boolean_attr | Attribute with a boolean value. | Any Bool | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| boolean_attr | Attribute with a boolean value. | Any Bool | false | ## Resource Attributes diff --git a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_logs.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_logs.go index b07d752ebee..8363ed80901 100644 --- a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_logs.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_logs.go @@ -11,23 +11,49 @@ import ( conventions "go.opentelemetry.io/collector/semconv/v1.9.0" ) +type EventAttributeOption interface { + apply(plog.LogRecord) +} + +type eventAttributeOptionFunc func(plog.LogRecord) + +func (eaof eventAttributeOptionFunc) apply(lr plog.LogRecord) { + eaof(lr) +} + +func WithOptionalIntAttrEventAttribute(optionalIntAttrAttributeValue int64) EventAttributeOption { + return eventAttributeOptionFunc(func(dp plog.LogRecord) { + dp.Attributes().PutInt("optional_int_attr", optionalIntAttrAttributeValue) + }) +} + +func WithOptionalStringAttrEventAttribute(optionalStringAttrAttributeValue string) EventAttributeOption { + return eventAttributeOptionFunc(func(dp plog.LogRecord) { + dp.Attributes().PutStr("optional_string_attr", optionalStringAttrAttributeValue) + }) +} + type eventDefaultEvent struct { data plog.LogRecordSlice // data buffer for generated log records. config EventConfig // event config provided by user. } -func (e *eventDefaultEvent) recordEvent(timestamp pcommon.Timestamp, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { +func (e *eventDefaultEvent) recordEvent(timestamp pcommon.Timestamp, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any, options ...EventAttributeOption) { if !e.config.Enabled { return } - lr := e.data.AppendEmpty() - lr.SetEventName("default.event") - lr.SetTimestamp(timestamp) - lr.Attributes().PutStr("string_attr", stringAttrAttributeValue) - lr.Attributes().PutInt("state", overriddenIntAttrAttributeValue) - lr.Attributes().PutStr("enum_attr", enumAttrAttributeValue) - lr.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) - lr.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) + dp := e.data.AppendEmpty() + dp.SetEventName("default.event") + dp.SetTimestamp(timestamp) + 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) + + for _, op := range options { + op.apply(dp) + } } // emit appends recorded event data to a events slice and prepares it for recording another set of log records. @@ -54,14 +80,15 @@ func (e *eventDefaultEventToBeRemoved) recordEvent(timestamp pcommon.Timestamp, if !e.config.Enabled { return } - lr := e.data.AppendEmpty() - lr.SetEventName("default.event.to_be_removed") - lr.SetTimestamp(timestamp) - lr.Attributes().PutStr("string_attr", stringAttrAttributeValue) - lr.Attributes().PutInt("state", overriddenIntAttrAttributeValue) - lr.Attributes().PutStr("enum_attr", enumAttrAttributeValue) - lr.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) - lr.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) + dp := e.data.AppendEmpty() + dp.SetEventName("default.event.to_be_removed") + dp.SetTimestamp(timestamp) + 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) + } // emit appends recorded event data to a events slice and prepares it for recording another set of log records. @@ -84,16 +111,20 @@ type eventDefaultEventToBeRenamed struct { config EventConfig // event config provided by user. } -func (e *eventDefaultEventToBeRenamed) recordEvent(timestamp pcommon.Timestamp, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool) { +func (e *eventDefaultEventToBeRenamed) recordEvent(timestamp pcommon.Timestamp, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool, options ...EventAttributeOption) { if !e.config.Enabled { return } - lr := e.data.AppendEmpty() - lr.SetEventName("default.event.to_be_renamed") - lr.SetTimestamp(timestamp) - lr.Attributes().PutStr("string_attr", stringAttrAttributeValue) - lr.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) - lr.Attributes().PutBool("boolean_attr2", booleanAttr2AttributeValue) + dp := e.data.AppendEmpty() + dp.SetEventName("default.event.to_be_renamed") + dp.SetTimestamp(timestamp) + dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) + dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) + dp.Attributes().PutBool("boolean_attr2", booleanAttr2AttributeValue) + + for _, op := range options { + op.apply(dp) + } } // emit appends recorded event data to a events slice and prepares it for recording another set of log records. @@ -292,8 +323,8 @@ func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { } // RecordDefaultEventEvent adds a log record of default.event event. -func (lb *LogsBuilder) RecordDefaultEventEvent(timestamp pcommon.Timestamp, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { - lb.eventDefaultEvent.recordEvent(timestamp, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue) +func (lb *LogsBuilder) RecordDefaultEventEvent(timestamp pcommon.Timestamp, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any, options ...EventAttributeOption) { + lb.eventDefaultEvent.recordEvent(timestamp, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue, options...) } // RecordDefaultEventToBeRemovedEvent adds a log record of default.event.to_be_removed event. @@ -302,6 +333,6 @@ func (lb *LogsBuilder) RecordDefaultEventToBeRemovedEvent(timestamp pcommon.Time } // RecordDefaultEventToBeRenamedEvent adds a log record of default.event.to_be_renamed event. -func (lb *LogsBuilder) RecordDefaultEventToBeRenamedEvent(timestamp pcommon.Timestamp, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool) { - lb.eventDefaultEventToBeRenamed.recordEvent(timestamp, stringAttrAttributeValue, booleanAttrAttributeValue, booleanAttr2AttributeValue) +func (lb *LogsBuilder) RecordDefaultEventToBeRenamedEvent(timestamp pcommon.Timestamp, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool, options ...EventAttributeOption) { + lb.eventDefaultEventToBeRenamed.recordEvent(timestamp, stringAttrAttributeValue, booleanAttrAttributeValue, booleanAttr2AttributeValue, options...) } diff --git a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_logs_test.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_logs_test.go index 1ce065c9c5e..58143801d3e 100644 --- a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_logs_test.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_logs_test.go @@ -152,13 +152,13 @@ func TestLogsBuilder(t *testing.T) { allEventsCount := 0 defaultEventsCount++ allEventsCount++ - lb.RecordDefaultEventEvent(timestamp, "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}) + lb.RecordDefaultEventEvent(timestamp, "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, WithOptionalIntAttrEventAttribute(17), WithOptionalStringAttrEventAttribute("optional_string_attr-val")) defaultEventsCount++ allEventsCount++ lb.RecordDefaultEventToBeRemovedEvent(timestamp, "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}) allEventsCount++ - lb.RecordDefaultEventToBeRenamedEvent(timestamp, "string_attr-val", true, false) + lb.RecordDefaultEventToBeRenamedEvent(timestamp, "string_attr-val", true, false, WithOptionalStringAttrEventAttribute("optional_string_attr-val")) rb := lb.NewResourceBuilder() rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) @@ -211,6 +211,12 @@ func TestLogsBuilder(t *testing.T) { attrVal, ok = lr.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) + attrVal, ok = lr.Attributes().Get("optional_int_attr") + assert.True(t, ok) + assert.EqualValues(t, 17, attrVal.Int()) + attrVal, ok = lr.Attributes().Get("optional_string_attr") + assert.True(t, ok) + assert.Equal(t, "optional_string_attr-val", attrVal.Str()) case "default.event.to_be_removed": assert.False(t, validatedEvents["default.event.to_be_removed"], "Found a duplicate in the events slice: default.event.to_be_removed") validatedEvents["default.event.to_be_removed"] = true @@ -245,6 +251,9 @@ func TestLogsBuilder(t *testing.T) { attrVal, ok = lr.Attributes().Get("boolean_attr2") assert.True(t, ok) assert.False(t, attrVal.Bool()) + attrVal, ok = lr.Attributes().Get("optional_string_attr") + assert.True(t, ok) + assert.Equal(t, "optional_string_attr-val", attrVal.Str()) } } }) diff --git a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go index 6bc70a5a957..acd07431f8d 100644 --- a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go @@ -75,6 +75,28 @@ type metricInfo struct { Name string } +type MetricAttributeOption interface { + apply(pmetric.NumberDataPoint) +} + +type metricAttributeOptionFunc func(pmetric.NumberDataPoint) + +func (maof metricAttributeOptionFunc) apply(dp pmetric.NumberDataPoint) { + maof(dp) +} + +func WithOptionalIntAttrMetricAttribute(optionalIntAttrAttributeValue int64) MetricAttributeOption { + return metricAttributeOptionFunc(func(dp pmetric.NumberDataPoint) { + dp.Attributes().PutInt("optional_int_attr", optionalIntAttrAttributeValue) + }) +} + +func WithOptionalStringAttrMetricAttribute(optionalStringAttrAttributeValue string) MetricAttributeOption { + return metricAttributeOptionFunc(func(dp pmetric.NumberDataPoint) { + dp.Attributes().PutStr("optional_string_attr", optionalStringAttrAttributeValue) + }) +} + type metricDefaultMetric struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. @@ -92,7 +114,7 @@ func (m *metricDefaultMetric) init() { m.data.Sum().DataPoints().EnsureCapacity(m.capacity) } -func (m *metricDefaultMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { +func (m *metricDefaultMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any, options ...MetricAttributeOption) { if !m.config.Enabled { return } @@ -105,6 +127,9 @@ func (m *metricDefaultMetric) recordDataPoint(start pcommon.Timestamp, ts pcommo dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) + for _, op := range options { + op.apply(dp) + } } // updateCapacity saves max length of data point slices that will be used for the slice capacity. @@ -255,7 +280,7 @@ func (m *metricOptionalMetric) init() { m.data.Gauge().DataPoints().EnsureCapacity(m.capacity) } -func (m *metricOptionalMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool) { +func (m *metricOptionalMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool, options ...MetricAttributeOption) { if !m.config.Enabled { return } @@ -266,6 +291,9 @@ func (m *metricOptionalMetric) recordDataPoint(start pcommon.Timestamp, ts pcomm dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) dp.Attributes().PutBool("boolean_attr2", booleanAttr2AttributeValue) + for _, op := range options { + op.apply(dp) + } } // updateCapacity saves max length of data point slices that will be used for the slice capacity. @@ -569,8 +597,8 @@ func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics } // RecordDefaultMetricDataPoint adds a data point to default.metric metric. -func (mb *MetricsBuilder) RecordDefaultMetricDataPoint(ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { - mb.metricDefaultMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue) +func (mb *MetricsBuilder) RecordDefaultMetricDataPoint(ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any, options ...MetricAttributeOption) { + mb.metricDefaultMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue, options...) } // RecordDefaultMetricToBeRemovedDataPoint adds a data point to default.metric.to_be_removed metric. @@ -589,8 +617,8 @@ func (mb *MetricsBuilder) RecordMetricInputTypeDataPoint(ts pcommon.Timestamp, i } // RecordOptionalMetricDataPoint adds a data point to optional.metric metric. -func (mb *MetricsBuilder) RecordOptionalMetricDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool) { - mb.metricOptionalMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue, booleanAttr2AttributeValue) +func (mb *MetricsBuilder) RecordOptionalMetricDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool, options ...MetricAttributeOption) { + mb.metricOptionalMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue, booleanAttr2AttributeValue, options...) } // RecordOptionalMetricEmptyUnitDataPoint adds a data point to optional.metric.empty_unit metric. 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 3ab8a21407e..e11ac2a2e84 100644 --- a/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics_test.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics_test.go @@ -99,7 +99,7 @@ func TestMetricsBuilder(t *testing.T) { defaultMetricsCount++ allMetricsCount++ - mb.RecordDefaultMetricDataPoint(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"}) + mb.RecordDefaultMetricDataPoint(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"}, WithOptionalIntAttrMetricAttribute(17), WithOptionalStringAttrMetricAttribute("optional_string_attr-val")) defaultMetricsCount++ allMetricsCount++ @@ -110,7 +110,7 @@ func TestMetricsBuilder(t *testing.T) { 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, false) + mb.RecordOptionalMetricDataPoint(ts, 1, "string_attr-val", true, false, WithOptionalStringAttrMetricAttribute("optional_string_attr-val")) allMetricsCount++ mb.RecordOptionalMetricEmptyUnitDataPoint(ts, 1, "string_attr-val", true) @@ -175,6 +175,12 @@ func TestMetricsBuilder(t *testing.T) { attrVal, ok = dp.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) + attrVal, ok = dp.Attributes().Get("optional_int_attr") + assert.True(t, ok) + assert.EqualValues(t, 17, attrVal.Int()) + attrVal, ok = dp.Attributes().Get("optional_string_attr") + assert.True(t, ok) + assert.Equal(t, "optional_string_attr-val", attrVal.Str()) case "default.metric.to_be_removed": assert.False(t, validatedMetrics["default.metric.to_be_removed"], "Found a duplicate in the metrics slice: default.metric.to_be_removed") validatedMetrics["default.metric.to_be_removed"] = true @@ -239,6 +245,9 @@ func TestMetricsBuilder(t *testing.T) { attrVal, ok = dp.Attributes().Get("boolean_attr2") assert.True(t, ok) assert.False(t, attrVal.Bool()) + attrVal, ok = dp.Attributes().Get("optional_string_attr") + assert.True(t, ok) + assert.Equal(t, "optional_string_attr-val", attrVal.Str()) case "optional.metric.empty_unit": assert.False(t, validatedMetrics["optional.metric.empty_unit"], "Found a duplicate in the metrics slice: optional.metric.empty_unit") validatedMetrics["optional.metric.empty_unit"] = true diff --git a/cmd/mdatagen/internal/samplereceiver/metadata.yaml b/cmd/mdatagen/internal/samplereceiver/metadata.yaml index aa7e927d6f5..2aa0056f65e 100644 --- a/cmd/mdatagen/internal/samplereceiver/metadata.yaml +++ b/cmd/mdatagen/internal/samplereceiver/metadata.yaml @@ -106,11 +106,21 @@ attributes: description: Attribute with a map value. type: map + optional_int_attr: + description: An optional attribute with an integer value + type: int + optional: true + + optional_string_attr: + description: An optional attribute with any string value + type: string + optional: true + events: default.event: enabled: true description: Example event enabled by default. - attributes: [ string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr ] + attributes: [ string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr, optional_int_attr, optional_string_attr] warnings: if_enabled_not_set: This event will be disabled by default soon. @@ -118,7 +128,7 @@ events: enabled: false description: "[DEPRECATED] Example event disabled by default." extended_documentation: The event will be renamed soon. - attributes: [ string_attr, boolean_attr, boolean_attr2 ] + attributes: [ string_attr, boolean_attr, boolean_attr2, optional_string_attr ] warnings: if_configured: This event is deprecated and will be renamed soon. @@ -140,7 +150,7 @@ metrics: value_type: int monotonic: true aggregation_temporality: cumulative - attributes: [string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr] + attributes: [string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr, optional_int_attr, optional_string_attr] warnings: if_enabled_not_set: This metric will be disabled by default soon. @@ -150,7 +160,7 @@ metrics: unit: "1" gauge: value_type: double - attributes: [string_attr, boolean_attr, boolean_attr2] + attributes: [string_attr, boolean_attr, boolean_attr2, optional_string_attr] warnings: if_configured: This metric is deprecated and will be removed soon. diff --git a/cmd/mdatagen/internal/samplescraper/documentation.md b/cmd/mdatagen/internal/samplescraper/documentation.md index f2d0a5a761a..41b2ee61eed 100644 --- a/cmd/mdatagen/internal/samplescraper/documentation.md +++ b/cmd/mdatagen/internal/samplescraper/documentation.md @@ -24,13 +24,13 @@ The metric will be become optional soon. #### 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 | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| state | Integer attribute with overridden name. | Any Int | false | +| enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | false | +| slice_attr | Attribute with a slice value. | Any Slice | false | +| map_attr | Attribute with a map value. | Any Map | false | ### default.metric.to_be_removed @@ -52,13 +52,13 @@ Monotonic cumulative sum int metric with string input_type enabled by default. #### 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 | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| state | Integer attribute with overridden name. | Any Int | false | +| enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | false | +| slice_attr | Attribute with a slice value. | Any Slice | false | +| map_attr | Attribute with a map value. | Any Map | false | ## Optional Metrics @@ -80,11 +80,11 @@ metrics: #### Attributes -| Name | Description | Values | -| ---- | ----------- | ------ | -| string_attr | Attribute with any string value. | Any Str | -| boolean_attr | Attribute with a boolean value. | Any Bool | -| boolean_attr2 | Another attribute with a boolean value. | Any Bool | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| boolean_attr | Attribute with a boolean value. | Any Bool | false | +| boolean_attr2 | Another attribute with a boolean value. | Any Bool | false | ### optional.metric.empty_unit @@ -96,10 +96,10 @@ metrics: #### Attributes -| Name | Description | Values | -| ---- | ----------- | ------ | -| string_attr | Attribute with any string value. | Any Str | -| boolean_attr | Attribute with a boolean value. | Any Bool | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| boolean_attr | Attribute with a boolean value. | Any Bool | false | ## Resource Attributes diff --git a/cmd/mdatagen/internal/templates/documentation.md.tmpl b/cmd/mdatagen/internal/templates/documentation.md.tmpl index 615431e12a0..2ee0bcff82a 100644 --- a/cmd/mdatagen/internal/templates/documentation.md.tmpl +++ b/cmd/mdatagen/internal/templates/documentation.md.tmpl @@ -22,12 +22,12 @@ #### Attributes -| Name | Description | Values | -| ---- | ----------- | ------ | +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | {{- range $metric.Attributes }} {{- $attribute := . | attributeInfo }} | {{ $attribute.Name }} | {{ $attribute.Description }} | -{{- if $attribute.Enum }} {{ $attribute.Type }}: ``{{ stringsJoin $attribute.Enum "``, ``" }}``{{ else }} Any {{ $attribute.Type }}{{ end }} | +{{- if $attribute.Enum }} {{ $attribute.Type }}: ``{{ stringsJoin $attribute.Enum "``, ``" }}``{{ else }} Any {{ $attribute.Type }}{{ end }} | {{ $attribute.Optional }} | {{- end }} {{- end }} diff --git a/cmd/mdatagen/internal/templates/helper.tmpl b/cmd/mdatagen/internal/templates/helper.tmpl new file mode 100644 index 00000000000..2fdca5ec42c --- /dev/null +++ b/cmd/mdatagen/internal/templates/helper.tmpl @@ -0,0 +1,15 @@ +{{- define "putAttribute" -}} + {{- if eq (attributeInfo .).Type.Primitive "[]byte" }} + dp.Attributes().PutEmptyBytes("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) + {{- else if eq (attributeInfo .).Type.Primitive "[]any" }} + dp.Attributes().PutEmptySlice("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) + {{- else if eq (attributeInfo .).Type.Primitive "map[string]any" }} + dp.Attributes().PutEmptyMap("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) + {{- else }} + dp.Attributes().Put{{ (attributeInfo .).Type }}("{{ (attributeInfo .).Name }}", {{ .RenderUnexported }}AttributeValue) + {{- end }} +{{- end -}} + +{{- define "getAttributeValue" -}} +{{ if (attributeInfo .).Enum }}Attribute{{ .Render }}{{ (index (attributeInfo .).Enum 0) | publicVar }}{{ else }}{{ (attributeInfo .).TestValue }}{{ end }} +{{- end -}} diff --git a/cmd/mdatagen/internal/templates/logs.go.tmpl b/cmd/mdatagen/internal/templates/logs.go.tmpl index ce174d396cd..eed85887e7f 100644 --- a/cmd/mdatagen/internal/templates/logs.go.tmpl +++ b/cmd/mdatagen/internal/templates/logs.go.tmpl @@ -15,6 +15,26 @@ import ( ) +{{ if getEventOptionalAttributes .Attributes }} +type EventAttributeOption interface { + apply(plog.LogRecord) +} + +type eventAttributeOptionFunc func(plog.LogRecord) + +func (eaof eventAttributeOptionFunc) apply(lr plog.LogRecord) { + eaof(lr) +} + +{{ range getEventOptionalAttributes .Attributes }} +func With{{ .Render }}EventAttribute({{ .RenderUnexported }}AttributeValue {{ (attributeInfo .).Type.Primitive }}) EventAttributeOption { + return eventAttributeOptionFunc(func(dp plog.LogRecord) { + {{- template "putAttribute" . }} + }) +} +{{ end }} +{{ end }} + {{ range $name, $event := .Events -}} type event{{ $name.Render }} struct { data plog.LogRecordSlice // data buffer for generated log records. @@ -22,23 +42,23 @@ type event{{ $name.Render }} struct { } func (e *event{{ $name.Render }}) recordEvent(timestamp pcommon.Timestamp -{{- range $event.Attributes -}}, {{ .RenderUnexported }}AttributeValue {{ (attributeInfo .).Type.Primitive }}{{ end }}) { +{{- range $event.Attributes -}}{{- if not (attributeInfo .).Optional -}}, {{ .RenderUnexported }}AttributeValue {{ (attributeInfo .).Type.Primitive }}{{ end }}{{end}}{{- if $event.HasOptionalAttribute $.Attributes -}}, options ...EventAttributeOption{{- end -}}) { if !e.config.Enabled { return } - lr := e.data.AppendEmpty() - lr.SetEventName("{{ $name }}") - lr.SetTimestamp(timestamp) + dp := e.data.AppendEmpty() + dp.SetEventName("{{ $name }}") + dp.SetTimestamp(timestamp) {{- range $event.Attributes }} - {{- if eq (attributeInfo .).Type.Primitive "[]byte" }} - lr.Attributes().PutEmptyBytes("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) - {{- else if eq (attributeInfo .).Type.Primitive "[]any" }} - lr.Attributes().PutEmptySlice("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) - {{- else if eq (attributeInfo .).Type.Primitive "map[string]any" }} - lr.Attributes().PutEmptyMap("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) - {{- else }} - lr.Attributes().Put{{ (attributeInfo .).Type }}("{{ (attributeInfo .).Name }}", {{ .RenderUnexported }}AttributeValue) + {{- if not (attributeInfo .).Optional -}} + {{- template "putAttribute" . }} + {{- end }} {{- end }} + + {{ if $event.HasOptionalAttribute $.Attributes }} + for _, op := range options { + op.apply(dp) + } {{- end }} } @@ -238,11 +258,21 @@ func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { // Record{{ $name.Render }}Event adds a log record of {{ $name }} event. func (lb *LogsBuilder) Record{{ $name.Render }}Event(timestamp pcommon.Timestamp {{- range $event.Attributes -}} + {{- if not (attributeInfo .).Optional -}} , {{ .RenderUnexported }}AttributeValue {{ if (attributeInfo .).Enum }}Attribute{{ .Render }}{{ else }}{{ (attributeInfo .).Type.Primitive }}{{ end }} - {{- end }}) { + {{- end -}} + {{- end -}} + {{- if $event.HasOptionalAttribute $.Attributes -}} + , options... EventAttributeOption + {{- end -}}) { lb.event{{ $name.Render }}.recordEvent(timestamp {{- range $event.Attributes -}} + {{- if not (attributeInfo .).Optional -}} , {{ .RenderUnexported }}AttributeValue{{ if (attributeInfo .).Enum }}.String(){{ end }} - {{- end }}) + {{- end -}} + {{- end -}} + {{- if $event.HasOptionalAttribute $.Attributes -}} + , options... + {{- end -}}) } {{ end }} diff --git a/cmd/mdatagen/internal/templates/logs_test.go.tmpl b/cmd/mdatagen/internal/templates/logs_test.go.tmpl index 764bed7564c..b55b7f0337a 100644 --- a/cmd/mdatagen/internal/templates/logs_test.go.tmpl +++ b/cmd/mdatagen/internal/templates/logs_test.go.tmpl @@ -187,8 +187,16 @@ func TestLogsBuilder(t *testing.T) { allEventsCount++ lb.Record{{ $name.Render }}Event(timestamp {{- range $event.Attributes -}} - , {{ if (attributeInfo .).Enum }}Attribute{{ .Render }}{{ (index (attributeInfo .).Enum 0) | publicVar }}{{ else }}{{ (attributeInfo .).TestValue }}{{ end }} - {{- end }}) + {{- if not (attributeInfo .).Optional -}} + , {{- template "getAttributeValue" . -}} + {{- end -}} + {{- end -}} + {{- range $event.Attributes -}} + {{- if (attributeInfo .).Optional -}} + , With{{ .Render }}EventAttribute({{- template "getAttributeValue" . -}}) + {{- end -}} + {{- end -}} + ) {{- end }} {{ if .ResourceAttributes }} diff --git a/cmd/mdatagen/internal/templates/metrics.go.tmpl b/cmd/mdatagen/internal/templates/metrics.go.tmpl index 938b4fa5613..b41cfb70d0e 100644 --- a/cmd/mdatagen/internal/templates/metrics.go.tmpl +++ b/cmd/mdatagen/internal/templates/metrics.go.tmpl @@ -74,6 +74,26 @@ type metricInfo struct { Name string } +{{ if getMetricOptionalAttributes .Attributes }} +type MetricAttributeOption interface { + apply(pmetric.NumberDataPoint) +} + +type metricAttributeOptionFunc func(pmetric.NumberDataPoint) + +func (maof metricAttributeOptionFunc) apply(dp pmetric.NumberDataPoint) { + maof(dp) +} + +{{ range getMetricOptionalAttributes .Attributes }} +func With{{ .Render }}MetricAttribute({{ .RenderUnexported }}AttributeValue {{ (attributeInfo .).Type.Primitive }}) MetricAttributeOption { + return metricAttributeOptionFunc(func(dp pmetric.NumberDataPoint) { + {{- template "putAttribute" . }} + }) +} +{{ end }} +{{ end }} + {{ range $name, $metric := .Metrics -}} type metric{{ $name.Render }} struct { data pmetric.Metric // data buffer for generated metric. @@ -99,7 +119,7 @@ func (m *metric{{ $name.Render }}) init() { } func (m *metric{{ $name.Render }}) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val {{ $metric.Data.MetricValueType.BasicType }} -{{- range $metric.Attributes -}}, {{ .RenderUnexported }}AttributeValue {{ (attributeInfo .).Type.Primitive }}{{ end }}) { +{{- range $metric.Attributes -}}{{- if not (attributeInfo .).Optional -}}, {{ .RenderUnexported }}AttributeValue {{ (attributeInfo .).Type.Primitive }}{{ end }}{{ end }}{{- if $metric.HasOptionalAttribute $.Attributes -}}, options ...MetricAttributeOption{{- end -}}) { if !m.config.Enabled { return } @@ -108,16 +128,16 @@ func (m *metric{{ $name.Render }}) recordDataPoint(start pcommon.Timestamp, ts p dp.SetTimestamp(ts) dp.Set{{ $metric.Data.MetricValueType }}Value(val) {{- range $metric.Attributes }} - {{- if eq (attributeInfo .).Type.Primitive "[]byte" }} - dp.Attributes().PutEmptyBytes("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) - {{- else if eq (attributeInfo .).Type.Primitive "[]any" }} - dp.Attributes().PutEmptySlice("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) - {{- else if eq (attributeInfo .).Type.Primitive "map[string]any" }} - dp.Attributes().PutEmptyMap("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) - {{- else }} - dp.Attributes().Put{{ (attributeInfo .).Type }}("{{ (attributeInfo .).Name }}", {{ .RenderUnexported }}AttributeValue) + {{- if not (attributeInfo .).Optional -}} + {{- template "putAttribute" . -}} {{- end }} {{- end }} + + {{- if $metric.HasOptionalAttribute $.Attributes }} + for _, op := range options { + op.apply(dp) + } + {{- end }} } // updateCapacity saves max length of data point slices that will be used for the slice capacity. @@ -357,8 +377,14 @@ func (mb *MetricsBuilder) Record{{ $name.Render }}DataPoint(ts pcommon.Timestamp {{- else }}, val {{ $metric.Data.MetricValueType.BasicType }} {{- end }} {{- range $metric.Attributes -}} + {{- if not (attributeInfo .).Optional -}} , {{ .RenderUnexported }}AttributeValue {{ if (attributeInfo .).Enum }}Attribute{{ .Render }}{{ else }}{{ (attributeInfo .).Type.Primitive }}{{ end }} - {{- end }}) + {{- end -}} + {{- end -}} + {{- if $metric.HasOptionalAttribute $.Attributes -}} + , options... MetricAttributeOption + {{- end -}} + ) {{- if $metric.Data.HasMetricInputType }} error{{ end }} { {{- if $metric.Data.HasMetricInputType }} {{- if eq $metric.Data.MetricValueType.BasicType "float64" }} @@ -372,8 +398,14 @@ func (mb *MetricsBuilder) Record{{ $name.Render }}DataPoint(ts pcommon.Timestamp {{- end }} mb.metric{{ $name.Render }}.recordDataPoint(mb.startTime, ts, val {{- range $metric.Attributes -}} + {{- if not (attributeInfo .).Optional -}} , {{ .RenderUnexported }}AttributeValue{{ if (attributeInfo .).Enum }}.String(){{ end }} - {{- end }}) + {{- end -}} + {{- end -}} + {{- if $metric.HasOptionalAttribute $.Attributes -}} + , options... + {{- end -}} + ) {{- if $metric.Data.HasMetricInputType }} return nil {{- end }} diff --git a/cmd/mdatagen/internal/templates/metrics_test.go.tmpl b/cmd/mdatagen/internal/templates/metrics_test.go.tmpl index a32dd9a0e45..d4ec81f66ec 100644 --- a/cmd/mdatagen/internal/templates/metrics_test.go.tmpl +++ b/cmd/mdatagen/internal/templates/metrics_test.go.tmpl @@ -121,8 +121,16 @@ func TestMetricsBuilder(t *testing.T) { allMetricsCount++ mb.Record{{ $name.Render }}DataPoint(ts, {{ if $metric.Data.HasMetricInputType }}"1"{{ else }}1{{ end }} {{- range $metric.Attributes -}} - , {{ if (attributeInfo .).Enum }}Attribute{{ .Render }}{{ (index (attributeInfo .).Enum 0) | publicVar }}{{ else }}{{ (attributeInfo .).TestValue }}{{ end }} - {{- end }}) + {{- if not (attributeInfo .).Optional -}} + , {{- template "getAttributeValue" . -}} + {{- end -}} + {{- end -}} + {{- range $metric.Attributes -}} + {{- if (attributeInfo .).Optional -}} + , With{{ .Render }}MetricAttribute({{- template "getAttributeValue" . -}}) + {{- end -}} + {{- end -}} + ) {{- end }} {{ if .ResourceAttributes }} diff --git a/cmd/mdatagen/internal/testdata/async_metric.yaml b/cmd/mdatagen/internal/testdata/async_metric.yaml index 5c344009696..5d6949f28bf 100644 --- a/cmd/mdatagen/internal/testdata/async_metric.yaml +++ b/cmd/mdatagen/internal/testdata/async_metric.yaml @@ -3,7 +3,6 @@ type: metricreceiver status: class: receiver stability: - development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] diff --git a/cmd/mdatagen/internal/testdata/metrics_and_type.yaml b/cmd/mdatagen/internal/testdata/metrics_and_type.yaml index 2306a08b35e..951f93f7d0a 100644 --- a/cmd/mdatagen/internal/testdata/metrics_and_type.yaml +++ b/cmd/mdatagen/internal/testdata/metrics_and_type.yaml @@ -3,7 +3,6 @@ type: metricreceiver status: class: receiver stability: - development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] diff --git a/cmd/mdatagen/internal/testdata/with_optional_attribute.yaml b/cmd/mdatagen/internal/testdata/with_optional_attribute.yaml new file mode 100644 index 00000000000..5be0edd2960 --- /dev/null +++ b/cmd/mdatagen/internal/testdata/with_optional_attribute.yaml @@ -0,0 +1,29 @@ +type: receiver + +status: + class: receiver + stability: + development: [logs] + beta: [traces] + stable: [metrics] + +attributes: + optional_int_attr: + description: Optional int attr. + type: string + optional: true + +metrics: + metric: + enabled: true + description: Metric. + unit: "1" + gauge: + value_type: double + attributes: [optional_int_attr] + +events: + event: + enabled: true + description: Event. + attributes: [optional_int_attr] diff --git a/cmd/mdatagen/metadata-schema.yaml b/cmd/mdatagen/metadata-schema.yaml index 0aeaf9ea169..3a711edaa1a 100644 --- a/cmd/mdatagen/metadata-schema.yaml +++ b/cmd/mdatagen/metadata-schema.yaml @@ -78,6 +78,8 @@ attributes: enum: [string] # Required: attribute value type. type: + # Optional: indicates whether the attribute is optional or not. + optional: # Optional: map of metric names with the key being the metric name and value # being described below.