From 29402267eb28346e8980b00892299839fb6aee3f Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Mon, 27 May 2024 09:09:35 -0700 Subject: [PATCH] [mdatagen] generate utility code to test telemetry (#10212) This will allow components to more easily test the telemetry they should be emitting. --------- Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- .../codeboten_add-mdatagen-testutility.yaml | 25 ++++++ cmd/mdatagen/embeded_templates_test.go | 29 +++---- cmd/mdatagen/go.mod | 2 +- .../internal/samplereceiver/factory.go | 7 +- .../generated_component_telemetry_test.go | 76 +++++++++++++++++++ .../internal/samplereceiver/metrics_test.go | 42 ++++++++++ cmd/mdatagen/main.go | 6 +- cmd/mdatagen/statusdata.go | 1 + .../component_telemetry_test.go.tmpl | 76 +++++++++++++++++++ cmd/mdatagen/templates/telemetry_test.go.tmpl | 3 + .../generated_component_telemetry_test.go | 76 +++++++++++++++++++ exporter/exporterhelper/metadata.yaml | 3 +- exporter/go.mod | 2 +- .../generated_component_telemetry_test.go | 76 +++++++++++++++++++ processor/go.mod | 2 +- .../generated_component_telemetry_test.go | 76 +++++++++++++++++++ processor/processorhelper/metadata.yaml | 3 +- receiver/go.mod | 2 +- .../generated_component_telemetry_test.go | 76 +++++++++++++++++++ receiver/receiverhelper/metadata.yaml | 3 +- .../generated_component_telemetry_test.go | 76 +++++++++++++++++++ receiver/scraperhelper/metadata.yaml | 3 +- 22 files changed, 641 insertions(+), 24 deletions(-) create mode 100644 .chloggen/codeboten_add-mdatagen-testutility.yaml create mode 100644 cmd/mdatagen/internal/samplereceiver/generated_component_telemetry_test.go create mode 100644 cmd/mdatagen/templates/component_telemetry_test.go.tmpl create mode 100644 exporter/exporterhelper/generated_component_telemetry_test.go create mode 100644 processor/batchprocessor/generated_component_telemetry_test.go create mode 100644 processor/processorhelper/generated_component_telemetry_test.go create mode 100644 receiver/receiverhelper/generated_component_telemetry_test.go create mode 100644 receiver/scraperhelper/generated_component_telemetry_test.go diff --git a/.chloggen/codeboten_add-mdatagen-testutility.yaml b/.chloggen/codeboten_add-mdatagen-testutility.yaml new file mode 100644 index 00000000000..ef7b7616af1 --- /dev/null +++ b/.chloggen/codeboten_add-mdatagen-testutility.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: mdatagen + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: auto-generate utilities to test component telemetry + +# One or more tracking issues or pull requests related to the change +issues: [19783] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/cmd/mdatagen/embeded_templates_test.go b/cmd/mdatagen/embeded_templates_test.go index 3bba543b139..40562297e30 100644 --- a/cmd/mdatagen/embeded_templates_test.go +++ b/cmd/mdatagen/embeded_templates_test.go @@ -20,20 +20,21 @@ func TestEnsureTemplatesLoaded(t *testing.T) { var ( templateFiles = map[string]struct{}{ - path.Join(rootDir, "component_test.go.tmpl"): {}, - path.Join(rootDir, "documentation.md.tmpl"): {}, - path.Join(rootDir, "metrics.go.tmpl"): {}, - path.Join(rootDir, "metrics_test.go.tmpl"): {}, - path.Join(rootDir, "resource.go.tmpl"): {}, - path.Join(rootDir, "resource_test.go.tmpl"): {}, - path.Join(rootDir, "config.go.tmpl"): {}, - path.Join(rootDir, "config_test.go.tmpl"): {}, - path.Join(rootDir, "package_test.go.tmpl"): {}, - path.Join(rootDir, "readme.md.tmpl"): {}, - path.Join(rootDir, "status.go.tmpl"): {}, - path.Join(rootDir, "telemetry.go.tmpl"): {}, - path.Join(rootDir, "telemetry_test.go.tmpl"): {}, - path.Join(rootDir, "testdata", "config.yaml.tmpl"): {}, + path.Join(rootDir, "component_test.go.tmpl"): {}, + path.Join(rootDir, "component_telemetry_test.go.tmpl"): {}, + path.Join(rootDir, "documentation.md.tmpl"): {}, + path.Join(rootDir, "metrics.go.tmpl"): {}, + path.Join(rootDir, "metrics_test.go.tmpl"): {}, + path.Join(rootDir, "resource.go.tmpl"): {}, + path.Join(rootDir, "resource_test.go.tmpl"): {}, + path.Join(rootDir, "config.go.tmpl"): {}, + path.Join(rootDir, "config_test.go.tmpl"): {}, + path.Join(rootDir, "package_test.go.tmpl"): {}, + path.Join(rootDir, "readme.md.tmpl"): {}, + path.Join(rootDir, "status.go.tmpl"): {}, + path.Join(rootDir, "telemetry.go.tmpl"): {}, + path.Join(rootDir, "telemetry_test.go.tmpl"): {}, + path.Join(rootDir, "testdata", "config.yaml.tmpl"): {}, } count = 0 ) diff --git a/cmd/mdatagen/go.mod b/cmd/mdatagen/go.mod index dd467ae3614..4348233d0bc 100644 --- a/cmd/mdatagen/go.mod +++ b/cmd/mdatagen/go.mod @@ -14,6 +14,7 @@ require ( go.opentelemetry.io/collector/receiver v0.101.0 go.opentelemetry.io/collector/semconv v0.101.0 go.opentelemetry.io/otel/metric v1.27.0 + go.opentelemetry.io/otel/sdk/metric v1.27.0 go.opentelemetry.io/otel/trace v1.27.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.0 @@ -46,7 +47,6 @@ require ( go.opentelemetry.io/otel v1.27.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.49.0 // indirect go.opentelemetry.io/otel/sdk v1.27.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.27.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/sys v0.20.0 // indirect diff --git a/cmd/mdatagen/internal/samplereceiver/factory.go b/cmd/mdatagen/internal/samplereceiver/factory.go index 89769521f74..565305d540c 100644 --- a/cmd/mdatagen/internal/samplereceiver/factory.go +++ b/cmd/mdatagen/internal/samplereceiver/factory.go @@ -26,7 +26,12 @@ func createTraces(context.Context, receiver.CreateSettings, component.Config, co return nopInstance, nil } -func createMetrics(context.Context, receiver.CreateSettings, component.Config, consumer.Metrics) (receiver.Metrics, error) { +func createMetrics(ctx context.Context, set receiver.CreateSettings, _ component.Config, _ consumer.Metrics) (receiver.Metrics, error) { + telemetryBuilder, err := metadata.NewTelemetryBuilder(set.TelemetrySettings, metadata.WithProcessRuntimeTotalAllocBytesCallback(func() int64 { return 2 })) + if err != nil { + return nil, err + } + telemetryBuilder.BatchSizeTriggerSend.Add(ctx, 1) return nopInstance, nil } diff --git a/cmd/mdatagen/internal/samplereceiver/generated_component_telemetry_test.go b/cmd/mdatagen/internal/samplereceiver/generated_component_telemetry_test.go new file mode 100644 index 00000000000..e8cf2fe05e9 --- /dev/null +++ b/cmd/mdatagen/internal/samplereceiver/generated_component_telemetry_test.go @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package samplereceiver + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/receiver/receivertest" +) + +type componentTestTelemetry struct { + reader *sdkmetric.ManualReader + meterProvider *sdkmetric.MeterProvider +} + +func (tt *componentTestTelemetry) NewCreateSettings() receiver.CreateSettings { + settings := receivertest.NewNopCreateSettings() + settings.MeterProvider = tt.meterProvider + settings.ID = component.NewID(component.MustNewType("sample")) + + return settings +} + +func setupTestTelemetry() componentTestTelemetry { + reader := sdkmetric.NewManualReader() + return componentTestTelemetry{ + reader: reader, + meterProvider: sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)), + } +} + +func (tt *componentTestTelemetry) assertMetrics(t *testing.T, expected []metricdata.Metrics) { + var md metricdata.ResourceMetrics + require.NoError(t, tt.reader.Collect(context.Background(), &md)) + // ensure all required metrics are present + for _, want := range expected { + got := tt.getMetric(want.Name, md) + metricdatatest.AssertEqual(t, want, got, metricdatatest.IgnoreTimestamp()) + } + + // ensure no additional metrics are emitted + require.Equal(t, len(expected), tt.len(md)) +} + +func (tt *componentTestTelemetry) getMetric(name string, got metricdata.ResourceMetrics) metricdata.Metrics { + for _, sm := range got.ScopeMetrics { + for _, m := range sm.Metrics { + if m.Name == name { + return m + } + } + } + + return metricdata.Metrics{} +} + +func (tt *componentTestTelemetry) len(got metricdata.ResourceMetrics) int { + metricsCount := 0 + for _, sm := range got.ScopeMetrics { + metricsCount += len(sm.Metrics) + } + + return metricsCount +} + +func (tt *componentTestTelemetry) Shutdown(ctx context.Context) error { + return tt.meterProvider.Shutdown(ctx) +} diff --git a/cmd/mdatagen/internal/samplereceiver/metrics_test.go b/cmd/mdatagen/internal/samplereceiver/metrics_test.go index ec5f67cf0db..2c3dd5675a5 100644 --- a/cmd/mdatagen/internal/samplereceiver/metrics_test.go +++ b/cmd/mdatagen/internal/samplereceiver/metrics_test.go @@ -4,11 +4,15 @@ package samplereceiver import ( + "context" "testing" "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver/internal/metadata" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver/receivertest" ) @@ -18,3 +22,41 @@ func TestGeneratedMetrics(t *testing.T) { m := mb.Emit() require.Equal(t, 0, m.ResourceMetrics().Len()) } + +func TestComponentTelemetry(t *testing.T) { + tt := setupTestTelemetry() + factory := NewFactory() + _, err := factory.CreateMetricsReceiver(context.Background(), tt.NewCreateSettings(), componenttest.NewNopHost(), new(consumertest.MetricsSink)) + require.NoError(t, err) + tt.assertMetrics(t, []metricdata.Metrics{ + { + Name: "batch_size_trigger_send", + Description: "Number of times the batch was sent due to a size trigger", + Unit: "1", + Data: metricdata.Sum[int64]{ + Temporality: metricdata.CumulativeTemporality, + IsMonotonic: true, + DataPoints: []metricdata.DataPoint[int64]{ + { + Value: 1, + }, + }, + }, + }, + { + Name: "process_runtime_total_alloc_bytes", + Description: "Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc')", + Unit: "By", + Data: metricdata.Sum[int64]{ + Temporality: metricdata.CumulativeTemporality, + IsMonotonic: true, + DataPoints: []metricdata.DataPoint[int64]{ + { + Value: 2, + }, + }, + }, + }, + }) + require.NoError(t, tt.Shutdown(context.Background())) +} diff --git a/cmd/mdatagen/main.go b/cmd/mdatagen/main.go index bb588aea8eb..cc325376826 100644 --- a/cmd/mdatagen/main.go +++ b/cmd/mdatagen/main.go @@ -59,7 +59,7 @@ func run(ymlPath string) error { return fmt.Errorf("unable to create output directory %q: %w", codeDir, err) } if md.Status != nil { - if md.Status.Class != "cmd" && md.Status.Class != "pkg" { + if md.Status.Class != "cmd" && md.Status.Class != "pkg" && !md.Status.NotComponent { if err = generateFile(filepath.Join(tmplDir, "status.go.tmpl"), filepath.Join(codeDir, "generated_status.go"), md, "metadata"); err != nil { return err @@ -88,6 +88,10 @@ func run(ymlPath string) error { toGenerate := map[string]string{} if len(md.Telemetry.Metrics) != 0 { // if there are telemetry metrics, generate telemetry specific files + if err = generateFile(filepath.Join(tmplDir, "component_telemetry_test.go.tmpl"), + filepath.Join(ymlDir, "generated_component_telemetry_test.go"), md, packageName); err != nil { + return err + } toGenerate[filepath.Join(tmplDir, "telemetry.go.tmpl")] = filepath.Join(codeDir, "generated_telemetry.go") toGenerate[filepath.Join(tmplDir, "telemetry_test.go.tmpl")] = filepath.Join(codeDir, "generated_telemetry_test.go") } diff --git a/cmd/mdatagen/statusdata.go b/cmd/mdatagen/statusdata.go index c157b82a73c..db130aaf3ea 100644 --- a/cmd/mdatagen/statusdata.go +++ b/cmd/mdatagen/statusdata.go @@ -39,6 +39,7 @@ type Status struct { Warnings []string `mapstructure:"warnings"` Codeowners *Codeowners `mapstructure:"codeowners"` UnsupportedPlatforms []string `mapstructure:"unsupported_platforms"` + NotComponent bool `mapstructure:"not_component"` } func (s *Status) SortedDistributions() []string { diff --git a/cmd/mdatagen/templates/component_telemetry_test.go.tmpl b/cmd/mdatagen/templates/component_telemetry_test.go.tmpl new file mode 100644 index 00000000000..adba6355149 --- /dev/null +++ b/cmd/mdatagen/templates/component_telemetry_test.go.tmpl @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package {{ if isCommand -}}main{{ else }}{{ .Package }}{{- end }} + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/{{ .Status.Class }}" + "go.opentelemetry.io/collector/{{ .Status.Class }}/{{ .Status.Class }}test" +) + +type componentTestTelemetry struct { + reader *sdkmetric.ManualReader + meterProvider *sdkmetric.MeterProvider +} + +func (tt *componentTestTelemetry) NewCreateSettings() {{ .Status.Class }}.CreateSettings { + settings := {{ .Status.Class }}test.NewNopCreateSettings() + settings.MeterProvider = tt.meterProvider + settings.ID = component.NewID(component.MustNewType("{{ .Type }}")) + + return settings +} + +func setupTestTelemetry() componentTestTelemetry { + reader := sdkmetric.NewManualReader() + return componentTestTelemetry{ + reader: reader, + meterProvider: sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)), + } +} + +func (tt *componentTestTelemetry) assertMetrics(t *testing.T, expected []metricdata.Metrics) { + var md metricdata.ResourceMetrics + require.NoError(t, tt.reader.Collect(context.Background(), &md)) + // ensure all required metrics are present + for _, want := range expected { + got := tt.getMetric(want.Name, md) + metricdatatest.AssertEqual(t, want, got, metricdatatest.IgnoreTimestamp()) + } + + // ensure no additional metrics are emitted + require.Equal(t, len(expected), tt.len(md)) +} + +func (tt *componentTestTelemetry) getMetric(name string, got metricdata.ResourceMetrics) metricdata.Metrics { + for _, sm := range got.ScopeMetrics { + for _, m := range sm.Metrics { + if m.Name == name { + return m + } + } + } + + return metricdata.Metrics{} +} + +func (tt *componentTestTelemetry) len(got metricdata.ResourceMetrics) int { + metricsCount := 0 + for _, sm := range got.ScopeMetrics { + metricsCount += len(sm.Metrics) + } + + return metricsCount +} + +func (tt *componentTestTelemetry) Shutdown(ctx context.Context) error { + return tt.meterProvider.Shutdown(ctx) +} diff --git a/cmd/mdatagen/templates/telemetry_test.go.tmpl b/cmd/mdatagen/templates/telemetry_test.go.tmpl index ed10dbae08b..244a0c92a0b 100644 --- a/cmd/mdatagen/templates/telemetry_test.go.tmpl +++ b/cmd/mdatagen/templates/telemetry_test.go.tmpl @@ -7,6 +7,8 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" @@ -75,4 +77,5 @@ func TestNewTelemetryBuilder(t *testing.T) { require.NoError(t, err) require.True(t, applied) } + {{- end }} diff --git a/exporter/exporterhelper/generated_component_telemetry_test.go b/exporter/exporterhelper/generated_component_telemetry_test.go new file mode 100644 index 00000000000..f12aeee27de --- /dev/null +++ b/exporter/exporterhelper/generated_component_telemetry_test.go @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package exporterhelper + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/exporter" + "go.opentelemetry.io/collector/exporter/exportertest" +) + +type componentTestTelemetry struct { + reader *sdkmetric.ManualReader + meterProvider *sdkmetric.MeterProvider +} + +func (tt *componentTestTelemetry) NewCreateSettings() exporter.CreateSettings { + settings := exportertest.NewNopCreateSettings() + settings.MeterProvider = tt.meterProvider + settings.ID = component.NewID(component.MustNewType("exporterhelper")) + + return settings +} + +func setupTestTelemetry() componentTestTelemetry { + reader := sdkmetric.NewManualReader() + return componentTestTelemetry{ + reader: reader, + meterProvider: sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)), + } +} + +func (tt *componentTestTelemetry) assertMetrics(t *testing.T, expected []metricdata.Metrics) { + var md metricdata.ResourceMetrics + require.NoError(t, tt.reader.Collect(context.Background(), &md)) + // ensure all required metrics are present + for _, want := range expected { + got := tt.getMetric(want.Name, md) + metricdatatest.AssertEqual(t, want, got, metricdatatest.IgnoreTimestamp()) + } + + // ensure no additional metrics are emitted + require.Equal(t, len(expected), tt.len(md)) +} + +func (tt *componentTestTelemetry) getMetric(name string, got metricdata.ResourceMetrics) metricdata.Metrics { + for _, sm := range got.ScopeMetrics { + for _, m := range sm.Metrics { + if m.Name == name { + return m + } + } + } + + return metricdata.Metrics{} +} + +func (tt *componentTestTelemetry) len(got metricdata.ResourceMetrics) int { + metricsCount := 0 + for _, sm := range got.ScopeMetrics { + metricsCount += len(sm.Metrics) + } + + return metricsCount +} + +func (tt *componentTestTelemetry) Shutdown(ctx context.Context) error { + return tt.meterProvider.Shutdown(ctx) +} diff --git a/exporter/exporterhelper/metadata.yaml b/exporter/exporterhelper/metadata.yaml index 1560331c1d9..26b06a37536 100644 --- a/exporter/exporterhelper/metadata.yaml +++ b/exporter/exporterhelper/metadata.yaml @@ -1,7 +1,8 @@ type: exporterhelper status: - class: pkg + class: exporter + not_component: true stability: beta: [traces, metrics, logs] distributions: [core, contrib] diff --git a/exporter/go.mod b/exporter/go.mod index a1bcf9c6b22..7b81b79551e 100644 --- a/exporter/go.mod +++ b/exporter/go.mod @@ -18,6 +18,7 @@ require ( go.opentelemetry.io/otel v1.27.0 go.opentelemetry.io/otel/metric v1.27.0 go.opentelemetry.io/otel/sdk v1.27.0 + go.opentelemetry.io/otel/sdk/metric v1.27.0 go.opentelemetry.io/otel/trace v1.27.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 @@ -49,7 +50,6 @@ require ( github.com/prometheus/procfs v0.15.0 // indirect go.opentelemetry.io/collector/confmap v0.101.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.49.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.27.0 // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect diff --git a/processor/batchprocessor/generated_component_telemetry_test.go b/processor/batchprocessor/generated_component_telemetry_test.go new file mode 100644 index 00000000000..425cd854d90 --- /dev/null +++ b/processor/batchprocessor/generated_component_telemetry_test.go @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package batchprocessor + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/processor" + "go.opentelemetry.io/collector/processor/processortest" +) + +type componentTestTelemetry struct { + reader *sdkmetric.ManualReader + meterProvider *sdkmetric.MeterProvider +} + +func (tt *componentTestTelemetry) NewCreateSettings() processor.CreateSettings { + settings := processortest.NewNopCreateSettings() + settings.MeterProvider = tt.meterProvider + settings.ID = component.NewID(component.MustNewType("batch")) + + return settings +} + +func setupTestTelemetry() componentTestTelemetry { + reader := sdkmetric.NewManualReader() + return componentTestTelemetry{ + reader: reader, + meterProvider: sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)), + } +} + +func (tt *componentTestTelemetry) assertMetrics(t *testing.T, expected []metricdata.Metrics) { + var md metricdata.ResourceMetrics + require.NoError(t, tt.reader.Collect(context.Background(), &md)) + // ensure all required metrics are present + for _, want := range expected { + got := tt.getMetric(want.Name, md) + metricdatatest.AssertEqual(t, want, got, metricdatatest.IgnoreTimestamp()) + } + + // ensure no additional metrics are emitted + require.Equal(t, len(expected), tt.len(md)) +} + +func (tt *componentTestTelemetry) getMetric(name string, got metricdata.ResourceMetrics) metricdata.Metrics { + for _, sm := range got.ScopeMetrics { + for _, m := range sm.Metrics { + if m.Name == name { + return m + } + } + } + + return metricdata.Metrics{} +} + +func (tt *componentTestTelemetry) len(got metricdata.ResourceMetrics) int { + metricsCount := 0 + for _, sm := range got.ScopeMetrics { + metricsCount += len(sm.Metrics) + } + + return metricsCount +} + +func (tt *componentTestTelemetry) Shutdown(ctx context.Context) error { + return tt.meterProvider.Shutdown(ctx) +} diff --git a/processor/go.mod b/processor/go.mod index 7972d7c2146..f15fc226409 100644 --- a/processor/go.mod +++ b/processor/go.mod @@ -13,6 +13,7 @@ require ( go.opentelemetry.io/collector/pdata/testdata v0.101.0 go.opentelemetry.io/otel v1.27.0 go.opentelemetry.io/otel/metric v1.27.0 + go.opentelemetry.io/otel/sdk/metric v1.27.0 go.opentelemetry.io/otel/trace v1.27.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.0 @@ -42,7 +43,6 @@ require ( go.opentelemetry.io/collector/confmap v0.101.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.49.0 // indirect go.opentelemetry.io/otel/sdk v1.27.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.27.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/sys v0.20.0 // indirect diff --git a/processor/processorhelper/generated_component_telemetry_test.go b/processor/processorhelper/generated_component_telemetry_test.go new file mode 100644 index 00000000000..95da78895e0 --- /dev/null +++ b/processor/processorhelper/generated_component_telemetry_test.go @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package processorhelper + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/processor" + "go.opentelemetry.io/collector/processor/processortest" +) + +type componentTestTelemetry struct { + reader *sdkmetric.ManualReader + meterProvider *sdkmetric.MeterProvider +} + +func (tt *componentTestTelemetry) NewCreateSettings() processor.CreateSettings { + settings := processortest.NewNopCreateSettings() + settings.MeterProvider = tt.meterProvider + settings.ID = component.NewID(component.MustNewType("processorhelper")) + + return settings +} + +func setupTestTelemetry() componentTestTelemetry { + reader := sdkmetric.NewManualReader() + return componentTestTelemetry{ + reader: reader, + meterProvider: sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)), + } +} + +func (tt *componentTestTelemetry) assertMetrics(t *testing.T, expected []metricdata.Metrics) { + var md metricdata.ResourceMetrics + require.NoError(t, tt.reader.Collect(context.Background(), &md)) + // ensure all required metrics are present + for _, want := range expected { + got := tt.getMetric(want.Name, md) + metricdatatest.AssertEqual(t, want, got, metricdatatest.IgnoreTimestamp()) + } + + // ensure no additional metrics are emitted + require.Equal(t, len(expected), tt.len(md)) +} + +func (tt *componentTestTelemetry) getMetric(name string, got metricdata.ResourceMetrics) metricdata.Metrics { + for _, sm := range got.ScopeMetrics { + for _, m := range sm.Metrics { + if m.Name == name { + return m + } + } + } + + return metricdata.Metrics{} +} + +func (tt *componentTestTelemetry) len(got metricdata.ResourceMetrics) int { + metricsCount := 0 + for _, sm := range got.ScopeMetrics { + metricsCount += len(sm.Metrics) + } + + return metricsCount +} + +func (tt *componentTestTelemetry) Shutdown(ctx context.Context) error { + return tt.meterProvider.Shutdown(ctx) +} diff --git a/processor/processorhelper/metadata.yaml b/processor/processorhelper/metadata.yaml index 75d66636d15..7e0c72f5c9c 100644 --- a/processor/processorhelper/metadata.yaml +++ b/processor/processorhelper/metadata.yaml @@ -1,7 +1,8 @@ type: processorhelper status: - class: pkg + class: processor + not_component: true stability: beta: [traces, metrics, logs] distributions: [core, contrib] diff --git a/receiver/go.mod b/receiver/go.mod index d7d689c09d1..a980ed1745d 100644 --- a/receiver/go.mod +++ b/receiver/go.mod @@ -13,6 +13,7 @@ require ( go.opentelemetry.io/otel v1.27.0 go.opentelemetry.io/otel/metric v1.27.0 go.opentelemetry.io/otel/sdk v1.27.0 + go.opentelemetry.io/otel/sdk/metric v1.27.0 go.opentelemetry.io/otel/trace v1.27.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 @@ -42,7 +43,6 @@ require ( github.com/prometheus/procfs v0.15.0 // indirect go.opentelemetry.io/collector/confmap v0.101.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.49.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.27.0 // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/receiver/receiverhelper/generated_component_telemetry_test.go b/receiver/receiverhelper/generated_component_telemetry_test.go new file mode 100644 index 00000000000..41d3c0bf81f --- /dev/null +++ b/receiver/receiverhelper/generated_component_telemetry_test.go @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package receiverhelper + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/receiver/receivertest" +) + +type componentTestTelemetry struct { + reader *sdkmetric.ManualReader + meterProvider *sdkmetric.MeterProvider +} + +func (tt *componentTestTelemetry) NewCreateSettings() receiver.CreateSettings { + settings := receivertest.NewNopCreateSettings() + settings.MeterProvider = tt.meterProvider + settings.ID = component.NewID(component.MustNewType("receiverhelper")) + + return settings +} + +func setupTestTelemetry() componentTestTelemetry { + reader := sdkmetric.NewManualReader() + return componentTestTelemetry{ + reader: reader, + meterProvider: sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)), + } +} + +func (tt *componentTestTelemetry) assertMetrics(t *testing.T, expected []metricdata.Metrics) { + var md metricdata.ResourceMetrics + require.NoError(t, tt.reader.Collect(context.Background(), &md)) + // ensure all required metrics are present + for _, want := range expected { + got := tt.getMetric(want.Name, md) + metricdatatest.AssertEqual(t, want, got, metricdatatest.IgnoreTimestamp()) + } + + // ensure no additional metrics are emitted + require.Equal(t, len(expected), tt.len(md)) +} + +func (tt *componentTestTelemetry) getMetric(name string, got metricdata.ResourceMetrics) metricdata.Metrics { + for _, sm := range got.ScopeMetrics { + for _, m := range sm.Metrics { + if m.Name == name { + return m + } + } + } + + return metricdata.Metrics{} +} + +func (tt *componentTestTelemetry) len(got metricdata.ResourceMetrics) int { + metricsCount := 0 + for _, sm := range got.ScopeMetrics { + metricsCount += len(sm.Metrics) + } + + return metricsCount +} + +func (tt *componentTestTelemetry) Shutdown(ctx context.Context) error { + return tt.meterProvider.Shutdown(ctx) +} diff --git a/receiver/receiverhelper/metadata.yaml b/receiver/receiverhelper/metadata.yaml index 9d1fe3c4436..2897d549a70 100644 --- a/receiver/receiverhelper/metadata.yaml +++ b/receiver/receiverhelper/metadata.yaml @@ -1,7 +1,8 @@ type: receiverhelper status: - class: pkg + class: receiver + not_component: true stability: beta: [traces, metrics, logs] distributions: [core, contrib] diff --git a/receiver/scraperhelper/generated_component_telemetry_test.go b/receiver/scraperhelper/generated_component_telemetry_test.go new file mode 100644 index 00000000000..7eeed50b953 --- /dev/null +++ b/receiver/scraperhelper/generated_component_telemetry_test.go @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package scraperhelper + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/metric/metricdata" + "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/receiver/receivertest" +) + +type componentTestTelemetry struct { + reader *sdkmetric.ManualReader + meterProvider *sdkmetric.MeterProvider +} + +func (tt *componentTestTelemetry) NewCreateSettings() receiver.CreateSettings { + settings := receivertest.NewNopCreateSettings() + settings.MeterProvider = tt.meterProvider + settings.ID = component.NewID(component.MustNewType("scraperhelper")) + + return settings +} + +func setupTestTelemetry() componentTestTelemetry { + reader := sdkmetric.NewManualReader() + return componentTestTelemetry{ + reader: reader, + meterProvider: sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)), + } +} + +func (tt *componentTestTelemetry) assertMetrics(t *testing.T, expected []metricdata.Metrics) { + var md metricdata.ResourceMetrics + require.NoError(t, tt.reader.Collect(context.Background(), &md)) + // ensure all required metrics are present + for _, want := range expected { + got := tt.getMetric(want.Name, md) + metricdatatest.AssertEqual(t, want, got, metricdatatest.IgnoreTimestamp()) + } + + // ensure no additional metrics are emitted + require.Equal(t, len(expected), tt.len(md)) +} + +func (tt *componentTestTelemetry) getMetric(name string, got metricdata.ResourceMetrics) metricdata.Metrics { + for _, sm := range got.ScopeMetrics { + for _, m := range sm.Metrics { + if m.Name == name { + return m + } + } + } + + return metricdata.Metrics{} +} + +func (tt *componentTestTelemetry) len(got metricdata.ResourceMetrics) int { + metricsCount := 0 + for _, sm := range got.ScopeMetrics { + metricsCount += len(sm.Metrics) + } + + return metricsCount +} + +func (tt *componentTestTelemetry) Shutdown(ctx context.Context) error { + return tt.meterProvider.Shutdown(ctx) +} diff --git a/receiver/scraperhelper/metadata.yaml b/receiver/scraperhelper/metadata.yaml index 7d084ca2b45..33a1080e7dd 100644 --- a/receiver/scraperhelper/metadata.yaml +++ b/receiver/scraperhelper/metadata.yaml @@ -1,7 +1,8 @@ type: scraperhelper status: - class: pkg + class: receiver + not_component: true stability: beta: [traces, metrics, logs] distributions: [core, contrib]