From 58e444b842eceb1a97dded8e84f8fecb082f3e85 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Wed, 20 Dec 2023 16:12:46 -0800 Subject: [PATCH 01/22] WIP --- otelcol/config.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/otelcol/config.go b/otelcol/config.go index 7c27bd40201..176bcc73010 100644 --- a/otelcol/config.go +++ b/otelcol/config.go @@ -152,6 +152,18 @@ func (cfg *Config) Validate() error { } return fmt.Errorf("service::pipelines::%s: references exporter %q which is not configured", pipelineID, ref) } + + // Validate that pipelines contain valid components for the type + // of pipeline. + switch pipelineID.Type() { + case component.DataTypeTraces: + for _, ref := range pipeline.Receivers { + receiver := cfg.Receivers[ref] + // TODO: somehow get receiver to return component.ErrDataTypeIsNotSupported + } + case component.DataTypeMetrics: + case component.DataTypeLogs: + } } return nil } From 0d5bf667bed908c7f0b5752b0255b45843f919ad Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 9 Jan 2024 18:50:15 -0800 Subject: [PATCH 02/22] Validate that pipeline components are of same signal type as pipeline --- otelcol/collector.go | 21 ++++++++++++++++++++- service/service.go | 30 ++++++++++++++++++++++++++++++ test.yaml | 0 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 test.yaml diff --git a/otelcol/collector.go b/otelcol/collector.go index a1500f5b81c..e0e3aa3cd12 100644 --- a/otelcol/collector.go +++ b/otelcol/collector.go @@ -236,7 +236,11 @@ func (col *Collector) DryRun(ctx context.Context) error { return fmt.Errorf("failed to get config: %w", err) } - return cfg.Validate() + if err := cfg.Validate(); err != nil { + return err + } + + return col.validatePipelineCfg(ctx, cfg, factories) } // Run starts the collector according to the given configuration, and waits for it to complete. @@ -314,3 +318,18 @@ func (col *Collector) shutdown(ctx context.Context) error { func (col *Collector) setCollectorState(state State) { col.state.Store(int32(state)) } + +// validatePipelineConfig validates that the components in a pipeline support the +// signal type of the pipeline. For example, this function will return an error if +// a metrics pipeline has non-metrics components. +func (col *Collector) validatePipelineCfg(ctx context.Context, cfg *Config, factories Factories) error { + set := service.Settings{ + Receivers: receiver.NewBuilder(cfg.Receivers, factories.Receivers), + Processors: processor.NewBuilder(cfg.Processors, factories.Processors), + Exporters: exporter.NewBuilder(cfg.Exporters, factories.Exporters), + Connectors: connector.NewBuilder(cfg.Connectors, factories.Connectors), + Extensions: extension.NewBuilder(cfg.Extensions, factories.Extensions), + } + + return service.Validate(ctx, set, cfg.Service) +} diff --git a/service/service.go b/service/service.go index febff396417..c2379bc390e 100644 --- a/service/service.go +++ b/service/service.go @@ -133,6 +133,36 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) { return srv, nil } +func Validate(ctx context.Context, set Settings, cfg Config) error { + tel, err := telemetry.New(ctx, telemetry.Settings{ZapOptions: set.LoggingOptions}, cfg.Telemetry) + if err != nil { + return fmt.Errorf("failed to get logger: %w", err) + } + + telSettings := servicetelemetry.TelemetrySettings{ + Logger: tel.Logger(), + TracerProvider: tel.TracerProvider(), + MeterProvider: noop.NewMeterProvider(), + } + + pSet := graph.Settings{ + Telemetry: telSettings, + BuildInfo: set.BuildInfo, + ReceiverBuilder: set.Receivers, + ProcessorBuilder: set.Processors, + ExporterBuilder: set.Exporters, + ConnectorBuilder: set.Connectors, + PipelineConfigs: cfg.Pipelines, + } + + _, err = graph.Build(ctx, pSet) + if err != nil { + return fmt.Errorf("failed to build pipelines: %w", err) + } + + return nil +} + // Start starts the extensions and pipelines. If Start fails Shutdown should be called to ensure a clean state. // Start does the following steps in order: // 1. Start all extensions. diff --git a/test.yaml b/test.yaml new file mode 100644 index 00000000000..e69de29bb2d From f2f70ea910e44e89b220a498255085138963d93d Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Thu, 11 Jan 2024 14:16:08 -0800 Subject: [PATCH 03/22] Adding CHANGELOG entry --- .chloggen/validate-pipeline-types.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .chloggen/validate-pipeline-types.yaml diff --git a/.chloggen/validate-pipeline-types.yaml b/.chloggen/validate-pipeline-types.yaml new file mode 100644 index 00000000000..03146a53711 --- /dev/null +++ b/.chloggen/validate-pipeline-types.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: service + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Validate pipeline type against component types + +# One or more tracking issues or pull requests related to the change +issues: [8007] + +# (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: [] \ No newline at end of file From 3f202b01fc5a122929420de1a32f9220b9b666ec Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Thu, 11 Jan 2024 14:48:54 -0800 Subject: [PATCH 04/22] Undo experimental changes --- otelcol/config.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/otelcol/config.go b/otelcol/config.go index 176bcc73010..7c27bd40201 100644 --- a/otelcol/config.go +++ b/otelcol/config.go @@ -152,18 +152,6 @@ func (cfg *Config) Validate() error { } return fmt.Errorf("service::pipelines::%s: references exporter %q which is not configured", pipelineID, ref) } - - // Validate that pipelines contain valid components for the type - // of pipeline. - switch pipelineID.Type() { - case component.DataTypeTraces: - for _, ref := range pipeline.Receivers { - receiver := cfg.Receivers[ref] - // TODO: somehow get receiver to return component.ErrDataTypeIsNotSupported - } - case component.DataTypeMetrics: - case component.DataTypeLogs: - } } return nil } From e2ea407d3e7ad628156c37be72733130adf46949 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Thu, 11 Jan 2024 16:23:31 -0800 Subject: [PATCH 05/22] Add unit test --- service/service_test.go | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/service/service_test.go b/service/service_test.go index c538dc0027e..2d8ac05b47e 100644 --- a/service/service_test.go +++ b/service/service_test.go @@ -13,6 +13,9 @@ import ( "testing" "time" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/receiver" + "github.com/prometheus/common/expfmt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -430,6 +433,64 @@ func TestServiceFatalError(t *testing.T) { require.ErrorIs(t, err, assert.AnError) } +func TestServiceValidate(t *testing.T) { + tests := map[string]struct { + createSettings func() Settings + config Config + + expectedErr string + }{ + "same_types": { + createSettings: func() Settings { return newNopSettings() }, + config: newNopConfig(), + expectedErr: "", + }, + "different_types": { + createSettings: func() Settings { + const typeStr = "nop" + + createMetricsReceiver := func(_ context.Context, _ receiver.CreateSettings, _ component.Config, _ consumer.Metrics) (receiver.Metrics, error) { + return struct { + component.StartFunc + component.ShutdownFunc + }{}, nil + } + + createDefaultConfig := func() component.Config { + return &struct{}{} + } + + metricsOnlyReceiverFactory := receiver.NewFactory( + typeStr, + createDefaultConfig, + receiver.WithMetrics(createMetricsReceiver, component.StabilityLevelStable), + ) + + settings := newNopSettings() + settings.Receivers = receiver.NewBuilder( + map[component.ID]component.Config{component.NewID(typeStr): metricsOnlyReceiverFactory.CreateDefaultConfig()}, + map[component.Type]receiver.Factory{typeStr: metricsOnlyReceiverFactory}, + ) + + return settings + }, + config: newNopConfig(), + expectedErr: `failed to create "nop" receiver for data type "traces": telemetry type is not supported`, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + err := Validate(context.Background(), test.createSettings(), test.config) + if test.expectedErr == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, test.expectedErr) + } + }) + } +} + func assertResourceLabels(t *testing.T, res pcommon.Resource, expectedLabels map[string]labelValue) { for key, labelValue := range expectedLabels { lookupKey, ok := prometheusToOtelConv[key] From 05e8169dd311379a377e23115681f520440d407a Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Thu, 11 Jan 2024 16:38:52 -0800 Subject: [PATCH 06/22] Refactoring for internal reuse --- service/service.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/service/service.go b/service/service.go index c2379bc390e..759c66524a4 100644 --- a/service/service.go +++ b/service/service.go @@ -7,6 +7,7 @@ import ( "context" "errors" "fmt" + "go.opentelemetry.io/otel/metric/noop" "runtime" sdkresource "go.opentelemetry.io/otel/sdk/resource" @@ -145,6 +146,10 @@ func Validate(ctx context.Context, set Settings, cfg Config) error { MeterProvider: noop.NewMeterProvider(), } + return validate(ctx, set, cfg, telSettings) +} + +func validate(ctx context.Context, set Settings, cfg Config, telSettings servicetelemetry.TelemetrySettings) error { pSet := graph.Settings{ Telemetry: telSettings, BuildInfo: set.BuildInfo, From d99b7b3772a5162916186b0bf74033d878ea8f41 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Thu, 11 Jan 2024 16:39:10 -0800 Subject: [PATCH 07/22] Better error message --- service/service.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/service/service.go b/service/service.go index 759c66524a4..37f2eb679b4 100644 --- a/service/service.go +++ b/service/service.go @@ -160,9 +160,8 @@ func validate(ctx context.Context, set Settings, cfg Config, telSettings service PipelineConfigs: cfg.Pipelines, } - _, err = graph.Build(ctx, pSet) - if err != nil { - return fmt.Errorf("failed to build pipelines: %w", err) + if _, err := graph.Build(ctx, pSet); err != nil { + return fmt.Errorf("failed to build pipelines for validation: %w", err) } return nil From 12341011bf22e19d10d23513bcb8b0780da9ee2b Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Thu, 11 Jan 2024 16:40:12 -0800 Subject: [PATCH 08/22] Remove accidentally committed file --- test.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test.yaml diff --git a/test.yaml b/test.yaml deleted file mode 100644 index e69de29bb2d..00000000000 From a6e92be11ecf6e5345ae417bd368b00cc85fbc6e Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Wed, 17 Jan 2024 14:20:11 -0800 Subject: [PATCH 09/22] Remove unnecessary validation when constructing new Service --- service/service.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/service/service.go b/service/service.go index 37f2eb679b4..8ce8874b4d1 100644 --- a/service/service.go +++ b/service/service.go @@ -123,7 +123,7 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) { // ignore other errors as they represent invalid state transitions and are considered benign. }), } - + // process the configuration and initialize the pipeline if err = srv.initExtensionsAndPipeline(ctx, set, cfg); err != nil { // If pipeline initialization fails then shut down telemetry @@ -146,10 +146,6 @@ func Validate(ctx context.Context, set Settings, cfg Config) error { MeterProvider: noop.NewMeterProvider(), } - return validate(ctx, set, cfg, telSettings) -} - -func validate(ctx context.Context, set Settings, cfg Config, telSettings servicetelemetry.TelemetrySettings) error { pSet := graph.Settings{ Telemetry: telSettings, BuildInfo: set.BuildInfo, From 652454a25b21464f97746ca742618daa2eff5caa Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Thu, 1 Feb 2024 05:03:14 -0800 Subject: [PATCH 10/22] Fix formatting --- service/service.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/service/service.go b/service/service.go index 8ce8874b4d1..1926a2910ad 100644 --- a/service/service.go +++ b/service/service.go @@ -7,9 +7,10 @@ import ( "context" "errors" "fmt" - "go.opentelemetry.io/otel/metric/noop" "runtime" + "go.opentelemetry.io/otel/metric/noop" + sdkresource "go.opentelemetry.io/otel/sdk/resource" "go.uber.org/multierr" "go.uber.org/zap" @@ -123,7 +124,7 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) { // ignore other errors as they represent invalid state transitions and are considered benign. }), } - + // process the configuration and initialize the pipeline if err = srv.initExtensionsAndPipeline(ctx, set, cfg); err != nil { // If pipeline initialization fails then shut down telemetry From fe472be8011da1de84338d9bbb391aeaf793892d Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Mon, 12 Feb 2024 15:24:27 -0800 Subject: [PATCH 11/22] Make linter happy --- service/service_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/service_test.go b/service/service_test.go index 2d8ac05b47e..adc4aa4d205 100644 --- a/service/service_test.go +++ b/service/service_test.go @@ -441,7 +441,7 @@ func TestServiceValidate(t *testing.T) { expectedErr string }{ "same_types": { - createSettings: func() Settings { return newNopSettings() }, + createSettings: newNopSettings, config: newNopConfig(), expectedErr: "", }, From 7004bc6ff7c081f10f15329cc079ba9b6a583ff9 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Mon, 12 Feb 2024 15:27:40 -0800 Subject: [PATCH 12/22] Make error check more resilient --- service/service_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/service_test.go b/service/service_test.go index adc4aa4d205..235969cfb42 100644 --- a/service/service_test.go +++ b/service/service_test.go @@ -475,7 +475,7 @@ func TestServiceValidate(t *testing.T) { return settings }, config: newNopConfig(), - expectedErr: `failed to create "nop" receiver for data type "traces": telemetry type is not supported`, + expectedErr: `telemetry type is not supported`, }, } From a49175bbd86c3e5c0e6c0ff3b2f6287b7a92fa2d Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Mon, 12 Feb 2024 16:36:50 -0800 Subject: [PATCH 13/22] Making impi happy --- service/service.go | 1 - service/service_test.go | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/service/service.go b/service/service.go index 1926a2910ad..052d7e957a6 100644 --- a/service/service.go +++ b/service/service.go @@ -10,7 +10,6 @@ import ( "runtime" "go.opentelemetry.io/otel/metric/noop" - sdkresource "go.opentelemetry.io/otel/sdk/resource" "go.uber.org/multierr" "go.uber.org/zap" diff --git a/service/service_test.go b/service/service_test.go index 235969cfb42..808130d8ad0 100644 --- a/service/service_test.go +++ b/service/service_test.go @@ -13,9 +13,6 @@ import ( "testing" "time" - "go.opentelemetry.io/collector/consumer" - "go.opentelemetry.io/collector/receiver" - "github.com/prometheus/common/expfmt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -27,6 +24,7 @@ import ( "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/connector/connectortest" + "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensiontest" @@ -34,6 +32,7 @@ import ( "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/processor/processortest" + "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/service/extensions" "go.opentelemetry.io/collector/service/pipelines" From baeebb749048a64574cf86037fd8ac3ba38a800a Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Mon, 4 Mar 2024 16:57:52 -0800 Subject: [PATCH 14/22] Add godoc comment on service.Validate function --- service/service.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/service/service.go b/service/service.go index 052d7e957a6..ac28f3c0bd9 100644 --- a/service/service.go +++ b/service/service.go @@ -134,6 +134,8 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) { return srv, nil } +// Validate validates the service. Validation fails if all the components in every +// service pipeline don't support the same signal type as that of the pipeline. func Validate(ctx context.Context, set Settings, cfg Config) error { tel, err := telemetry.New(ctx, telemetry.Settings{ZapOptions: set.LoggingOptions}, cfg.Telemetry) if err != nil { From 9903642f5ffbdfd38dca74b87eccaebbd6e3369a Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 5 Mar 2024 14:08:59 -0800 Subject: [PATCH 15/22] Call service.New to validate pipeline types --- otelcol/collector.go | 7 ++- otelcol/collector_test.go | 41 ++++++++++--- otelcol/factories_test.go | 2 +- .../otelcol-invalid-receiver-type.yaml | 18 ++++++ receiver/receivertest/nop_logs_receiver.go | 54 +++++++++++++++++ service/service.go | 32 ---------- service/service_test.go | 60 ------------------- 7 files changed, 112 insertions(+), 102 deletions(-) create mode 100644 otelcol/testdata/otelcol-invalid-receiver-type.yaml create mode 100644 receiver/receivertest/nop_logs_receiver.go diff --git a/otelcol/collector.go b/otelcol/collector.go index e0e3aa3cd12..8e50749f449 100644 --- a/otelcol/collector.go +++ b/otelcol/collector.go @@ -331,5 +331,10 @@ func (col *Collector) validatePipelineCfg(ctx context.Context, cfg *Config, fact Extensions: extension.NewBuilder(cfg.Extensions, factories.Extensions), } - return service.Validate(ctx, set, cfg.Service) + _, err := service.New(ctx, set, cfg.Service) + if err != nil { + return err + } + + return nil } diff --git a/otelcol/collector_test.go b/otelcol/collector_test.go index c56d56fc728..94a728add09 100644 --- a/otelcol/collector_test.go +++ b/otelcol/collector_test.go @@ -421,16 +421,41 @@ func TestCollectorClosedStateOnStartUpError(t *testing.T) { } func TestCollectorDryRun(t *testing.T) { - // Load a bad config causing startup to fail - set := CollectorSettings{ - BuildInfo: component.NewDefaultBuildInfo(), - Factories: nopFactories, - ConfigProviderSettings: newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-invalid.yaml")}), + tests := map[string]struct { + settings CollectorSettings + expectedErr string + }{ + "invalid_processor": { + settings: CollectorSettings{ + BuildInfo: component.NewDefaultBuildInfo(), + Factories: nopFactories, + ConfigProviderSettings: newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-invalid.yaml")}), + }, + expectedErr: `service::pipelines::traces: references processor "invalid" which is not configured`, + }, + "logs_receiver_traces_pipeline": { + settings: CollectorSettings{ + BuildInfo: component.NewDefaultBuildInfo(), + Factories: nopFactories, + ConfigProviderSettings: newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-invalid-receiver-type.yaml")}), + }, + expectedErr: `failed to build pipelines: failed to create "nop_logs" receiver for data type "traces": telemetry type is not supported`, + }, } - col, err := NewCollector(set) - require.NoError(t, err) - require.Error(t, col.DryRun(context.Background())) + for name, test := range tests { + t.Run(name, func(t *testing.T) { + col, err := NewCollector(test.settings) + require.NoError(t, err) + + err = col.DryRun(context.Background()) + if test.expectedErr == "" { + require.NoError(t, err) + } else { + require.EqualError(t, err, test.expectedErr) + } + }) + } } func TestPassConfmapToServiceFailure(t *testing.T) { diff --git a/otelcol/factories_test.go b/otelcol/factories_test.go index 645d59c7db2..993e9f75cf7 100644 --- a/otelcol/factories_test.go +++ b/otelcol/factories_test.go @@ -28,7 +28,7 @@ func nopFactories() (Factories, error) { return Factories{}, err } - if factories.Receivers, err = receiver.MakeFactoryMap(receivertest.NewNopFactory()); err != nil { + if factories.Receivers, err = receiver.MakeFactoryMap(receivertest.NewNopFactory(), receivertest.NewNopLogsFactory()); err != nil { return Factories{}, err } diff --git a/otelcol/testdata/otelcol-invalid-receiver-type.yaml b/otelcol/testdata/otelcol-invalid-receiver-type.yaml new file mode 100644 index 00000000000..5837810fcca --- /dev/null +++ b/otelcol/testdata/otelcol-invalid-receiver-type.yaml @@ -0,0 +1,18 @@ +receivers: + nop_logs: + +processors: + nop: + +exporters: + nop: + +service: + telemetry: + metrics: + address: localhost:8888 + pipelines: + traces: + receivers: [nop_logs] + processors: [nop] + exporters: [nop] diff --git a/receiver/receivertest/nop_logs_receiver.go b/receiver/receivertest/nop_logs_receiver.go new file mode 100644 index 00000000000..4d872e1e631 --- /dev/null +++ b/receiver/receivertest/nop_logs_receiver.go @@ -0,0 +1,54 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package receivertest // import "go.opentelemetry.io/collector/receiver/receivertest" + +import ( + "context" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/receiver" +) + +var nopLogsComponentType = component.MustNewType("nop_logs") + +// NewNopLogsCreateSettings returns a new nop settings for Create*Receiver functions. +func NewNopLogsCreateSettings() receiver.CreateSettings { + return receiver.CreateSettings{ + ID: component.NewID(nopLogsComponentType), + TelemetrySettings: componenttest.NewNopTelemetrySettings(), + BuildInfo: component.NewDefaultBuildInfo(), + } +} + +// NewNopLogsFactory returns a receiver.Factory that constructs nop logs receivers. +func NewNopLogsFactory() receiver.Factory { + createLogs := func(context.Context, receiver.CreateSettings, component.Config, consumer.Logs) (receiver.Logs, error) { + return nopInstance, nil + } + + return receiver.NewFactory( + nopLogsComponentType, + func() component.Config { return &nopLogsConfig{} }, + receiver.WithLogs(createLogs, component.StabilityLevelStable)) +} + +type nopLogsConfig struct{} + +var nopLogsInstance = &nopLogsReceiver{} + +// nopLogsReceiver acts as a receiver for testing purposes. +type nopLogsReceiver struct { + component.StartFunc + component.ShutdownFunc +} + +// NewNopLogsBuilder returns a receiver.Builder that constructs nop receivers. +func NewNopLogsBuilder() *receiver.Builder { + nopFactory := NewNopLogsFactory() + return receiver.NewBuilder( + map[component.ID]component.Config{component.NewID(componentType): nopFactory.CreateDefaultConfig()}, + map[component.Type]receiver.Factory{componentType: nopFactory}) +} diff --git a/service/service.go b/service/service.go index ac28f3c0bd9..febff396417 100644 --- a/service/service.go +++ b/service/service.go @@ -9,7 +9,6 @@ import ( "fmt" "runtime" - "go.opentelemetry.io/otel/metric/noop" sdkresource "go.opentelemetry.io/otel/sdk/resource" "go.uber.org/multierr" "go.uber.org/zap" @@ -134,37 +133,6 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) { return srv, nil } -// Validate validates the service. Validation fails if all the components in every -// service pipeline don't support the same signal type as that of the pipeline. -func Validate(ctx context.Context, set Settings, cfg Config) error { - tel, err := telemetry.New(ctx, telemetry.Settings{ZapOptions: set.LoggingOptions}, cfg.Telemetry) - if err != nil { - return fmt.Errorf("failed to get logger: %w", err) - } - - telSettings := servicetelemetry.TelemetrySettings{ - Logger: tel.Logger(), - TracerProvider: tel.TracerProvider(), - MeterProvider: noop.NewMeterProvider(), - } - - pSet := graph.Settings{ - Telemetry: telSettings, - BuildInfo: set.BuildInfo, - ReceiverBuilder: set.Receivers, - ProcessorBuilder: set.Processors, - ExporterBuilder: set.Exporters, - ConnectorBuilder: set.Connectors, - PipelineConfigs: cfg.Pipelines, - } - - if _, err := graph.Build(ctx, pSet); err != nil { - return fmt.Errorf("failed to build pipelines for validation: %w", err) - } - - return nil -} - // Start starts the extensions and pipelines. If Start fails Shutdown should be called to ensure a clean state. // Start does the following steps in order: // 1. Start all extensions. diff --git a/service/service_test.go b/service/service_test.go index 808130d8ad0..c538dc0027e 100644 --- a/service/service_test.go +++ b/service/service_test.go @@ -24,7 +24,6 @@ import ( "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/connector/connectortest" - "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensiontest" @@ -32,7 +31,6 @@ import ( "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/processor/processortest" - "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/service/extensions" "go.opentelemetry.io/collector/service/pipelines" @@ -432,64 +430,6 @@ func TestServiceFatalError(t *testing.T) { require.ErrorIs(t, err, assert.AnError) } -func TestServiceValidate(t *testing.T) { - tests := map[string]struct { - createSettings func() Settings - config Config - - expectedErr string - }{ - "same_types": { - createSettings: newNopSettings, - config: newNopConfig(), - expectedErr: "", - }, - "different_types": { - createSettings: func() Settings { - const typeStr = "nop" - - createMetricsReceiver := func(_ context.Context, _ receiver.CreateSettings, _ component.Config, _ consumer.Metrics) (receiver.Metrics, error) { - return struct { - component.StartFunc - component.ShutdownFunc - }{}, nil - } - - createDefaultConfig := func() component.Config { - return &struct{}{} - } - - metricsOnlyReceiverFactory := receiver.NewFactory( - typeStr, - createDefaultConfig, - receiver.WithMetrics(createMetricsReceiver, component.StabilityLevelStable), - ) - - settings := newNopSettings() - settings.Receivers = receiver.NewBuilder( - map[component.ID]component.Config{component.NewID(typeStr): metricsOnlyReceiverFactory.CreateDefaultConfig()}, - map[component.Type]receiver.Factory{typeStr: metricsOnlyReceiverFactory}, - ) - - return settings - }, - config: newNopConfig(), - expectedErr: `telemetry type is not supported`, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - err := Validate(context.Background(), test.createSettings(), test.config) - if test.expectedErr == "" { - require.NoError(t, err) - } else { - require.ErrorContains(t, err, test.expectedErr) - } - }) - } -} - func assertResourceLabels(t *testing.T, res pcommon.Resource, expectedLabels map[string]labelValue) { for key, labelValue := range expectedLabels { lookupKey, ok := prometheusToOtelConv[key] From 66fa0e4b933b067ab05d587daf391bf4acb4016d Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Wed, 6 Mar 2024 17:39:34 -0800 Subject: [PATCH 16/22] Use functional options to dynamically construct nop receiver --- otelcol/collector_test.go | 2 +- otelcol/factories_test.go | 2 +- .../otelcol-invalid-receiver-type.yaml | 4 +- receiver/receivertest/nop_logs_receiver.go | 54 ------------- receiver/receivertest/nop_receiver.go | 79 ++++++++++++++++--- 5 files changed, 70 insertions(+), 71 deletions(-) delete mode 100644 receiver/receivertest/nop_logs_receiver.go diff --git a/otelcol/collector_test.go b/otelcol/collector_test.go index 94a728add09..4a0accb800e 100644 --- a/otelcol/collector_test.go +++ b/otelcol/collector_test.go @@ -439,7 +439,7 @@ func TestCollectorDryRun(t *testing.T) { Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-invalid-receiver-type.yaml")}), }, - expectedErr: `failed to build pipelines: failed to create "nop_logs" receiver for data type "traces": telemetry type is not supported`, + expectedErr: `failed to build pipelines: failed to create "nop_notraces" receiver for data type "traces": telemetry type is not supported`, }, } diff --git a/otelcol/factories_test.go b/otelcol/factories_test.go index 993e9f75cf7..1e6d0b34a06 100644 --- a/otelcol/factories_test.go +++ b/otelcol/factories_test.go @@ -28,7 +28,7 @@ func nopFactories() (Factories, error) { return Factories{}, err } - if factories.Receivers, err = receiver.MakeFactoryMap(receivertest.NewNopFactory(), receivertest.NewNopLogsFactory()); err != nil { + if factories.Receivers, err = receiver.MakeFactoryMap(receivertest.NewNopFactory(), receivertest.NewNopFactory(receivertest.WithoutTraces())); err != nil { return Factories{}, err } diff --git a/otelcol/testdata/otelcol-invalid-receiver-type.yaml b/otelcol/testdata/otelcol-invalid-receiver-type.yaml index 5837810fcca..0a9c071248c 100644 --- a/otelcol/testdata/otelcol-invalid-receiver-type.yaml +++ b/otelcol/testdata/otelcol-invalid-receiver-type.yaml @@ -1,5 +1,5 @@ receivers: - nop_logs: + nop_notraces: processors: nop: @@ -13,6 +13,6 @@ service: address: localhost:8888 pipelines: traces: - receivers: [nop_logs] + receivers: [nop_notraces] processors: [nop] exporters: [nop] diff --git a/receiver/receivertest/nop_logs_receiver.go b/receiver/receivertest/nop_logs_receiver.go deleted file mode 100644 index 4d872e1e631..00000000000 --- a/receiver/receivertest/nop_logs_receiver.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package receivertest // import "go.opentelemetry.io/collector/receiver/receivertest" - -import ( - "context" - - "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/component/componenttest" - "go.opentelemetry.io/collector/consumer" - "go.opentelemetry.io/collector/receiver" -) - -var nopLogsComponentType = component.MustNewType("nop_logs") - -// NewNopLogsCreateSettings returns a new nop settings for Create*Receiver functions. -func NewNopLogsCreateSettings() receiver.CreateSettings { - return receiver.CreateSettings{ - ID: component.NewID(nopLogsComponentType), - TelemetrySettings: componenttest.NewNopTelemetrySettings(), - BuildInfo: component.NewDefaultBuildInfo(), - } -} - -// NewNopLogsFactory returns a receiver.Factory that constructs nop logs receivers. -func NewNopLogsFactory() receiver.Factory { - createLogs := func(context.Context, receiver.CreateSettings, component.Config, consumer.Logs) (receiver.Logs, error) { - return nopInstance, nil - } - - return receiver.NewFactory( - nopLogsComponentType, - func() component.Config { return &nopLogsConfig{} }, - receiver.WithLogs(createLogs, component.StabilityLevelStable)) -} - -type nopLogsConfig struct{} - -var nopLogsInstance = &nopLogsReceiver{} - -// nopLogsReceiver acts as a receiver for testing purposes. -type nopLogsReceiver struct { - component.StartFunc - component.ShutdownFunc -} - -// NewNopLogsBuilder returns a receiver.Builder that constructs nop receivers. -func NewNopLogsBuilder() *receiver.Builder { - nopFactory := NewNopLogsFactory() - return receiver.NewBuilder( - map[component.ID]component.Config{component.NewID(componentType): nopFactory.CreateDefaultConfig()}, - map[component.Type]receiver.Factory{componentType: nopFactory}) -} diff --git a/receiver/receivertest/nop_receiver.go b/receiver/receivertest/nop_receiver.go index 024242a864a..4af56770509 100644 --- a/receiver/receivertest/nop_receiver.go +++ b/receiver/receivertest/nop_receiver.go @@ -14,25 +14,80 @@ import ( "go.opentelemetry.io/collector/receiver" ) -var componentType = component.MustNewType("nop") +var defaultComponentType = component.MustNewType("nop") // NewNopCreateSettings returns a new nop settings for Create*Receiver functions. func NewNopCreateSettings() receiver.CreateSettings { return receiver.CreateSettings{ - ID: component.NewIDWithName(componentType, uuid.NewString()), + ID: component.NewIDWithName(defaultComponentType, uuid.NewString()), TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } // NewNopFactory returns a receiver.Factory that constructs nop receivers. -func NewNopFactory() receiver.Factory { - return receiver.NewFactory( - componentType, - func() component.Config { return &nopConfig{} }, - receiver.WithTraces(createTraces, component.StabilityLevelStable), - receiver.WithMetrics(createMetrics, component.StabilityLevelStable), - receiver.WithLogs(createLogs, component.StabilityLevelStable)) +func NewNopFactory(opts ...NopOption) receiver.Factory { + cfg := defaultNopConfig() + for _, opt := range opts { + opt(cfg) + } + + factoryOpts := make([]receiver.FactoryOption, 0) + componentType := defaultComponentType + if cfg.withTraces { + factoryOpts = append(factoryOpts, receiver.WithTraces(createTraces, component.StabilityLevelStable)) + } else { + componentType += "_notraces" + } + if cfg.withMetrics { + factoryOpts = append(factoryOpts, receiver.WithMetrics(createMetrics, component.StabilityLevelStable)) + } else { + componentType += "_nometrics" + } + if cfg.withLogs { + factoryOpts = append(factoryOpts, receiver.WithLogs(createLogs, component.StabilityLevelStable)) + } else { + componentType += "_nologs" + } + + return receiver.NewFactory(componentType, func() component.Config { return cfg }, factoryOpts...) +} + +type nopConfig struct { + withTraces bool + withMetrics bool + withLogs bool +} + +func defaultNopConfig() *nopConfig { + return &nopConfig{ + withTraces: true, + withMetrics: true, + withLogs: true, + } +} + +type NopOption func(*nopConfig) + +// WithoutTraces creates a NopReceiver that cannot produce traces. +func WithoutTraces() NopOption { + return func(c *nopConfig) { + c.withTraces = false + } +} + +// WithoutMetrics creates a NopReceiver that cannot produce metrics. +func WithoutMetrics() NopOption { + return func(c *nopConfig) { + c.withMetrics = false + } +} + +// WithoutLogs creates a NopReceiver that cannot produce logs. +func WithoutLogs() NopOption { + return func(c *nopConfig) { + c.withLogs = false + } } func createTraces(context.Context, receiver.CreateSettings, component.Config, consumer.Traces) (receiver.Traces, error) { @@ -47,8 +102,6 @@ func createLogs(context.Context, receiver.CreateSettings, component.Config, cons return nopInstance, nil } -type nopConfig struct{} - var nopInstance = &nopReceiver{} // nopReceiver acts as a receiver for testing purposes. @@ -61,6 +114,6 @@ type nopReceiver struct { func NewNopBuilder() *receiver.Builder { nopFactory := NewNopFactory() return receiver.NewBuilder( - map[component.ID]component.Config{component.NewID(componentType): nopFactory.CreateDefaultConfig()}, - map[component.Type]receiver.Factory{componentType: nopFactory}) + map[component.ID]component.Config{component.NewID(defaultComponentType): nopFactory.CreateDefaultConfig()}, + map[component.Type]receiver.Factory{defaultComponentType: nopFactory}) } From 8669a58ab3a704488482ecfa6f6bdce4948e1fb6 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Thu, 7 Mar 2024 10:28:47 -0800 Subject: [PATCH 17/22] Fix type mismatches --- receiver/receivertest/nop_receiver.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/receiver/receivertest/nop_receiver.go b/receiver/receivertest/nop_receiver.go index 4af56770509..d3583a4e0ed 100644 --- a/receiver/receivertest/nop_receiver.go +++ b/receiver/receivertest/nop_receiver.go @@ -33,7 +33,7 @@ func NewNopFactory(opts ...NopOption) receiver.Factory { } factoryOpts := make([]receiver.FactoryOption, 0) - componentType := defaultComponentType + componentType := defaultComponentType.String() if cfg.withTraces { factoryOpts = append(factoryOpts, receiver.WithTraces(createTraces, component.StabilityLevelStable)) } else { @@ -50,7 +50,7 @@ func NewNopFactory(opts ...NopOption) receiver.Factory { componentType += "_nologs" } - return receiver.NewFactory(componentType, func() component.Config { return cfg }, factoryOpts...) + return receiver.NewFactory(component.MustNewType(componentType), func() component.Config { return cfg }, factoryOpts...) } type nopConfig struct { From 0294904dcce82f5dd817e4a6f5c579d8a9ec67db Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Thu, 7 Mar 2024 11:36:04 -0800 Subject: [PATCH 18/22] Implement new nop factor constructor for specific data type --- otelcol/collector_test.go | 2 +- otelcol/command_components.go | 85 ++++++++++++------- otelcol/factories_test.go | 3 +- .../otelcol-invalid-receiver-type.yaml | 4 +- receiver/receivertest/nop_receiver.go | 82 ++++++------------ 5 files changed, 85 insertions(+), 91 deletions(-) diff --git a/otelcol/collector_test.go b/otelcol/collector_test.go index 4a0accb800e..94a728add09 100644 --- a/otelcol/collector_test.go +++ b/otelcol/collector_test.go @@ -439,7 +439,7 @@ func TestCollectorDryRun(t *testing.T) { Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-invalid-receiver-type.yaml")}), }, - expectedErr: `failed to build pipelines: failed to create "nop_notraces" receiver for data type "traces": telemetry type is not supported`, + expectedErr: `failed to build pipelines: failed to create "nop_logs" receiver for data type "traces": telemetry type is not supported`, }, } diff --git a/otelcol/command_components.go b/otelcol/command_components.go index 83dd4670375..ced647cb1d0 100644 --- a/otelcol/command_components.go +++ b/otelcol/command_components.go @@ -5,6 +5,12 @@ package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "fmt" + "go.opentelemetry.io/collector/connector" + "go.opentelemetry.io/collector/exporter" + "go.opentelemetry.io/collector/extension" + "go.opentelemetry.io/collector/processor" + "go.opentelemetry.io/collector/receiver" + "sort" "github.com/spf13/cobra" "gopkg.in/yaml.v3" @@ -41,59 +47,59 @@ func newComponentsCommand(set CollectorSettings) *cobra.Command { } components := componentsOutput{} - for con := range factories.Connectors { + for _, con := range sortFactoriesByType[connector.Factory](factories.Connectors) { components.Connectors = append(components.Connectors, componentWithStability{ - Name: con, + Name: con.Type(), Stability: map[string]string{ - "logs-to-logs": factories.Connectors[con].LogsToLogsStability().String(), - "logs-to-metrics": factories.Connectors[con].LogsToMetricsStability().String(), - "logs-to-traces": factories.Connectors[con].LogsToTracesStability().String(), + "logs-to-logs": con.LogsToLogsStability().String(), + "logs-to-metrics": con.LogsToMetricsStability().String(), + "logs-to-traces": con.LogsToTracesStability().String(), - "metrics-to-logs": factories.Connectors[con].MetricsToLogsStability().String(), - "metrics-to-metrics": factories.Connectors[con].MetricsToMetricsStability().String(), - "metrics-to-traces": factories.Connectors[con].MetricsToTracesStability().String(), + "metrics-to-logs": con.MetricsToLogsStability().String(), + "metrics-to-metrics": con.MetricsToMetricsStability().String(), + "metrics-to-traces": con.MetricsToTracesStability().String(), - "traces-to-logs": factories.Connectors[con].TracesToLogsStability().String(), - "traces-to-metrics": factories.Connectors[con].TracesToMetricsStability().String(), - "traces-to-traces": factories.Connectors[con].TracesToTracesStability().String(), + "traces-to-logs": con.TracesToLogsStability().String(), + "traces-to-metrics": con.TracesToMetricsStability().String(), + "traces-to-traces": con.TracesToTracesStability().String(), }, }) } - for ext := range factories.Extensions { + for _, ext := range sortFactoriesByType[extension.Factory](factories.Extensions) { components.Extensions = append(components.Extensions, componentWithStability{ - Name: ext, + Name: ext.Type(), Stability: map[string]string{ - "extension": factories.Extensions[ext].ExtensionStability().String(), + "extension": ext.ExtensionStability().String(), }, }) } - for prs := range factories.Processors { + for _, prs := range sortFactoriesByType[processor.Factory](factories.Processors) { components.Processors = append(components.Processors, componentWithStability{ - Name: prs, + Name: prs.Type(), Stability: map[string]string{ - "logs": factories.Processors[prs].LogsProcessorStability().String(), - "metrics": factories.Processors[prs].MetricsProcessorStability().String(), - "traces": factories.Processors[prs].TracesProcessorStability().String(), + "logs": prs.LogsProcessorStability().String(), + "metrics": prs.MetricsProcessorStability().String(), + "traces": prs.TracesProcessorStability().String(), }, }) } - for rcv := range factories.Receivers { + for _, rcv := range sortFactoriesByType[receiver.Factory](factories.Receivers) { components.Receivers = append(components.Receivers, componentWithStability{ - Name: rcv, + Name: rcv.Type(), Stability: map[string]string{ - "logs": factories.Receivers[rcv].LogsReceiverStability().String(), - "metrics": factories.Receivers[rcv].MetricsReceiverStability().String(), - "traces": factories.Receivers[rcv].TracesReceiverStability().String(), + "logs": rcv.LogsReceiverStability().String(), + "metrics": rcv.MetricsReceiverStability().String(), + "traces": rcv.TracesReceiverStability().String(), }, }) } - for exp := range factories.Exporters { + for _, exp := range sortFactoriesByType[exporter.Factory](factories.Exporters) { components.Exporters = append(components.Exporters, componentWithStability{ - Name: exp, + Name: exp.Type(), Stability: map[string]string{ - "logs": factories.Exporters[exp].LogsExporterStability().String(), - "metrics": factories.Exporters[exp].MetricsExporterStability().String(), - "traces": factories.Exporters[exp].TracesExporterStability().String(), + "logs": exp.LogsExporterStability().String(), + "metrics": exp.MetricsExporterStability().String(), + "traces": exp.TracesExporterStability().String(), }, }) } @@ -107,3 +113,24 @@ func newComponentsCommand(set CollectorSettings) *cobra.Command { }, } } + +func sortFactoriesByType[T component.Factory](factories map[component.Type]T) []T { + // Gather component types (factories map keys) + componentTypes := make([]component.Type, 0, len(factories)) + for componentType := range factories { + componentTypes = append(componentTypes, componentType) + } + + // Sort component types as strings + sort.Slice(componentTypes, func(i, j int) bool { + return componentTypes[i].String() < componentTypes[j].String() + }) + + // Build and return list of factories, sorted by component types + sortedFactories := make([]T, 0, len(factories)) + for _, componentType := range componentTypes { + sortedFactories = append(sortedFactories, factories[componentType]) + } + + return sortedFactories +} diff --git a/otelcol/factories_test.go b/otelcol/factories_test.go index 1e6d0b34a06..965ea91844b 100644 --- a/otelcol/factories_test.go +++ b/otelcol/factories_test.go @@ -4,6 +4,7 @@ package otelcol import ( + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/exporter" @@ -28,7 +29,7 @@ func nopFactories() (Factories, error) { return Factories{}, err } - if factories.Receivers, err = receiver.MakeFactoryMap(receivertest.NewNopFactory(), receivertest.NewNopFactory(receivertest.WithoutTraces())); err != nil { + if factories.Receivers, err = receiver.MakeFactoryMap(receivertest.NewNopFactory(), receivertest.NewNopFactoryForType(component.DataTypeLogs)); err != nil { return Factories{}, err } diff --git a/otelcol/testdata/otelcol-invalid-receiver-type.yaml b/otelcol/testdata/otelcol-invalid-receiver-type.yaml index 0a9c071248c..5837810fcca 100644 --- a/otelcol/testdata/otelcol-invalid-receiver-type.yaml +++ b/otelcol/testdata/otelcol-invalid-receiver-type.yaml @@ -1,5 +1,5 @@ receivers: - nop_notraces: + nop_logs: processors: nop: @@ -13,6 +13,6 @@ service: address: localhost:8888 pipelines: traces: - receivers: [nop_notraces] + receivers: [nop_logs] processors: [nop] exporters: [nop] diff --git a/receiver/receivertest/nop_receiver.go b/receiver/receivertest/nop_receiver.go index d3583a4e0ed..e9cec06ca1b 100644 --- a/receiver/receivertest/nop_receiver.go +++ b/receiver/receivertest/nop_receiver.go @@ -25,70 +25,36 @@ func NewNopCreateSettings() receiver.CreateSettings { } } -// NewNopFactory returns a receiver.Factory that constructs nop receivers. -func NewNopFactory(opts ...NopOption) receiver.Factory { - cfg := defaultNopConfig() - for _, opt := range opts { - opt(cfg) - } - - factoryOpts := make([]receiver.FactoryOption, 0) - componentType := defaultComponentType.String() - if cfg.withTraces { - factoryOpts = append(factoryOpts, receiver.WithTraces(createTraces, component.StabilityLevelStable)) - } else { - componentType += "_notraces" - } - if cfg.withMetrics { - factoryOpts = append(factoryOpts, receiver.WithMetrics(createMetrics, component.StabilityLevelStable)) - } else { - componentType += "_nometrics" - } - if cfg.withLogs { - factoryOpts = append(factoryOpts, receiver.WithLogs(createLogs, component.StabilityLevelStable)) - } else { - componentType += "_nologs" - } - - return receiver.NewFactory(component.MustNewType(componentType), func() component.Config { return cfg }, factoryOpts...) -} - -type nopConfig struct { - withTraces bool - withMetrics bool - withLogs bool +// NewNopFactory returns a receiver.Factory that constructs nop receivers supporting all data types. +func NewNopFactory() receiver.Factory { + return receiver.NewFactory( + defaultComponentType, + func() component.Config { return &nopConfig{} }, + receiver.WithTraces(createTraces, component.StabilityLevelStable), + receiver.WithMetrics(createMetrics, component.StabilityLevelStable), + receiver.WithLogs(createLogs, component.StabilityLevelStable)) } -func defaultNopConfig() *nopConfig { - return &nopConfig{ - withTraces: true, - withMetrics: true, - withLogs: true, +// NewNopFactoryForType returns a receiver.Factory that constructs nop receivers supporting only the +// given data type. +func NewNopFactoryForType(dataType component.DataType) receiver.Factory { + var factoryOpt receiver.FactoryOption + switch dataType { + case component.DataTypeTraces: + factoryOpt = receiver.WithTraces(createTraces, component.StabilityLevelStable) + case component.DataTypeMetrics: + factoryOpt = receiver.WithMetrics(createMetrics, component.StabilityLevelStable) + case component.DataTypeLogs: + factoryOpt = receiver.WithLogs(createLogs, component.StabilityLevelStable) + default: + panic("unsupported data type for creating nop receiver factory: " + dataType.String()) } -} - -type NopOption func(*nopConfig) - -// WithoutTraces creates a NopReceiver that cannot produce traces. -func WithoutTraces() NopOption { - return func(c *nopConfig) { - c.withTraces = false - } -} -// WithoutMetrics creates a NopReceiver that cannot produce metrics. -func WithoutMetrics() NopOption { - return func(c *nopConfig) { - c.withMetrics = false - } + componentType := component.MustNewType(defaultComponentType.String() + "_" + dataType.String()) + return receiver.NewFactory(componentType, func() component.Config { return &nopConfig{} }, factoryOpt) } -// WithoutLogs creates a NopReceiver that cannot produce logs. -func WithoutLogs() NopOption { - return func(c *nopConfig) { - c.withLogs = false - } -} +type nopConfig struct{} func createTraces(context.Context, receiver.CreateSettings, component.Config, consumer.Traces) (receiver.Traces, error) { return nopInstance, nil From ef47aa53ffd0804ef420b8f05e7772bad495a912 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Mon, 25 Mar 2024 15:52:56 -0700 Subject: [PATCH 19/22] Run make fmt --- otelcol/command_components.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/otelcol/command_components.go b/otelcol/command_components.go index ced647cb1d0..077b1a312d8 100644 --- a/otelcol/command_components.go +++ b/otelcol/command_components.go @@ -5,12 +5,13 @@ package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "fmt" + "sort" + "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/receiver" - "sort" "github.com/spf13/cobra" "gopkg.in/yaml.v3" From 382fcaed8efd51a8802792689efb8f13a7275a46 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 9 Apr 2024 11:35:07 +0530 Subject: [PATCH 20/22] Update test --- otelcol/testdata/components-output.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/otelcol/testdata/components-output.yaml b/otelcol/testdata/components-output.yaml index bfac28484ec..929ae01945b 100644 --- a/otelcol/testdata/components-output.yaml +++ b/otelcol/testdata/components-output.yaml @@ -8,6 +8,11 @@ receivers: logs: Stable metrics: Stable traces: Stable + - name: nop_logs + stability: + logs: Stable + metrics: Undefined + traces: Undefined processors: - name: nop stability: From 4e4f31bde026659b9b3d9a5a29c578bcabc02348 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 9 Apr 2024 11:42:00 +0530 Subject: [PATCH 21/22] Fixing linting error with import groups --- otelcol/command_components.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/otelcol/command_components.go b/otelcol/command_components.go index 077b1a312d8..fde9755cfad 100644 --- a/otelcol/command_components.go +++ b/otelcol/command_components.go @@ -7,6 +7,7 @@ import ( "fmt" "sort" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/extension" @@ -15,8 +16,6 @@ import ( "github.com/spf13/cobra" "gopkg.in/yaml.v3" - - "go.opentelemetry.io/collector/component" ) type componentWithStability struct { From 9ba6c10fc4c2a1769c31330a3ff07f535597da8b Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 9 Apr 2024 11:48:31 +0530 Subject: [PATCH 22/22] Try reordering imports --- otelcol/command_components.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/otelcol/command_components.go b/otelcol/command_components.go index fde9755cfad..da13d6779a7 100644 --- a/otelcol/command_components.go +++ b/otelcol/command_components.go @@ -7,15 +7,15 @@ import ( "fmt" "sort" + "github.com/spf13/cobra" + "gopkg.in/yaml.v3" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/receiver" - - "github.com/spf13/cobra" - "gopkg.in/yaml.v3" ) type componentWithStability struct {