diff --git a/.chloggen/mdatagen-complete-host.yaml b/.chloggen/mdatagen-complete-host.yaml new file mode 100644 index 000000000000..4d3c3107cb41 --- /dev/null +++ b/.chloggen/mdatagen-complete-host.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: Use a custom host implementation for lifecycle tests + +# One or more tracking issues or pull requests related to the change +issues: [13589] + +# (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: Use a custom noop host implementation that implements all non-deprecated, publicly-accessible interfaces implemented by the Collector service. + +# 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: [] diff --git a/.github/workflows/utils/cspell.json b/.github/workflows/utils/cspell.json index a8e2be148d6a..5314962ff1e2 100644 --- a/.github/workflows/utils/cspell.json +++ b/.github/workflows/utils/cspell.json @@ -405,6 +405,7 @@ "rrschulze", "runperf", "safelist", + "samplefactoryreceiver", "samplereceiver", "samplingdecision", "samplingprocessor", diff --git a/cmd/mdatagen/go.mod b/cmd/mdatagen/go.mod index 7eb4725df714..4c8931534e01 100644 --- a/cmd/mdatagen/go.mod +++ b/cmd/mdatagen/go.mod @@ -23,6 +23,7 @@ require ( go.opentelemetry.io/collector/receiver/receivertest v0.131.0 go.opentelemetry.io/collector/scraper v0.131.0 go.opentelemetry.io/collector/scraper/scrapertest v0.131.0 + go.opentelemetry.io/collector/service/hostcapabilities v0.131.0 go.opentelemetry.io/otel v1.37.0 go.opentelemetry.io/otel/metric v1.37.0 go.opentelemetry.io/otel/sdk/metric v1.37.0 @@ -65,14 +66,15 @@ require ( go.opentelemetry.io/collector/pipeline/xpipeline v0.131.0 // indirect go.opentelemetry.io/collector/processor/xprocessor v0.131.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.131.0 // indirect + go.opentelemetry.io/collector/service v0.131.0 // indirect go.opentelemetry.io/contrib/bridges/otelzap v0.12.0 // indirect go.opentelemetry.io/otel/log v0.13.0 // indirect go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.40.0 // indirect - golang.org/x/sys v0.33.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/sys v0.34.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/grpc v1.74.2 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -141,3 +143,61 @@ replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../../internal/ replace go.opentelemetry.io/collector/connector/xconnector => ../../connector/xconnector replace go.opentelemetry.io/collector/internal/telemetry => ../../internal/telemetry + +replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest + +replace go.opentelemetry.io/collector/exporter => ../../exporter + +replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap + +replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware + +replace go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware + +replace go.opentelemetry.io/collector/exporter/exportertest => ../../exporter/exportertest + +replace go.opentelemetry.io/collector/client => ../../client + +replace go.opentelemetry.io/collector/extension => ../../extension + +replace go.opentelemetry.io/collector/config/configauth => ../../config/configauth + +replace go.opentelemetry.io/collector/otelcol => ../../otelcol + +replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest + +replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension + +replace go.opentelemetry.io/collector/extension/zpagesextension => ../../extension/zpagesextension + +replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry + +replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional + +replace go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque + +replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest + +replace go.opentelemetry.io/collector/service => ../../service + +replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth + +replace go.opentelemetry.io/collector/service/hostcapabilities => ../../service/hostcapabilities + +replace go.opentelemetry.io/collector/confmap/provider/yamlprovider => ../../confmap/provider/yamlprovider + +replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls + +replace go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression + +replace go.opentelemetry.io/collector/exporter/xexporter => ../../exporter/xexporter + +replace go.opentelemetry.io/collector/config/configtelemetry => ../../config/configtelemetry + +replace go.opentelemetry.io/collector/config/confighttp => ../../config/confighttp + +replace go.opentelemetry.io/collector => ../.. + +replace go.opentelemetry.io/collector/extension/extensioncapabilities => ../../extension/extensioncapabilities + +replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata diff --git a/cmd/mdatagen/go.sum b/cmd/mdatagen/go.sum index b4f0737e692e..1e915af74b43 100644 --- a/cmd/mdatagen/go.sum +++ b/cmd/mdatagen/go.sum @@ -98,16 +98,16 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= @@ -120,8 +120,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= diff --git a/cmd/mdatagen/internal/loader.go b/cmd/mdatagen/internal/loader.go index fb61333e12af..161e3bf50a77 100644 --- a/cmd/mdatagen/internal/loader.go +++ b/cmd/mdatagen/internal/loader.go @@ -39,7 +39,7 @@ func LoadMetadata(filePath string) (Metadata, error) { return Metadata{}, err } - md := Metadata{ShortFolderName: shortFolderName(filePath), Tests: Tests{Host: "componenttest.NewNopHost()"}} + md := Metadata{ShortFolderName: shortFolderName(filePath), Tests: Tests{Host: "newMdatagenNopHost()"}} err = conf.Unmarshal(&md) if err != nil { return md, err diff --git a/cmd/mdatagen/internal/loader_test.go b/cmd/mdatagen/internal/loader_test.go index 583578d5f0bd..4ea52e111d93 100644 --- a/cmd/mdatagen/internal/loader_test.go +++ b/cmd/mdatagen/internal/loader_test.go @@ -400,7 +400,7 @@ func TestLoadMetadata(t *testing.T) { }, ScopeName: "go.opentelemetry.io/collector/internal/receiver/samplereceiver", ShortFolderName: "sample", - Tests: Tests{Host: "componenttest.NewNopHost()"}, + Tests: Tests{Host: "newMdatagenNopHost()"}, }, }, { @@ -412,7 +412,7 @@ func TestLoadMetadata(t *testing.T) { ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", PackageName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", ShortFolderName: "testdata", - Tests: Tests{Host: "componenttest.NewNopHost()"}, + Tests: Tests{Host: "newMdatagenNopHost()"}, }, }, { @@ -423,7 +423,7 @@ func TestLoadMetadata(t *testing.T) { ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", PackageName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", ShortFolderName: "testdata", - Tests: Tests{Host: "componenttest.NewNopHost()"}, + Tests: Tests{Host: "newMdatagenNopHost()"}, Status: &Status{ Class: "receiver", Stability: map[component.StabilityLevel][]string{ @@ -442,7 +442,7 @@ func TestLoadMetadata(t *testing.T) { ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", PackageName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", ShortFolderName: "testdata", - Tests: Tests{Host: "componenttest.NewNopHost()"}, + Tests: Tests{Host: "newMdatagenNopHost()"}, Status: &Status{ Class: "receiver", Stability: map[component.StabilityLevel][]string{ diff --git a/cmd/mdatagen/internal/sampleconnector/generated_component_test.go b/cmd/mdatagen/internal/sampleconnector/generated_component_test.go index 5e013cc3e078..08dde142959e 100644 --- a/cmd/mdatagen/internal/sampleconnector/generated_component_test.go +++ b/cmd/mdatagen/internal/sampleconnector/generated_component_test.go @@ -63,7 +63,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstConnector, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstConnector.Start(context.Background(), host)) require.NoError(t, firstConnector.Shutdown(context.Background())) @@ -74,3 +74,19 @@ func TestComponentLifecycle(t *testing.T) { }) } } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/cmd/mdatagen/internal/sampleconnector/metrics_test.go b/cmd/mdatagen/internal/sampleconnector/metrics_test.go index aff84fc64268..4aaaef1837ba 100644 --- a/cmd/mdatagen/internal/sampleconnector/metrics_test.go +++ b/cmd/mdatagen/internal/sampleconnector/metrics_test.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/cmd/mdatagen/internal/sampleconnector/internal/metadata" - "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pmetric" @@ -24,7 +23,7 @@ func TestGeneratedMetrics(t *testing.T) { } func TestNopConnector(t *testing.T) { - connector, err := createMetricsToMetricsConnector(context.Background(), connectortest.NewNopSettings(metadata.Type), componenttest.NewNopHost(), new(consumertest.MetricsSink)) + connector, err := createMetricsToMetricsConnector(context.Background(), connectortest.NewNopSettings(metadata.Type), newMdatagenNopHost(), new(consumertest.MetricsSink)) require.NoError(t, err) require.False(t, connector.Capabilities().MutatesData) require.NoError(t, connector.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/README.md b/cmd/mdatagen/internal/samplefactoryreceiver/README.md new file mode 100644 index 000000000000..6a12429d7cff --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/README.md @@ -0,0 +1,28 @@ +# Sample Receiver +This receiver is used for testing purposes to check the output of mdatagen. + +| Status | | +| ------------- |-----------| +| Stability | [deprecated]: profiles | +| | [development]: logs | +| | [beta]: traces | +| | [stable]: metrics | +| Deprecation of profiles | [Date]: 2025-02-05 | +| | [Migration Note]: no migration needed | +| Unsupported Platforms | freebsd, illumos | +| Distributions | [] | +| Warnings | [Any additional information that should be brought to the consumer's attention](#warnings) | +| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fsamplefactory%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fsamplefactory) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fsamplefactory%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fsamplefactory) | +| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@dmitryax](https://www.github.com/dmitryax) | + +[deprecated]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecated +[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development +[beta]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#beta +[stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable +[Date]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information +[Migration Note]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information + + +## Warnings + +This is where warnings are described. diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/doc.go b/cmd/mdatagen/internal/samplefactoryreceiver/doc.go new file mode 100644 index 000000000000..4866c4a67a30 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/doc.go @@ -0,0 +1,7 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Generate a test metrics builder from a sample metrics set covering all configuration options. +//go:generate mdatagen metadata.yaml + +package samplefactoryreceiver // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplefactoryreceiver" diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/documentation.md b/cmd/mdatagen/internal/samplefactoryreceiver/documentation.md new file mode 100644 index 000000000000..64856552e710 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/documentation.md @@ -0,0 +1,231 @@ +[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) + +# sample + +## Default Metrics + +The following metrics are emitted by default. Each of them can be disabled by applying the following configuration: + +```yaml +metrics: + : + enabled: false +``` + +### default.metric + +Monotonic cumulative sum int metric enabled by default. + +The metric will be become optional soon. + +| Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | +| ---- | ----------- | ---------- | ----------------------- | --------- | +| s | Sum | Int | Cumulative | true | + +#### Attributes + +| 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 + +[DEPRECATED] Non-monotonic delta sum double metric enabled by default. + +The metric will be removed soon. + +| Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | +| ---- | ----------- | ---------- | ----------------------- | --------- | +| 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 | 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 + +The following metrics are not emitted by default. Each of them can be enabled by applying the following configuration: + +```yaml +metrics: + : + enabled: true +``` + +### optional.metric + +[DEPRECATED] Gauge double metric disabled by default. + +| Unit | Metric Type | Value Type | +| ---- | ----------- | ---------- | +| 1 | Gauge | Double | + +#### Attributes + +| 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 + +[DEPRECATED] Gauge double metric disabled by default. + +| Unit | Metric Type | Value Type | +| ---- | ----------- | ---------- | +| | Gauge | Double | + +#### Attributes + +| Name | Description | Values | Optional | +| ---- | ----------- | ------ | -------- | +| string_attr | Attribute with any string value. | Any Str | false | +| boolean_attr | Attribute with a boolean value. | Any Bool | false | + +## Default Events + +The following events are emitted by default. Each of them can be disabled by applying the following configuration: + +```yaml +events: + : + enabled: false +``` + +### default.event + +Example event 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 | +| optional_int_attr | An optional attribute with an integer value | Any Int | +| optional_string_attr | An optional attribute with any string value | Any Str | + +### default.event.to_be_removed + +[DEPRECATED] Example to-be-removed event enabled by default. + +The event will be removed 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 | + +## Optional Events + +The following events are not emitted by default. Each of them can be enabled by applying the following configuration: + +```yaml +events: + : + enabled: true +``` + +### default.event.to_be_renamed + +[DEPRECATED] Example event disabled by default. + +The event will be renamed soon. + +#### 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 | +| optional_string_attr | An optional attribute with any string value | Any Str | + +## Resource Attributes + +| Name | Description | Values | Enabled | +| ---- | ----------- | ------ | ------- | +| map.resource.attr | Resource attribute with a map value. | Any Map | true | +| optional.resource.attr | Explicitly disabled ResourceAttribute. | Any Str | false | +| slice.resource.attr | Resource attribute with a slice value. | Any Slice | true | +| string.enum.resource.attr | Resource attribute with a known set of string values. | Str: ``one``, ``two`` | true | +| string.resource.attr | Resource attribute with any string value. | Any Str | true | +| string.resource.attr_disable_warning | Resource attribute with any string value. | Any Str | true | +| string.resource.attr_remove_warning | Resource attribute with any string value. | Any Str | false | +| string.resource.attr_to_be_removed | Resource attribute with any string value. | Any Str | true | + +## Internal Telemetry + +The following telemetry is emitted by this component. + +### otelcol_batch_size_trigger_send + +Number of times the batch was sent due to a size trigger [deprecated since v0.110.0] + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| {times} | Sum | Int | true | + +### otelcol_process_runtime_total_alloc_bytes + +Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc') + +| Unit | Metric Type | Value Type | Monotonic | +| ---- | ----------- | ---------- | --------- | +| By | Sum | Int | true | + +### otelcol_queue_capacity + +Queue capacity - sync gauge example. + +| Unit | Metric Type | Value Type | +| ---- | ----------- | ---------- | +| {items} | Gauge | Int | + +### otelcol_queue_length + +This metric is optional and therefore not initialized in NewTelemetryBuilder. [alpha] + +For example this metric only exists if feature A is enabled. + +| Unit | Metric Type | Value Type | +| ---- | ----------- | ---------- | +| {items} | Gauge | Int | + +### otelcol_request_duration + +Duration of request [alpha] + +| Unit | Metric Type | Value Type | +| ---- | ----------- | ---------- | +| s | Histogram | Double | diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/factory.go b/cmd/mdatagen/internal/samplefactoryreceiver/factory.go new file mode 100644 index 000000000000..a3cba05934d2 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/factory.go @@ -0,0 +1,75 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package samplefactoryreceiver // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplefactoryreceiver" + +import ( + "context" + "errors" + + "go.opentelemetry.io/otel/metric" + + "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/service/hostcapabilities" +) + +// NewFactory returns a receiver.Factory for sample receiver. +func NewFactory() receiver.Factory { + return receiver.NewFactory( + metadata.Type, + func() component.Config { return &struct{}{} }, + receiver.WithTraces(createTraces, metadata.TracesStability), + receiver.WithMetrics(createMetrics, metadata.MetricsStability), + receiver.WithLogs(createLogs, metadata.LogsStability)) +} + +func createTraces(context.Context, receiver.Settings, component.Config, consumer.Traces) (receiver.Traces, error) { + return nopInstance, nil +} + +func createMetrics(ctx context.Context, set receiver.Settings, _ component.Config, _ consumer.Metrics) (receiver.Metrics, error) { + telemetryBuilder, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) + if err != nil { + return nil, err + } + err = telemetryBuilder.RegisterProcessRuntimeTotalAllocBytesCallback(func(_ context.Context, observer metric.Int64Observer) error { + observer.Observe(2) + return nil + }) + if err != nil { + return nil, err + } + + telemetryBuilder.BatchSizeTriggerSend.Add(ctx, 1) + return nopReceiver{telemetryBuilder: telemetryBuilder}, nil +} + +func createLogs(context.Context, receiver.Settings, component.Config, consumer.Logs) (receiver.Logs, error) { + return nopInstance, nil +} + +var nopInstance = &nopReceiver{} + +type nopReceiver struct { + component.StartFunc + telemetryBuilder *metadata.TelemetryBuilder +} + +func (r nopReceiver) Start(_ context.Context, host component.Host) error { + if _, ok := host.(hostcapabilities.ComponentFactory); !ok { + return errors.New("host does not implement hostcapabilities.ComponentFactory") + } + + return nil +} + +// Shutdown shuts down the component. +func (r nopReceiver) Shutdown(context.Context) error { + if r.telemetryBuilder != nil { + r.telemetryBuilder.Shutdown() + } + return nil +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/generated_component_test.go b/cmd/mdatagen/internal/samplefactoryreceiver/generated_component_test.go new file mode 100644 index 000000000000..38cf1def51ea --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/generated_component_test.go @@ -0,0 +1,103 @@ +// Code generated by mdatagen. DO NOT EDIT. +//go:build !freebsd && !illumos + +package samplefactoryreceiver + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/consumer/consumertest" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/receiver/receivertest" +) + +var typ = component.MustNewType("sample") + +func TestComponentFactoryType(t *testing.T) { + require.Equal(t, typ, NewFactory().Type()) +} + +func TestComponentConfigStruct(t *testing.T) { + require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) +} + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + tests := []struct { + createFn func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) + name string + }{ + + { + name: "logs", + createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { + return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "metrics", + createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { + return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "traces", + createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { + return factory.CreateTraces(ctx, set, cfg, consumertest.NewNop()) + }, + }, + } + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, sub.Unmarshal(&cfg)) + + for _, tt := range tests { + t.Run(tt.name+"-shutdown", func(t *testing.T) { + c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) + require.NoError(t, err) + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run(tt.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) + require.NoError(t, err) + host := newMdatagenNopHost() + require.NoError(t, err) + require.NoError(t, firstRcvr.Start(context.Background(), host)) + require.NoError(t, firstRcvr.Shutdown(context.Background())) + secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) + require.NoError(t, err) + require.NoError(t, secondRcvr.Start(context.Background(), host)) + require.NoError(t, secondRcvr.Shutdown(context.Background())) + }) + } +} + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/generated_package_test.go b/cmd/mdatagen/internal/samplefactoryreceiver/generated_package_test.go new file mode 100644 index 000000000000..70c4b90fee34 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/generated_package_test.go @@ -0,0 +1,13 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package samplefactoryreceiver + +import ( + "testing" + + "go.uber.org/goleak" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_config.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_config.go new file mode 100644 index 000000000000..4668abbc7322 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_config.go @@ -0,0 +1,196 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "go.opentelemetry.io/collector/confmap" + "go.opentelemetry.io/collector/filter" +) + +// MetricConfig provides common config for a particular metric. +type MetricConfig struct { + Enabled bool `mapstructure:"enabled"` + + enabledSetByUser bool +} + +func (ms *MetricConfig) Unmarshal(parser *confmap.Conf) error { + if parser == nil { + return nil + } + err := parser.Unmarshal(ms) + if err != nil { + return err + } + ms.enabledSetByUser = parser.IsSet("enabled") + return nil +} + +// MetricsConfig provides config for sample metrics. +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"` +} + +func DefaultMetricsConfig() MetricsConfig { + return MetricsConfig{ + DefaultMetric: MetricConfig{ + Enabled: true, + }, + DefaultMetricToBeRemoved: MetricConfig{ + Enabled: true, + }, + MetricInputType: MetricConfig{ + Enabled: true, + }, + OptionalMetric: MetricConfig{ + Enabled: false, + }, + OptionalMetricEmptyUnit: MetricConfig{ + Enabled: false, + }, + } +} + +// EventConfig provides common config for a particular event. +type EventConfig struct { + Enabled bool `mapstructure:"enabled"` + + enabledSetByUser bool +} + +func (ec *EventConfig) Unmarshal(parser *confmap.Conf) error { + if parser == nil { + return nil + } + err := parser.Unmarshal(ec) + if err != nil { + return err + } + ec.enabledSetByUser = parser.IsSet("enabled") + return nil +} + +// EventsConfig provides config for sample events. +type EventsConfig struct { + DefaultEvent EventConfig `mapstructure:"default.event"` + DefaultEventToBeRemoved EventConfig `mapstructure:"default.event.to_be_removed"` + DefaultEventToBeRenamed EventConfig `mapstructure:"default.event.to_be_renamed"` +} + +func DefaultEventsConfig() EventsConfig { + return EventsConfig{ + DefaultEvent: EventConfig{ + Enabled: true, + }, + DefaultEventToBeRemoved: EventConfig{ + Enabled: true, + }, + DefaultEventToBeRenamed: EventConfig{ + Enabled: false, + }, + } +} + +// ResourceAttributeConfig provides common config for a particular resource attribute. +type ResourceAttributeConfig struct { + Enabled bool `mapstructure:"enabled"` + // Experimental: MetricsInclude defines a list of filters for attribute values. + // If the list is not empty, only metrics with matching resource attribute values will be emitted. + MetricsInclude []filter.Config `mapstructure:"metrics_include"` + // Experimental: MetricsExclude defines a list of filters for attribute values. + // If the list is not empty, metrics with matching resource attribute values will not be emitted. + // MetricsInclude has higher priority than MetricsExclude. + MetricsExclude []filter.Config `mapstructure:"metrics_exclude"` + // Experimental: EventsInclude defines a list of filters for attribute values. + // If the list is not empty, only events with matching resource attribute values will be emitted. + EventsInclude []filter.Config `mapstructure:"events_include"` + // Experimental: EventsExclude defines a list of filters for attribute values. + // If the list is not empty, events with matching resource attribute values will not be emitted. + // EventsInclude has higher priority than EventsExclude. + EventsExclude []filter.Config `mapstructure:"events_exclude"` + + enabledSetByUser bool +} + +func (rac *ResourceAttributeConfig) Unmarshal(parser *confmap.Conf) error { + if parser == nil { + return nil + } + err := parser.Unmarshal(rac) + if err != nil { + return err + } + rac.enabledSetByUser = parser.IsSet("enabled") + return nil +} + +// ResourceAttributesConfig provides config for sample resource attributes. +type ResourceAttributesConfig struct { + MapResourceAttr ResourceAttributeConfig `mapstructure:"map.resource.attr"` + OptionalResourceAttr ResourceAttributeConfig `mapstructure:"optional.resource.attr"` + SliceResourceAttr ResourceAttributeConfig `mapstructure:"slice.resource.attr"` + StringEnumResourceAttr ResourceAttributeConfig `mapstructure:"string.enum.resource.attr"` + StringResourceAttr ResourceAttributeConfig `mapstructure:"string.resource.attr"` + StringResourceAttrDisableWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_disable_warning"` + StringResourceAttrRemoveWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_remove_warning"` + StringResourceAttrToBeRemoved ResourceAttributeConfig `mapstructure:"string.resource.attr_to_be_removed"` +} + +func DefaultResourceAttributesConfig() ResourceAttributesConfig { + return ResourceAttributesConfig{ + MapResourceAttr: ResourceAttributeConfig{ + Enabled: true, + }, + OptionalResourceAttr: ResourceAttributeConfig{ + Enabled: false, + }, + SliceResourceAttr: ResourceAttributeConfig{ + Enabled: true, + }, + StringEnumResourceAttr: ResourceAttributeConfig{ + Enabled: true, + }, + StringResourceAttr: ResourceAttributeConfig{ + Enabled: true, + }, + StringResourceAttrDisableWarning: ResourceAttributeConfig{ + Enabled: true, + }, + StringResourceAttrRemoveWarning: ResourceAttributeConfig{ + Enabled: false, + }, + StringResourceAttrToBeRemoved: ResourceAttributeConfig{ + Enabled: true, + }, + } +} + +// MetricsBuilderConfig is a configuration for sample metrics builder. +type MetricsBuilderConfig struct { + Metrics MetricsConfig `mapstructure:"metrics"` + ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` +} + +func DefaultMetricsBuilderConfig() MetricsBuilderConfig { + return MetricsBuilderConfig{ + Metrics: DefaultMetricsConfig(), + ResourceAttributes: DefaultResourceAttributesConfig(), + } +} + +// LogsBuilderConfig is a configuration for sample logs builder. +type LogsBuilderConfig struct { + Events EventsConfig `mapstructure:"events"` + ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` +} + +func DefaultLogsBuilderConfig() LogsBuilderConfig { + return LogsBuilderConfig{ + Events: DefaultEventsConfig(), + ResourceAttributes: DefaultResourceAttributesConfig(), + } +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_config_test.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_config_test.go new file mode 100644 index 000000000000..8f1e1b3d164a --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_config_test.go @@ -0,0 +1,155 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "path/filepath" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/confmap" + "go.opentelemetry.io/collector/confmap/confmaptest" +) + +func TestMetricsBuilderConfig(t *testing.T) { + tests := []struct { + name string + want MetricsBuilderConfig + }{ + { + name: "default", + want: DefaultMetricsBuilderConfig(), + }, + { + name: "all_set", + want: MetricsBuilderConfig{ + Metrics: MetricsConfig{ + DefaultMetric: MetricConfig{Enabled: true}, + DefaultMetricToBeRemoved: MetricConfig{Enabled: true}, + MetricInputType: MetricConfig{Enabled: true}, + OptionalMetric: MetricConfig{Enabled: true}, + OptionalMetricEmptyUnit: MetricConfig{Enabled: true}, + }, + ResourceAttributes: ResourceAttributesConfig{ + MapResourceAttr: ResourceAttributeConfig{Enabled: true}, + OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, + SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, + StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, + StringResourceAttr: ResourceAttributeConfig{Enabled: true}, + StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, + StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, + StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, + }, + }, + }, + { + name: "none_set", + want: MetricsBuilderConfig{ + Metrics: MetricsConfig{ + DefaultMetric: MetricConfig{Enabled: false}, + DefaultMetricToBeRemoved: MetricConfig{Enabled: false}, + MetricInputType: MetricConfig{Enabled: false}, + OptionalMetric: MetricConfig{Enabled: false}, + OptionalMetricEmptyUnit: MetricConfig{Enabled: false}, + }, + ResourceAttributes: ResourceAttributesConfig{ + MapResourceAttr: ResourceAttributeConfig{Enabled: false}, + OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, + SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, + StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, + StringResourceAttr: ResourceAttributeConfig{Enabled: false}, + StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, + StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, + StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := loadMetricsBuilderConfig(t, tt.name) + diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(MetricConfig{}, ResourceAttributeConfig{})) + require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) + }) + } +} + +func loadMetricsBuilderConfig(t *testing.T, name string) MetricsBuilderConfig { + cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) + require.NoError(t, err) + sub, err := cm.Sub(name) + require.NoError(t, err) + cfg := DefaultMetricsBuilderConfig() + require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) + return cfg +} + +func loadLogsBuilderConfig(t *testing.T, name string) LogsBuilderConfig { + cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) + require.NoError(t, err) + sub, err := cm.Sub(name) + require.NoError(t, err) + cfg := DefaultLogsBuilderConfig() + require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) + return cfg +} + +func TestResourceAttributesConfig(t *testing.T) { + tests := []struct { + name string + want ResourceAttributesConfig + }{ + { + name: "default", + want: DefaultResourceAttributesConfig(), + }, + { + name: "all_set", + want: ResourceAttributesConfig{ + MapResourceAttr: ResourceAttributeConfig{Enabled: true}, + OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, + SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, + StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, + StringResourceAttr: ResourceAttributeConfig{Enabled: true}, + StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, + StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, + StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, + }, + }, + { + name: "none_set", + want: ResourceAttributesConfig{ + MapResourceAttr: ResourceAttributeConfig{Enabled: false}, + OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, + SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, + StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, + StringResourceAttr: ResourceAttributeConfig{Enabled: false}, + StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, + StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, + StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := loadResourceAttributesConfig(t, tt.name) + diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(ResourceAttributeConfig{})) + require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) + }) + } +} + +func loadResourceAttributesConfig(t *testing.T, name string) ResourceAttributesConfig { + cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) + require.NoError(t, err) + sub, err := cm.Sub(name) + require.NoError(t, err) + sub, err = sub.Sub("resource_attributes") + require.NoError(t, err) + cfg := DefaultResourceAttributesConfig() + require.NoError(t, sub.Unmarshal(&cfg)) + return cfg +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_logs.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_logs.go new file mode 100644 index 000000000000..7510fb02b729 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_logs.go @@ -0,0 +1,95 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + conventions "go.opentelemetry.io/otel/semconv/v1.9.0" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/receiver" +) + +// LogsBuilder provides an interface for scrapers to report logs while taking care of all the transformations +// required to produce log representation defined in metadata and user config. +type LogsBuilder struct { + logsBuffer plog.Logs + logRecordsBuffer plog.LogRecordSlice + buildInfo component.BuildInfo // contains version information. +} + +// LogBuilderOption applies changes to default logs builder. +type LogBuilderOption interface { + apply(*LogsBuilder) +} + +func NewLogsBuilder(settings receiver.Settings) *LogsBuilder { + lb := &LogsBuilder{ + logsBuffer: plog.NewLogs(), + logRecordsBuffer: plog.NewLogRecordSlice(), + buildInfo: settings.BuildInfo, + } + + return lb +} + +// ResourceLogsOption applies changes to provided resource logs. +type ResourceLogsOption interface { + apply(plog.ResourceLogs) +} + +type resourceLogsOptionFunc func(plog.ResourceLogs) + +func (rlof resourceLogsOptionFunc) apply(rl plog.ResourceLogs) { + rlof(rl) +} + +// WithLogsResource sets the provided resource on the emitted ResourceLogs. +// It's recommended to use ResourceBuilder to create the resource. +func WithLogsResource(res pcommon.Resource) ResourceLogsOption { + return resourceLogsOptionFunc(func(rl plog.ResourceLogs) { + res.CopyTo(rl.Resource()) + }) +} + +// AppendLogRecord adds a log record to the logs builder. +func (lb *LogsBuilder) AppendLogRecord(lr plog.LogRecord) { + lr.MoveTo(lb.logRecordsBuffer.AppendEmpty()) +} + +// EmitForResource saves all the generated logs under a new resource and updates the internal state to be ready for +// recording another set of log records as part of another resource. This function can be helpful when one scraper +// needs to emit logs from several resources. Otherwise calling this function is not required, +// just `Emit` function can be called instead. +// Resource attributes should be provided as ResourceLogsOption arguments. +func (lb *LogsBuilder) EmitForResource(options ...ResourceLogsOption) { + rl := plog.NewResourceLogs() + rl.SetSchemaUrl(conventions.SchemaURL) + ils := rl.ScopeLogs().AppendEmpty() + ils.Scope().SetName(ScopeName) + ils.Scope().SetVersion(lb.buildInfo.Version) + + for _, op := range options { + op.apply(rl) + } + + if lb.logRecordsBuffer.Len() > 0 { + lb.logRecordsBuffer.MoveAndAppendTo(ils.LogRecords()) + lb.logRecordsBuffer = plog.NewLogRecordSlice() + } + + if ils.LogRecords().Len() > 0 { + rl.MoveTo(lb.logsBuffer.ResourceLogs().AppendEmpty()) + } +} + +// Emit returns all the logs accumulated by the logs builder and updates the internal state to be ready for +// recording another set of logs. This function will be responsible for applying all the transformations required to +// produce logs representation defined in metadata and user config. +func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { + lb.EmitForResource(options...) + logs := lb.logsBuffer + lb.logsBuffer = plog.NewLogs() + return logs +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_logs_test.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_logs_test.go new file mode 100644 index 000000000000..1992e9c96bf1 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_logs_test.go @@ -0,0 +1,66 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" + + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/receiver/receivertest" +) + +func TestLogsBuilderAppendLogRecord(t *testing.T) { + observedZapCore, _ := observer.New(zap.WarnLevel) + settings := receivertest.NewNopSettings(receivertest.NopType) + settings.Logger = zap.New(observedZapCore) + lb := NewLogsBuilder(settings) + + res := pcommon.NewResource() + + // append the first log record + lr := plog.NewLogRecord() + lr.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + lr.Attributes().PutStr("type", "log") + lr.Body().SetStr("the first log record") + + // append the second log record + lr2 := plog.NewLogRecord() + lr2.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + lr2.Attributes().PutStr("type", "event") + lr2.Body().SetStr("the second log record") + + lb.AppendLogRecord(lr) + lb.AppendLogRecord(lr2) + + logs := lb.Emit(WithLogsResource(res)) + assert.Equal(t, 1, logs.ResourceLogs().Len()) + + rl := logs.ResourceLogs().At(0) + assert.Equal(t, 1, rl.ScopeLogs().Len()) + + sl := rl.ScopeLogs().At(0) + assert.Equal(t, ScopeName, sl.Scope().Name()) + assert.Equal(t, lb.buildInfo.Version, sl.Scope().Version()) + + assert.Equal(t, 2, sl.LogRecords().Len()) + + attrVal, ok := sl.LogRecords().At(0).Attributes().Get("type") + assert.True(t, ok) + assert.Equal(t, "log", attrVal.Str()) + + assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(0).Body().Type()) + assert.Equal(t, "the first log record", sl.LogRecords().At(0).Body().Str()) + + attrVal, ok = sl.LogRecords().At(1).Attributes().Get("type") + assert.True(t, ok) + assert.Equal(t, "event", attrVal.Str()) + + assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(1).Body().Type()) + assert.Equal(t, "the second log record", sl.LogRecords().At(1).Body().Str()) +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_metrics.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_metrics.go new file mode 100644 index 000000000000..6f7473f89c82 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_metrics.go @@ -0,0 +1,637 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "fmt" + "strconv" + "time" + + conventions "go.opentelemetry.io/otel/semconv/v1.9.0" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/filter" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/receiver" +) + +// AttributeEnumAttr specifies the value enum_attr attribute. +type AttributeEnumAttr int + +const ( + _ AttributeEnumAttr = iota + AttributeEnumAttrRed + AttributeEnumAttrGreen + AttributeEnumAttrBlue +) + +// String returns the string representation of the AttributeEnumAttr. +func (av AttributeEnumAttr) String() string { + switch av { + case AttributeEnumAttrRed: + return "red" + case AttributeEnumAttrGreen: + return "green" + case AttributeEnumAttrBlue: + return "blue" + } + return "" +} + +// MapAttributeEnumAttr is a helper map of string to AttributeEnumAttr attribute value. +var MapAttributeEnumAttr = map[string]AttributeEnumAttr{ + "red": AttributeEnumAttrRed, + "green": AttributeEnumAttrGreen, + "blue": AttributeEnumAttrBlue, +} + +var MetricsInfo = metricsInfo{ + DefaultMetric: metricInfo{ + Name: "default.metric", + }, + DefaultMetricToBeRemoved: metricInfo{ + Name: "default.metric.to_be_removed", + }, + MetricInputType: metricInfo{ + Name: "metric.input_type", + }, + OptionalMetric: metricInfo{ + Name: "optional.metric", + }, + OptionalMetricEmptyUnit: metricInfo{ + Name: "optional.metric.empty_unit", + }, +} + +type metricsInfo struct { + DefaultMetric metricInfo + DefaultMetricToBeRemoved metricInfo + MetricInputType metricInfo + OptionalMetric metricInfo + OptionalMetricEmptyUnit metricInfo +} + +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. + capacity int // max observed number of data points added to the metric. +} + +// init fills default.metric metric with initial data. +func (m *metricDefaultMetric) init() { + m.data.SetName("default.metric") + m.data.SetDescription("Monotonic cumulative sum int metric 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 *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 + } + 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) + for _, op := range options { + op.apply(dp) + } +} + +// updateCapacity saves max length of data point slices that will be used for the slice capacity. +func (m *metricDefaultMetric) 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 *metricDefaultMetric) emit(metrics pmetric.MetricSlice) { + if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricDefaultMetric(cfg MetricConfig) metricDefaultMetric { + m := metricDefaultMetric{config: cfg} + if cfg.Enabled { + m.data = pmetric.NewMetric() + m.init() + } + return m +} + +type metricDefaultMetricToBeRemoved 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 default.metric.to_be_removed metric with initial data. +func (m *metricDefaultMetricToBeRemoved) init() { + m.data.SetName("default.metric.to_be_removed") + m.data.SetDescription("[DEPRECATED] Non-monotonic delta sum double metric enabled by default.") + m.data.SetUnit("s") + m.data.SetEmptySum() + m.data.Sum().SetIsMonotonic(false) + m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityDelta) +} + +func (m *metricDefaultMetricToBeRemoved) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64) { + if !m.config.Enabled { + return + } + dp := m.data.Sum().DataPoints().AppendEmpty() + dp.SetStartTimestamp(start) + dp.SetTimestamp(ts) + dp.SetDoubleValue(val) +} + +// updateCapacity saves max length of data point slices that will be used for the slice capacity. +func (m *metricDefaultMetricToBeRemoved) 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 *metricDefaultMetricToBeRemoved) emit(metrics pmetric.MetricSlice) { + if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricDefaultMetricToBeRemoved(cfg MetricConfig) metricDefaultMetricToBeRemoved { + m := metricDefaultMetricToBeRemoved{config: cfg} + if cfg.Enabled { + m.data = pmetric.NewMetric() + m.init() + } + 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. + capacity int // max observed number of data points added to the metric. +} + +// init fills optional.metric metric with initial data. +func (m *metricOptionalMetric) init() { + m.data.SetName("optional.metric") + m.data.SetDescription("[DEPRECATED] Gauge double metric disabled by default.") + m.data.SetUnit("1") + m.data.SetEmptyGauge() + 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, options ...MetricAttributeOption) { + if !m.config.Enabled { + return + } + dp := m.data.Gauge().DataPoints().AppendEmpty() + dp.SetStartTimestamp(start) + dp.SetTimestamp(ts) + dp.SetDoubleValue(val) + 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. +func (m *metricOptionalMetric) updateCapacity() { + if m.data.Gauge().DataPoints().Len() > m.capacity { + m.capacity = m.data.Gauge().DataPoints().Len() + } +} + +// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. +func (m *metricOptionalMetric) emit(metrics pmetric.MetricSlice) { + if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricOptionalMetric(cfg MetricConfig) metricOptionalMetric { + m := metricOptionalMetric{config: cfg} + if cfg.Enabled { + m.data = pmetric.NewMetric() + m.init() + } + return m +} + +type metricOptionalMetricEmptyUnit 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 optional.metric.empty_unit metric with initial data. +func (m *metricOptionalMetricEmptyUnit) init() { + m.data.SetName("optional.metric.empty_unit") + m.data.SetDescription("[DEPRECATED] Gauge double metric disabled by default.") + m.data.SetUnit("") + m.data.SetEmptyGauge() + m.data.Gauge().DataPoints().EnsureCapacity(m.capacity) +} + +func (m *metricOptionalMetricEmptyUnit) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { + if !m.config.Enabled { + return + } + dp := m.data.Gauge().DataPoints().AppendEmpty() + dp.SetStartTimestamp(start) + dp.SetTimestamp(ts) + dp.SetDoubleValue(val) + dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) + dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) +} + +// updateCapacity saves max length of data point slices that will be used for the slice capacity. +func (m *metricOptionalMetricEmptyUnit) updateCapacity() { + if m.data.Gauge().DataPoints().Len() > m.capacity { + m.capacity = m.data.Gauge().DataPoints().Len() + } +} + +// emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. +func (m *metricOptionalMetricEmptyUnit) emit(metrics pmetric.MetricSlice) { + if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { + m.updateCapacity() + m.data.MoveTo(metrics.AppendEmpty()) + m.init() + } +} + +func newMetricOptionalMetricEmptyUnit(cfg MetricConfig) metricOptionalMetricEmptyUnit { + m := metricOptionalMetricEmptyUnit{config: cfg} + if cfg.Enabled { + m.data = pmetric.NewMetric() + m.init() + } + return m +} + +// MetricsBuilder provides an interface for scrapers to report metrics while taking care of all the transformations +// required to produce metric representation defined in metadata and user config. +type MetricsBuilder struct { + config MetricsBuilderConfig // config of the metrics builder. + startTime pcommon.Timestamp // start time that will be applied to all recorded data points. + metricsCapacity int // maximum observed number of metrics per resource. + metricsBuffer pmetric.Metrics // accumulates metrics data before emitting. + buildInfo component.BuildInfo // contains version information. + resourceAttributeIncludeFilter map[string]filter.Filter + resourceAttributeExcludeFilter map[string]filter.Filter + metricDefaultMetric metricDefaultMetric + metricDefaultMetricToBeRemoved metricDefaultMetricToBeRemoved + metricMetricInputType metricMetricInputType + metricOptionalMetric metricOptionalMetric + metricOptionalMetricEmptyUnit metricOptionalMetricEmptyUnit +} + +// MetricBuilderOption applies changes to default metrics builder. +type MetricBuilderOption interface { + apply(*MetricsBuilder) +} + +type metricBuilderOptionFunc func(mb *MetricsBuilder) + +func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { + mbof(mb) +} + +// WithStartTime sets startTime on the metrics builder. +func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { + return metricBuilderOptionFunc(func(mb *MetricsBuilder) { + mb.startTime = startTime + }) +} +func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { + if !mbc.Metrics.DefaultMetric.enabledSetByUser { + settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `default.metric`: This metric will be disabled by default soon.") + } + if mbc.Metrics.DefaultMetricToBeRemoved.Enabled { + settings.Logger.Warn("[WARNING] `default.metric.to_be_removed` should not be enabled: This metric is deprecated and will be removed soon.") + } + if mbc.Metrics.OptionalMetric.enabledSetByUser { + settings.Logger.Warn("[WARNING] `optional.metric` should not be configured: This metric is deprecated and will be removed soon.") + } + if mbc.Metrics.OptionalMetricEmptyUnit.enabledSetByUser { + settings.Logger.Warn("[WARNING] `optional.metric.empty_unit` should not be configured: This metric is deprecated and will be removed soon.") + } + if !mbc.ResourceAttributes.StringResourceAttrDisableWarning.enabledSetByUser { + settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.") + } + if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.enabledSetByUser || mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude != nil || mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude != nil { + settings.Logger.Warn("[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.") + } + if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.Enabled { + settings.Logger.Warn("[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.") + } + mb := &MetricsBuilder{ + config: mbc, + startTime: pcommon.NewTimestampFromTime(time.Now()), + metricsBuffer: pmetric.NewMetrics(), + 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), + resourceAttributeIncludeFilter: make(map[string]filter.Filter), + resourceAttributeExcludeFilter: make(map[string]filter.Filter), + } + if mbc.ResourceAttributes.MapResourceAttr.MetricsInclude != nil { + mb.resourceAttributeIncludeFilter["map.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.MapResourceAttr.MetricsInclude) + } + if mbc.ResourceAttributes.MapResourceAttr.MetricsExclude != nil { + mb.resourceAttributeExcludeFilter["map.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.MapResourceAttr.MetricsExclude) + } + if mbc.ResourceAttributes.OptionalResourceAttr.MetricsInclude != nil { + mb.resourceAttributeIncludeFilter["optional.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.OptionalResourceAttr.MetricsInclude) + } + if mbc.ResourceAttributes.OptionalResourceAttr.MetricsExclude != nil { + mb.resourceAttributeExcludeFilter["optional.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.OptionalResourceAttr.MetricsExclude) + } + if mbc.ResourceAttributes.SliceResourceAttr.MetricsInclude != nil { + mb.resourceAttributeIncludeFilter["slice.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.SliceResourceAttr.MetricsInclude) + } + if mbc.ResourceAttributes.SliceResourceAttr.MetricsExclude != nil { + mb.resourceAttributeExcludeFilter["slice.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.SliceResourceAttr.MetricsExclude) + } + if mbc.ResourceAttributes.StringEnumResourceAttr.MetricsInclude != nil { + mb.resourceAttributeIncludeFilter["string.enum.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringEnumResourceAttr.MetricsInclude) + } + if mbc.ResourceAttributes.StringEnumResourceAttr.MetricsExclude != nil { + mb.resourceAttributeExcludeFilter["string.enum.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringEnumResourceAttr.MetricsExclude) + } + if mbc.ResourceAttributes.StringResourceAttr.MetricsInclude != nil { + mb.resourceAttributeIncludeFilter["string.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttr.MetricsInclude) + } + if mbc.ResourceAttributes.StringResourceAttr.MetricsExclude != nil { + mb.resourceAttributeExcludeFilter["string.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttr.MetricsExclude) + } + if mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsInclude != nil { + mb.resourceAttributeIncludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsInclude) + } + if mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsExclude != nil { + mb.resourceAttributeExcludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsExclude) + } + if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude != nil { + mb.resourceAttributeIncludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude) + } + if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude != nil { + mb.resourceAttributeExcludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude) + } + if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsInclude != nil { + mb.resourceAttributeIncludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsInclude) + } + if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsExclude != nil { + mb.resourceAttributeExcludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsExclude) + } + + for _, op := range options { + op.apply(mb) + } + return mb +} + +// NewResourceBuilder returns a new resource builder that should be used to build a resource associated with for the emitted metrics. +func (mb *MetricsBuilder) NewResourceBuilder() *ResourceBuilder { + return NewResourceBuilder(mb.config.ResourceAttributes) +} + +// updateCapacity updates max length of metrics and resource attributes that will be used for the slice capacity. +func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { + if mb.metricsCapacity < rm.ScopeMetrics().At(0).Metrics().Len() { + mb.metricsCapacity = rm.ScopeMetrics().At(0).Metrics().Len() + } +} + +// ResourceMetricsOption applies changes to provided resource metrics. +type ResourceMetricsOption interface { + apply(pmetric.ResourceMetrics) +} + +type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) + +func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { + rmof(rm) +} + +// WithResource sets the provided resource on the emitted ResourceMetrics. +// It's recommended to use ResourceBuilder to create the resource. +func WithResource(res pcommon.Resource) ResourceMetricsOption { + return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { + res.CopyTo(rm.Resource()) + }) +} + +// WithStartTimeOverride overrides start time for all the resource metrics data points. +// This option should be only used if different start time has to be set on metrics coming from different resources. +func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { + return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { + var dps pmetric.NumberDataPointSlice + metrics := rm.ScopeMetrics().At(0).Metrics() + for i := 0; i < metrics.Len(); i++ { + switch metrics.At(i).Type() { + case pmetric.MetricTypeGauge: + dps = metrics.At(i).Gauge().DataPoints() + case pmetric.MetricTypeSum: + dps = metrics.At(i).Sum().DataPoints() + } + for j := 0; j < dps.Len(); j++ { + dps.At(j).SetStartTimestamp(start) + } + } + }) +} + +// EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for +// recording another set of data points as part of another resource. This function can be helpful when one scraper +// needs to emit metrics from several resources. Otherwise calling this function is not required, +// just `Emit` function can be called instead. +// Resource attributes should be provided as ResourceMetricsOption arguments. +func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { + rm := pmetric.NewResourceMetrics() + rm.SetSchemaUrl(conventions.SchemaURL) + ils := rm.ScopeMetrics().AppendEmpty() + ils.Scope().SetName(ScopeName) + ils.Scope().SetVersion(mb.buildInfo.Version) + 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()) + + for _, op := range options { + op.apply(rm) + } + for attr, filter := range mb.resourceAttributeIncludeFilter { + if val, ok := rm.Resource().Attributes().Get(attr); ok && !filter.Matches(val.AsString()) { + return + } + } + for attr, filter := range mb.resourceAttributeExcludeFilter { + if val, ok := rm.Resource().Attributes().Get(attr); ok && filter.Matches(val.AsString()) { + return + } + } + + if ils.Metrics().Len() > 0 { + mb.updateCapacity(rm) + rm.MoveTo(mb.metricsBuffer.ResourceMetrics().AppendEmpty()) + } +} + +// Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for +// recording another set of metrics. This function will be responsible for applying all the transformations required to +// produce metric representation defined in metadata and user config, e.g. delta or cumulative. +func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { + mb.EmitForResource(options...) + metrics := mb.metricsBuffer + mb.metricsBuffer = pmetric.NewMetrics() + return 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, 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. +func (mb *MetricsBuilder) RecordDefaultMetricToBeRemovedDataPoint(ts pcommon.Timestamp, val float64) { + 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, 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. +func (mb *MetricsBuilder) RecordOptionalMetricEmptyUnitDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { + mb.metricOptionalMetricEmptyUnit.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue) +} + +// Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, +// and metrics builder should update its startTime and reset it's internal state accordingly. +func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { + mb.startTime = pcommon.NewTimestampFromTime(time.Now()) + for _, op := range options { + op.apply(mb) + } +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_metrics_test.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_metrics_test.go new file mode 100644 index 000000000000..e11ac2a2e846 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_metrics_test.go @@ -0,0 +1,273 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" + + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/receiver/receivertest" +) + +type testDataSet int + +const ( + testDataSetDefault testDataSet = iota + testDataSetAll + testDataSetNone +) + +func TestMetricsBuilder(t *testing.T) { + tests := []struct { + name string + metricsSet testDataSet + resAttrsSet testDataSet + expectEmpty bool + }{ + { + name: "default", + }, + { + name: "all_set", + metricsSet: testDataSetAll, + resAttrsSet: testDataSetAll, + }, + { + name: "none_set", + metricsSet: testDataSetNone, + resAttrsSet: testDataSetNone, + expectEmpty: true, + }, + { + name: "filter_set_include", + resAttrsSet: testDataSetAll, + }, + { + name: "filter_set_exclude", + resAttrsSet: testDataSetAll, + expectEmpty: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + start := pcommon.Timestamp(1_000_000_000) + ts := pcommon.Timestamp(1_000_001_000) + observedZapCore, observedLogs := observer.New(zap.WarnLevel) + settings := receivertest.NewNopSettings(receivertest.NopType) + settings.Logger = zap.New(observedZapCore) + mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) + + expectedWarnings := 0 + if tt.metricsSet == testDataSetDefault { + assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `default.metric`: This metric will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) + expectedWarnings++ + } + if tt.metricsSet == testDataSetDefault || tt.metricsSet == testDataSetAll { + assert.Equal(t, "[WARNING] `default.metric.to_be_removed` should not be enabled: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) + expectedWarnings++ + } + if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { + assert.Equal(t, "[WARNING] `optional.metric` should not be configured: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) + expectedWarnings++ + } + if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { + assert.Equal(t, "[WARNING] `optional.metric.empty_unit` should not be configured: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) + expectedWarnings++ + } + if tt.resAttrsSet == testDataSetDefault { + assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) + expectedWarnings++ + } + if tt.resAttrsSet == testDataSetAll || tt.resAttrsSet == testDataSetNone { + assert.Equal(t, "[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) + expectedWarnings++ + } + if tt.resAttrsSet == testDataSetDefault || tt.resAttrsSet == testDataSetAll { + assert.Equal(t, "[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) + expectedWarnings++ + } + + assert.Equal(t, expectedWarnings, observedLogs.Len()) + + defaultMetricsCount := 0 + allMetricsCount := 0 + + 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"}, WithOptionalIntAttrMetricAttribute(17), WithOptionalStringAttrMetricAttribute("optional_string_attr-val")) + + defaultMetricsCount++ + 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, false, WithOptionalStringAttrMetricAttribute("optional_string_attr-val")) + + allMetricsCount++ + mb.RecordOptionalMetricEmptyUnitDataPoint(ts, 1, "string_attr-val", true) + + rb := mb.NewResourceBuilder() + rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) + rb.SetOptionalResourceAttr("optional.resource.attr-val") + rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) + rb.SetStringEnumResourceAttrOne() + rb.SetStringResourceAttr("string.resource.attr-val") + rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") + rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") + rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") + res := rb.Emit() + metrics := mb.Emit(WithResource(res)) + + if tt.expectEmpty { + assert.Equal(t, 0, metrics.ResourceMetrics().Len()) + return + } + + assert.Equal(t, 1, metrics.ResourceMetrics().Len()) + rm := metrics.ResourceMetrics().At(0) + assert.Equal(t, res, rm.Resource()) + assert.Equal(t, 1, rm.ScopeMetrics().Len()) + ms := rm.ScopeMetrics().At(0).Metrics() + if tt.metricsSet == testDataSetDefault { + assert.Equal(t, defaultMetricsCount, ms.Len()) + } + if tt.metricsSet == testDataSetAll { + assert.Equal(t, allMetricsCount, ms.Len()) + } + validatedMetrics := make(map[string]bool) + for i := 0; i < ms.Len(); i++ { + switch ms.At(i).Name() { + case "default.metric": + assert.False(t, validatedMetrics["default.metric"], "Found a duplicate in the metrics slice: default.metric") + validatedMetrics["default.metric"] = 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 enabled by default.", ms.At(i).Description()) + assert.Equal(t, "s", ms.At(i).Unit()) + assert.True(t, 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.Equal(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.Equal(t, "red", attrVal.Str()) + attrVal, ok = dp.Attributes().Get("slice_attr") + assert.True(t, ok) + assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) + 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 + assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) + assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) + assert.Equal(t, "[DEPRECATED] Non-monotonic delta sum double metric enabled by default.", ms.At(i).Description()) + assert.Equal(t, "s", ms.At(i).Unit()) + assert.False(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, pmetric.AggregationTemporalityDelta, 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.NumberDataPointValueTypeDouble, dp.ValueType()) + assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) + 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.True(t, 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.Equal(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.Equal(t, "red", attrVal.Str()) + attrVal, ok = dp.Attributes().Get("slice_attr") + assert.True(t, ok) + assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) + 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()) + case "optional.metric": + assert.False(t, validatedMetrics["optional.metric"], "Found a duplicate in the metrics slice: optional.metric") + validatedMetrics["optional.metric"] = true + assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) + assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) + assert.Equal(t, "[DEPRECATED] Gauge double metric disabled by default.", ms.At(i).Description()) + assert.Equal(t, "1", ms.At(i).Unit()) + dp := ms.At(i).Gauge().DataPoints().At(0) + assert.Equal(t, start, dp.StartTimestamp()) + assert.Equal(t, ts, dp.Timestamp()) + assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) + assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) + attrVal, ok := dp.Attributes().Get("string_attr") + assert.True(t, ok) + assert.Equal(t, "string_attr-val", attrVal.Str()) + attrVal, ok = dp.Attributes().Get("boolean_attr") + assert.True(t, ok) + assert.True(t, attrVal.Bool()) + 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 + assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) + assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) + assert.Equal(t, "[DEPRECATED] Gauge double metric disabled by default.", ms.At(i).Description()) + assert.Empty(t, ms.At(i).Unit()) + dp := ms.At(i).Gauge().DataPoints().At(0) + assert.Equal(t, start, dp.StartTimestamp()) + assert.Equal(t, ts, dp.Timestamp()) + assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) + assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) + attrVal, ok := dp.Attributes().Get("string_attr") + assert.True(t, ok) + assert.Equal(t, "string_attr-val", attrVal.Str()) + attrVal, ok = dp.Attributes().Get("boolean_attr") + assert.True(t, ok) + assert.True(t, attrVal.Bool()) + } + } + }) + } +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_resource.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_resource.go new file mode 100644 index 000000000000..da69b3c08411 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_resource.go @@ -0,0 +1,92 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "go.opentelemetry.io/collector/pdata/pcommon" +) + +// ResourceBuilder is a helper struct to build resources predefined in metadata.yaml. +// The ResourceBuilder is not thread-safe and must not to be used in multiple goroutines. +type ResourceBuilder struct { + config ResourceAttributesConfig + res pcommon.Resource +} + +// NewResourceBuilder creates a new ResourceBuilder. This method should be called on the start of the application. +func NewResourceBuilder(rac ResourceAttributesConfig) *ResourceBuilder { + return &ResourceBuilder{ + config: rac, + res: pcommon.NewResource(), + } +} + +// SetMapResourceAttr sets provided value as "map.resource.attr" attribute. +func (rb *ResourceBuilder) SetMapResourceAttr(val map[string]any) { + if rb.config.MapResourceAttr.Enabled { + rb.res.Attributes().PutEmptyMap("map.resource.attr").FromRaw(val) + } +} + +// SetOptionalResourceAttr sets provided value as "optional.resource.attr" attribute. +func (rb *ResourceBuilder) SetOptionalResourceAttr(val string) { + if rb.config.OptionalResourceAttr.Enabled { + rb.res.Attributes().PutStr("optional.resource.attr", val) + } +} + +// SetSliceResourceAttr sets provided value as "slice.resource.attr" attribute. +func (rb *ResourceBuilder) SetSliceResourceAttr(val []any) { + if rb.config.SliceResourceAttr.Enabled { + rb.res.Attributes().PutEmptySlice("slice.resource.attr").FromRaw(val) + } +} + +// SetStringEnumResourceAttrOne sets "string.enum.resource.attr=one" attribute. +func (rb *ResourceBuilder) SetStringEnumResourceAttrOne() { + if rb.config.StringEnumResourceAttr.Enabled { + rb.res.Attributes().PutStr("string.enum.resource.attr", "one") + } +} + +// SetStringEnumResourceAttrTwo sets "string.enum.resource.attr=two" attribute. +func (rb *ResourceBuilder) SetStringEnumResourceAttrTwo() { + if rb.config.StringEnumResourceAttr.Enabled { + rb.res.Attributes().PutStr("string.enum.resource.attr", "two") + } +} + +// SetStringResourceAttr sets provided value as "string.resource.attr" attribute. +func (rb *ResourceBuilder) SetStringResourceAttr(val string) { + if rb.config.StringResourceAttr.Enabled { + rb.res.Attributes().PutStr("string.resource.attr", val) + } +} + +// SetStringResourceAttrDisableWarning sets provided value as "string.resource.attr_disable_warning" attribute. +func (rb *ResourceBuilder) SetStringResourceAttrDisableWarning(val string) { + if rb.config.StringResourceAttrDisableWarning.Enabled { + rb.res.Attributes().PutStr("string.resource.attr_disable_warning", val) + } +} + +// SetStringResourceAttrRemoveWarning sets provided value as "string.resource.attr_remove_warning" attribute. +func (rb *ResourceBuilder) SetStringResourceAttrRemoveWarning(val string) { + if rb.config.StringResourceAttrRemoveWarning.Enabled { + rb.res.Attributes().PutStr("string.resource.attr_remove_warning", val) + } +} + +// SetStringResourceAttrToBeRemoved sets provided value as "string.resource.attr_to_be_removed" attribute. +func (rb *ResourceBuilder) SetStringResourceAttrToBeRemoved(val string) { + if rb.config.StringResourceAttrToBeRemoved.Enabled { + rb.res.Attributes().PutStr("string.resource.attr_to_be_removed", val) + } +} + +// Emit returns the built resource and resets the internal builder state. +func (rb *ResourceBuilder) Emit() pcommon.Resource { + r := rb.res + rb.res = pcommon.NewResource() + return r +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_resource_test.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_resource_test.go new file mode 100644 index 000000000000..5c03ab595fd7 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_resource_test.go @@ -0,0 +1,82 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestResourceBuilder(t *testing.T) { + for _, tt := range []string{"default", "all_set", "none_set"} { + t.Run(tt, func(t *testing.T) { + cfg := loadResourceAttributesConfig(t, tt) + rb := NewResourceBuilder(cfg) + rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) + rb.SetOptionalResourceAttr("optional.resource.attr-val") + rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) + rb.SetStringEnumResourceAttrOne() + rb.SetStringResourceAttr("string.resource.attr-val") + rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") + rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") + rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") + + res := rb.Emit() + assert.Equal(t, 0, rb.Emit().Attributes().Len()) // Second call should return empty Resource + + switch tt { + case "default": + assert.Equal(t, 6, res.Attributes().Len()) + case "all_set": + assert.Equal(t, 8, res.Attributes().Len()) + case "none_set": + assert.Equal(t, 0, res.Attributes().Len()) + return + default: + assert.Failf(t, "unexpected test case: %s", tt) + } + + val, ok := res.Attributes().Get("map.resource.attr") + assert.True(t, ok) + if ok { + assert.Equal(t, map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}, val.Map().AsRaw()) + } + val, ok = res.Attributes().Get("optional.resource.attr") + assert.Equal(t, tt == "all_set", ok) + if ok { + assert.Equal(t, "optional.resource.attr-val", val.Str()) + } + val, ok = res.Attributes().Get("slice.resource.attr") + assert.True(t, ok) + if ok { + assert.Equal(t, []any{"slice.resource.attr-item1", "slice.resource.attr-item2"}, val.Slice().AsRaw()) + } + val, ok = res.Attributes().Get("string.enum.resource.attr") + assert.True(t, ok) + if ok { + assert.Equal(t, "one", val.Str()) + } + val, ok = res.Attributes().Get("string.resource.attr") + assert.True(t, ok) + if ok { + assert.Equal(t, "string.resource.attr-val", val.Str()) + } + val, ok = res.Attributes().Get("string.resource.attr_disable_warning") + assert.True(t, ok) + if ok { + assert.Equal(t, "string.resource.attr_disable_warning-val", val.Str()) + } + val, ok = res.Attributes().Get("string.resource.attr_remove_warning") + assert.Equal(t, tt == "all_set", ok) + if ok { + assert.Equal(t, "string.resource.attr_remove_warning-val", val.Str()) + } + val, ok = res.Attributes().Get("string.resource.attr_to_be_removed") + assert.True(t, ok) + if ok { + assert.Equal(t, "string.resource.attr_to_be_removed-val", val.Str()) + } + }) + } +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_status.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_status.go new file mode 100644 index 000000000000..d1fd7dabe614 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_status.go @@ -0,0 +1,19 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "go.opentelemetry.io/collector/component" +) + +var ( + Type = component.MustNewType("sample") + ScopeName = "go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver" +) + +const ( + ProfilesStability = component.StabilityLevelDeprecated + LogsStability = component.StabilityLevelDevelopment + TracesStability = component.StabilityLevelBeta + MetricsStability = component.StabilityLevelStable +) diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_telemetry.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_telemetry.go new file mode 100644 index 000000000000..474c3b3cad98 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_telemetry.go @@ -0,0 +1,139 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "context" + "errors" + "sync" + + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/metric/embedded" + "go.opentelemetry.io/otel/trace" + + "go.opentelemetry.io/collector/component" +) + +func Meter(settings component.TelemetrySettings) metric.Meter { + return settings.MeterProvider.Meter("go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver") +} + +func Tracer(settings component.TelemetrySettings) trace.Tracer { + return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver") +} + +// TelemetryBuilder provides an interface for components to report telemetry +// as defined in metadata and user config. +type TelemetryBuilder struct { + meter metric.Meter + mu sync.Mutex + registrations []metric.Registration + BatchSizeTriggerSend metric.Int64Counter + ProcessRuntimeTotalAllocBytes metric.Int64ObservableCounter + QueueCapacity metric.Int64Gauge + QueueLength metric.Int64ObservableGauge + RequestDuration metric.Float64Histogram +} + +// TelemetryBuilderOption applies changes to default builder. +type TelemetryBuilderOption interface { + apply(*TelemetryBuilder) +} + +type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) + +func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { + tbof(mb) +} + +// RegisterProcessRuntimeTotalAllocBytesCallback sets callback for observable ProcessRuntimeTotalAllocBytes metric. +func (builder *TelemetryBuilder) RegisterProcessRuntimeTotalAllocBytesCallback(cb metric.Int64Callback) error { + reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { + cb(ctx, &observerInt64{inst: builder.ProcessRuntimeTotalAllocBytes, obs: o}) + return nil + }, builder.ProcessRuntimeTotalAllocBytes) + if err != nil { + return err + } + builder.mu.Lock() + defer builder.mu.Unlock() + builder.registrations = append(builder.registrations, reg) + return nil +} + +// RegisterQueueLengthCallback sets callback for observable QueueLength metric. +func (builder *TelemetryBuilder) RegisterQueueLengthCallback(cb metric.Int64Callback) error { + reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { + cb(ctx, &observerInt64{inst: builder.QueueLength, obs: o}) + return nil + }, builder.QueueLength) + if err != nil { + return err + } + builder.mu.Lock() + defer builder.mu.Unlock() + builder.registrations = append(builder.registrations, reg) + return nil +} + +type observerInt64 struct { + embedded.Int64Observer + inst metric.Int64Observable + obs metric.Observer +} + +func (oi *observerInt64) Observe(value int64, opts ...metric.ObserveOption) { + oi.obs.ObserveInt64(oi.inst, value, opts...) +} + +// Shutdown unregister all registered callbacks for async instruments. +func (builder *TelemetryBuilder) Shutdown() { + builder.mu.Lock() + defer builder.mu.Unlock() + for _, reg := range builder.registrations { + reg.Unregister() + } +} + +// NewTelemetryBuilder provides a struct with methods to update all internal telemetry +// for a component +func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { + builder := TelemetryBuilder{} + for _, op := range options { + op.apply(&builder) + } + builder.meter = Meter(settings) + var err, errs error + builder.BatchSizeTriggerSend, err = builder.meter.Int64Counter( + "otelcol_batch_size_trigger_send", + metric.WithDescription("Number of times the batch was sent due to a size trigger [deprecated since v0.110.0]"), + metric.WithUnit("{times}"), + ) + errs = errors.Join(errs, err) + builder.ProcessRuntimeTotalAllocBytes, err = builder.meter.Int64ObservableCounter( + "otelcol_process_runtime_total_alloc_bytes", + metric.WithDescription("Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc')"), + metric.WithUnit("By"), + ) + errs = errors.Join(errs, err) + builder.QueueCapacity, err = builder.meter.Int64Gauge( + "otelcol_queue_capacity", + metric.WithDescription("Queue capacity - sync gauge example."), + metric.WithUnit("{items}"), + ) + errs = errors.Join(errs, err) + builder.QueueLength, err = builder.meter.Int64ObservableGauge( + "otelcol_queue_length", + metric.WithDescription("This metric is optional and therefore not initialized in NewTelemetryBuilder. [alpha]"), + metric.WithUnit("{items}"), + ) + errs = errors.Join(errs, err) + builder.RequestDuration, err = builder.meter.Float64Histogram( + "otelcol_request_duration", + metric.WithDescription("Duration of request [alpha]"), + metric.WithUnit("s"), + metric.WithExplicitBucketBoundaries([]float64{1, 10, 100}...), + ) + errs = errors.Join(errs, err) + return &builder, errs +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_telemetry_test.go b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_telemetry_test.go new file mode 100644 index 000000000000..1d8320c33cc9 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/generated_telemetry_test.go @@ -0,0 +1,74 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "testing" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel/metric" + embeddedmetric "go.opentelemetry.io/otel/metric/embedded" + noopmetric "go.opentelemetry.io/otel/metric/noop" + "go.opentelemetry.io/otel/trace" + embeddedtrace "go.opentelemetry.io/otel/trace/embedded" + nooptrace "go.opentelemetry.io/otel/trace/noop" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" +) + +type mockMeter struct { + noopmetric.Meter + name string +} +type mockMeterProvider struct { + embeddedmetric.MeterProvider +} + +func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { + return mockMeter{name: name} +} + +type mockTracer struct { + nooptrace.Tracer + name string +} + +type mockTracerProvider struct { + embeddedtrace.TracerProvider +} + +func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { + return mockTracer{name: name} +} + +func TestProviders(t *testing.T) { + set := component.TelemetrySettings{ + MeterProvider: mockMeterProvider{}, + TracerProvider: mockTracerProvider{}, + } + + meter := Meter(set) + if m, ok := meter.(mockMeter); ok { + require.Equal(t, "go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver", m.name) + } else { + require.Fail(t, "returned Meter not mockMeter") + } + + tracer := Tracer(set) + if m, ok := tracer.(mockTracer); ok { + require.Equal(t, "go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver", m.name) + } else { + require.Fail(t, "returned Meter not mockTracer") + } +} + +func TestNewTelemetryBuilder(t *testing.T) { + set := componenttest.NewNopTelemetrySettings() + applied := false + _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { + applied = true + })) + require.NoError(t, err) + require.True(t, applied) +} diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/testdata/config.yaml b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/testdata/config.yaml new file mode 100644 index 000000000000..b8e4438bb0d6 --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/testdata/config.yaml @@ -0,0 +1,173 @@ +default: +all_set: + metrics: + default.metric: + enabled: true + default.metric.to_be_removed: + enabled: true + metric.input_type: + enabled: true + optional.metric: + enabled: true + optional.metric.empty_unit: + enabled: true + events: + default.event: + enabled: true + default.event.to_be_removed: + enabled: true + default.event.to_be_renamed: + enabled: true + resource_attributes: + map.resource.attr: + enabled: true + optional.resource.attr: + enabled: true + slice.resource.attr: + enabled: true + string.enum.resource.attr: + enabled: true + string.resource.attr: + enabled: true + string.resource.attr_disable_warning: + enabled: true + string.resource.attr_remove_warning: + enabled: true + string.resource.attr_to_be_removed: + enabled: true +none_set: + metrics: + default.metric: + enabled: false + default.metric.to_be_removed: + enabled: false + metric.input_type: + enabled: false + optional.metric: + enabled: false + optional.metric.empty_unit: + enabled: false + events: + default.event: + enabled: false + default.event.to_be_removed: + enabled: false + default.event.to_be_renamed: + enabled: false + resource_attributes: + map.resource.attr: + enabled: false + optional.resource.attr: + enabled: false + slice.resource.attr: + enabled: false + string.enum.resource.attr: + enabled: false + string.resource.attr: + enabled: false + string.resource.attr_disable_warning: + enabled: false + string.resource.attr_remove_warning: + enabled: false + string.resource.attr_to_be_removed: + enabled: false +filter_set_include: + resource_attributes: + map.resource.attr: + enabled: true + metrics_include: + - regexp: ".*" + events_include: + - regexp: ".*" + optional.resource.attr: + enabled: true + metrics_include: + - regexp: ".*" + events_include: + - regexp: ".*" + slice.resource.attr: + enabled: true + metrics_include: + - regexp: ".*" + events_include: + - regexp: ".*" + string.enum.resource.attr: + enabled: true + metrics_include: + - regexp: ".*" + events_include: + - regexp: ".*" + string.resource.attr: + enabled: true + metrics_include: + - regexp: ".*" + events_include: + - regexp: ".*" + string.resource.attr_disable_warning: + enabled: true + metrics_include: + - regexp: ".*" + events_include: + - regexp: ".*" + string.resource.attr_remove_warning: + enabled: true + metrics_include: + - regexp: ".*" + events_include: + - regexp: ".*" + string.resource.attr_to_be_removed: + enabled: true + metrics_include: + - regexp: ".*" + events_include: + - regexp: ".*" +filter_set_exclude: + resource_attributes: + map.resource.attr: + enabled: true + metrics_exclude: + - regexp: ".*" + events_exclude: + - regexp: ".*" + optional.resource.attr: + enabled: true + metrics_exclude: + - strict: "optional.resource.attr-val" + events_exclude: + - strict: "optional.resource.attr-val" + slice.resource.attr: + enabled: true + metrics_exclude: + - regexp: ".*" + events_exclude: + - regexp: ".*" + string.enum.resource.attr: + enabled: true + metrics_exclude: + - strict: "one" + events_exclude: + - strict: "one" + string.resource.attr: + enabled: true + metrics_exclude: + - strict: "string.resource.attr-val" + events_exclude: + - strict: "string.resource.attr-val" + string.resource.attr_disable_warning: + enabled: true + metrics_exclude: + - strict: "string.resource.attr_disable_warning-val" + events_exclude: + - strict: "string.resource.attr_disable_warning-val" + string.resource.attr_remove_warning: + enabled: true + metrics_exclude: + - strict: "string.resource.attr_remove_warning-val" + events_exclude: + - strict: "string.resource.attr_remove_warning-val" + string.resource.attr_to_be_removed: + enabled: true + metrics_exclude: + - strict: "string.resource.attr_to_be_removed-val" + events_exclude: + - strict: "string.resource.attr_to_be_removed-val" diff --git a/cmd/mdatagen/internal/samplefactoryreceiver/metadata.yaml b/cmd/mdatagen/internal/samplefactoryreceiver/metadata.yaml new file mode 100644 index 000000000000..a64cd97fd72f --- /dev/null +++ b/cmd/mdatagen/internal/samplefactoryreceiver/metadata.yaml @@ -0,0 +1,27 @@ +# Sample metadata file with all available configurations for a receiver. + +type: sample +scope_name: go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver +github_project: open-telemetry/opentelemetry-collector + +sem_conv_version: 1.9.0 + +status: + disable_codecov_badge: true + class: receiver + stability: + development: [logs] + beta: [traces] + stable: [metrics] + deprecated: [profiles] + deprecation: + profiles: + migration: "no migration needed" + date: "2025-02-05" + distributions: [] + unsupported_platforms: [freebsd, illumos] + codeowners: + active: [dmitryax] + warnings: + - Any additional information that should be brought to the consumer's attention + diff --git a/cmd/mdatagen/internal/sampleprocessor/generated_component_test.go b/cmd/mdatagen/internal/sampleprocessor/generated_component_test.go index 6925f6f82f4d..26bf0ad844a8 100644 --- a/cmd/mdatagen/internal/sampleprocessor/generated_component_test.go +++ b/cmd/mdatagen/internal/sampleprocessor/generated_component_test.go @@ -79,7 +79,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { @@ -151,3 +151,19 @@ func generateLifecycleTestTraces() ptrace.Traces { span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/cmd/mdatagen/internal/samplereceiver/generated_component_test.go b/cmd/mdatagen/internal/samplereceiver/generated_component_test.go index e317b2ec8587..99fa261656c0 100644 --- a/cmd/mdatagen/internal/samplereceiver/generated_component_test.go +++ b/cmd/mdatagen/internal/samplereceiver/generated_component_test.go @@ -74,7 +74,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) @@ -85,3 +85,19 @@ func TestComponentLifecycle(t *testing.T) { }) } } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/cmd/mdatagen/internal/samplereceiver/metrics_test.go b/cmd/mdatagen/internal/samplereceiver/metrics_test.go index f010ec208bdd..39dba32b28b6 100644 --- a/cmd/mdatagen/internal/samplereceiver/metrics_test.go +++ b/cmd/mdatagen/internal/samplereceiver/metrics_test.go @@ -28,7 +28,7 @@ func TestGeneratedMetrics(t *testing.T) { func TestComponentTelemetry(t *testing.T) { tt := componenttest.NewTelemetry() factory := NewFactory() - receiver, err := factory.CreateMetrics(context.Background(), metadatatest.NewSettings(tt), componenttest.NewNopHost(), new(consumertest.MetricsSink)) + receiver, err := factory.CreateMetrics(context.Background(), metadatatest.NewSettings(tt), newMdatagenNopHost(), new(consumertest.MetricsSink)) require.NoError(t, err) metadatatest.AssertEqualBatchSizeTriggerSend(t, tt, []metricdata.DataPoint[int64]{ diff --git a/cmd/mdatagen/internal/samplescraper/generated_component_test.go b/cmd/mdatagen/internal/samplescraper/generated_component_test.go index 0d23068a83d1..bfa30b0c4cc9 100644 --- a/cmd/mdatagen/internal/samplescraper/generated_component_test.go +++ b/cmd/mdatagen/internal/samplescraper/generated_component_test.go @@ -66,7 +66,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), scrapertest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) @@ -77,3 +77,19 @@ func TestComponentLifecycle(t *testing.T) { }) } } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/cmd/mdatagen/internal/templates/component_test.go.tmpl b/cmd/mdatagen/internal/templates/component_test.go.tmpl index 309b7bd67bb0..1437e6637c55 100644 --- a/cmd/mdatagen/internal/templates/component_test.go.tmpl +++ b/cmd/mdatagen/internal/templates/component_test.go.tmpl @@ -597,3 +597,21 @@ func generateLifecycleTestTraces() ptrace.Traces { } {{- end }} {{- end }} + +{{- if not .Tests.SkipLifecycle }} +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} +{{- end }} diff --git a/connector/forwardconnector/generated_component_test.go b/connector/forwardconnector/generated_component_test.go index 8814bd8d6491..c60eef921283 100644 --- a/connector/forwardconnector/generated_component_test.go +++ b/connector/forwardconnector/generated_component_test.go @@ -78,7 +78,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstConnector, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstConnector.Start(context.Background(), host)) require.NoError(t, firstConnector.Shutdown(context.Background())) @@ -89,3 +89,19 @@ func TestComponentLifecycle(t *testing.T) { }) } } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/exporter/debugexporter/generated_component_test.go b/exporter/debugexporter/generated_component_test.go index a1a503c484ac..70b7c521bec1 100644 --- a/exporter/debugexporter/generated_component_test.go +++ b/exporter/debugexporter/generated_component_test.go @@ -77,7 +77,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { @@ -151,3 +151,19 @@ func generateLifecycleTestTraces() ptrace.Traces { span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/exporter/nopexporter/generated_component_test.go b/exporter/nopexporter/generated_component_test.go index ea06ba97013a..9db2dbd02a5f 100644 --- a/exporter/nopexporter/generated_component_test.go +++ b/exporter/nopexporter/generated_component_test.go @@ -77,7 +77,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { @@ -151,3 +151,19 @@ func generateLifecycleTestTraces() ptrace.Traces { span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/exporter/otlpexporter/generated_component_test.go b/exporter/otlpexporter/generated_component_test.go index 6e78d300420f..56db8c1503ae 100644 --- a/exporter/otlpexporter/generated_component_test.go +++ b/exporter/otlpexporter/generated_component_test.go @@ -77,7 +77,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { @@ -151,3 +151,19 @@ func generateLifecycleTestTraces() ptrace.Traces { span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/exporter/otlphttpexporter/generated_component_test.go b/exporter/otlphttpexporter/generated_component_test.go index 91c0c0ac2269..ef3b0f47f29d 100644 --- a/exporter/otlphttpexporter/generated_component_test.go +++ b/exporter/otlphttpexporter/generated_component_test.go @@ -77,7 +77,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { @@ -151,3 +151,19 @@ func generateLifecycleTestTraces() ptrace.Traces { span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/extension/memorylimiterextension/generated_component_test.go b/extension/memorylimiterextension/generated_component_test.go index 3a7cd50107ba..393e5e9d4b08 100644 --- a/extension/memorylimiterextension/generated_component_test.go +++ b/extension/memorylimiterextension/generated_component_test.go @@ -36,12 +36,28 @@ func TestComponentLifecycle(t *testing.T) { t.Run("lifecycle", func(t *testing.T) { firstExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) - require.NoError(t, firstExt.Start(context.Background(), componenttest.NewNopHost())) + require.NoError(t, firstExt.Start(context.Background(), newMdatagenNopHost())) require.NoError(t, firstExt.Shutdown(context.Background())) secondExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) - require.NoError(t, secondExt.Start(context.Background(), componenttest.NewNopHost())) + require.NoError(t, secondExt.Start(context.Background(), newMdatagenNopHost())) require.NoError(t, secondExt.Shutdown(context.Background())) }) } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/extension/zpagesextension/generated_component_test.go b/extension/zpagesextension/generated_component_test.go index ca305e577f44..1f5cd31f0e40 100644 --- a/extension/zpagesextension/generated_component_test.go +++ b/extension/zpagesextension/generated_component_test.go @@ -42,12 +42,28 @@ func TestComponentLifecycle(t *testing.T) { t.Run("lifecycle", func(t *testing.T) { firstExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) - require.NoError(t, firstExt.Start(context.Background(), componenttest.NewNopHost())) + require.NoError(t, firstExt.Start(context.Background(), newMdatagenNopHost())) require.NoError(t, firstExt.Shutdown(context.Background())) secondExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) - require.NoError(t, secondExt.Start(context.Background(), componenttest.NewNopHost())) + require.NoError(t, secondExt.Start(context.Background(), newMdatagenNopHost())) require.NoError(t, secondExt.Shutdown(context.Background())) }) } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/processor/batchprocessor/generated_component_test.go b/processor/batchprocessor/generated_component_test.go index beeee720e856..4fe7fa51dfb8 100644 --- a/processor/batchprocessor/generated_component_test.go +++ b/processor/batchprocessor/generated_component_test.go @@ -78,7 +78,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { @@ -150,3 +150,19 @@ func generateLifecycleTestTraces() ptrace.Traces { span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/processor/memorylimiterprocessor/generated_component_test.go b/processor/memorylimiterprocessor/generated_component_test.go index 042f372e46c2..8cedb2a4827d 100644 --- a/processor/memorylimiterprocessor/generated_component_test.go +++ b/processor/memorylimiterprocessor/generated_component_test.go @@ -72,7 +72,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { @@ -144,3 +144,19 @@ func generateLifecycleTestTraces() ptrace.Traces { span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/receiver/nopreceiver/generated_component_test.go b/receiver/nopreceiver/generated_component_test.go index 49d1db079ff1..bafdd244664a 100644 --- a/receiver/nopreceiver/generated_component_test.go +++ b/receiver/nopreceiver/generated_component_test.go @@ -73,7 +73,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) @@ -84,3 +84,19 @@ func TestComponentLifecycle(t *testing.T) { }) } } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/receiver/otlpreceiver/generated_component_test.go b/receiver/otlpreceiver/generated_component_test.go index 90607b16e397..651136873022 100644 --- a/receiver/otlpreceiver/generated_component_test.go +++ b/receiver/otlpreceiver/generated_component_test.go @@ -73,7 +73,7 @@ func TestComponentLifecycle(t *testing.T) { t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) - host := componenttest.NewNopHost() + host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) @@ -84,3 +84,19 @@ func TestComponentLifecycle(t *testing.T) { }) } } + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +}