diff --git a/otelcol/unmarshaler.go b/otelcol/unmarshaler.go index ed97d975ef..d38e140b06 100644 --- a/otelcol/unmarshaler.go +++ b/otelcol/unmarshaler.go @@ -27,11 +27,9 @@ type configSettings struct { // unmarshal the configSettings from a confmap.Conf. // After the config is unmarshalled, `Validate()` must be called to validate. func unmarshal(v *confmap.Conf, factories Factories) (*configSettings, error) { - // TODO remove these params once SDK and resource creation are encapsulated - // within the otelconftelemetry factory. They are not used when creating - // the default config. + // TODO: inject the telemetry factory through factories, once available. // See https://github.com/open-telemetry/opentelemetry-collector/issues/4970 - telFactory := otelconftelemetry.NewFactory(nil, nil) + telFactory := otelconftelemetry.NewFactory() defaultTelConfig := *telFactory.CreateDefaultConfig().(*otelconftelemetry.Config) // Unmarshal top level sections and validate. diff --git a/service/config_test.go b/service/config_test.go index 334f79fb41..e9fffd02b2 100644 --- a/service/config_test.go +++ b/service/config_test.go @@ -79,7 +79,7 @@ func TestConfigValidate(t *testing.T) { } func TestConfmapMarshalConfig(t *testing.T) { - telFactory := otelconftelemetry.NewFactory(nil, nil) + telFactory := otelconftelemetry.NewFactory() defaultTelConfig := *telFactory.CreateDefaultConfig().(*otelconftelemetry.Config) conf := confmap.New() diff --git a/service/service.go b/service/service.go index caec6440a1..38c43caf8d 100644 --- a/service/service.go +++ b/service/service.go @@ -13,9 +13,7 @@ import ( config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric" noopmetric "go.opentelemetry.io/otel/metric/noop" - sdkresource "go.opentelemetry.io/otel/sdk/resource" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.uber.org/multierr" "go.uber.org/zap" @@ -37,7 +35,6 @@ import ( "go.opentelemetry.io/collector/service/internal/graph" "go.opentelemetry.io/collector/service/internal/moduleinfo" "go.opentelemetry.io/collector/service/internal/proctelemetry" - "go.opentelemetry.io/collector/service/internal/resource" "go.opentelemetry.io/collector/service/internal/status" "go.opentelemetry.io/collector/service/telemetry" "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" @@ -101,11 +98,11 @@ type Settings struct { // Service represents the implementation of a component.Host. type Service struct { - buildInfo component.BuildInfo - telemetrySettings component.TelemetrySettings - host *graph.Host - collectorConf *confmap.Conf - sdk *config.SDK + buildInfo component.BuildInfo + telemetrySettings component.TelemetrySettings + host *graph.Host + collectorConf *confmap.Conf + telemetryProviders telemetry.Providers } // New creates a new Service, its telemetry, and Components. @@ -126,39 +123,31 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) { collectorConf: set.CollectorConf, } - // Fetch data for internal telemetry like instance id and sdk version to provide for internal telemetry. - res := resource.New(set.BuildInfo, cfg.Telemetry.Resource) - pcommonRes := pdataFromSdk(res) - mpConfig := &cfg.Telemetry.Metrics.MeterProvider if mpConfig.Views == nil { mpConfig.Views = configureViews(cfg.Telemetry.Metrics.Level) } - sdk, err := otelconftelemetry.NewSDK(ctx, &cfg.Telemetry, res) - if err != nil { - return nil, fmt.Errorf("failed to create SDK: %w", err) - } - srv.sdk = sdk - defer func() { - if err != nil { - err = multierr.Append(err, sdk.Shutdown(ctx)) - } - }() - - telFactory := otelconftelemetry.NewFactory(sdk, res) + telFactory := otelconftelemetry.NewFactory() telset := telemetry.Settings{ BuildInfo: set.BuildInfo, ZapOptions: set.LoggingOptions, } - logger, loggerProvider, err := telFactory.CreateLogger(ctx, telset, &cfg.Telemetry) + telProviders, err := telFactory.CreateProviders(ctx, telset, &cfg.Telemetry) if err != nil { - return nil, fmt.Errorf("failed to create logger: %w", err) + return nil, fmt.Errorf("failed to create telemetry providers: %w", err) } + srv.telemetryProviders = telProviders + defer func() { + if err != nil { + err = multierr.Append(err, telProviders.Shutdown(ctx)) + } + }() // Use initialized logger to handle any subsequent errors // https://github.com/open-telemetry/opentelemetry-collector/pull/13081 + logger := telProviders.Logger() defer func() { if err != nil { logger.Error("error found during service initialization", zap.Error(err)) @@ -168,6 +157,7 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) { // Wrap the zap.Logger with componentattribute so scope attributes // can be added and removed dynamically, and tee logs to the // LoggerProvider. + loggerProvider := telProviders.LoggerProvider() logger = logger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core { core = componentattribute.NewConsoleCoreWithAttributes(core, attribute.NewSet()) core = componentattribute.NewOTelTeeCoreWithAttributes( @@ -179,23 +169,11 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) { return core })) - tracerProvider, err := telFactory.CreateTracerProvider(ctx, telset, &cfg.Telemetry) - if err != nil { - return nil, fmt.Errorf("failed to create tracer provider: %w", err) - } - - logger.Info("Setting up own telemetry...") - - mp, err := telFactory.CreateMeterProvider(ctx, telset, &cfg.Telemetry) - if err != nil { - return nil, fmt.Errorf("failed to create meter provider: %w", err) - } srv.telemetrySettings = component.TelemetrySettings{ Logger: logger, - MeterProvider: mp, - TracerProvider: tracerProvider, - // Construct telemetry attributes from build info and config's resource attributes. - Resource: pcommonRes, + MeterProvider: telProviders.MeterProvider(), + TracerProvider: telProviders.TracerProvider(), + Resource: telProviders.Resource(), } srv.host.Reporter = status.NewReporter(srv.host.NotifyComponentStatusChange, func(err error) { if errors.Is(err, status.ErrStatusNotReady) { @@ -220,25 +198,9 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) { return nil, fmt.Errorf("failed to register process metrics: %w", err) } } - - logsAboutMeterProvider(logger, cfg.Telemetry.Metrics, mp) - return srv, nil } -func logsAboutMeterProvider(logger *zap.Logger, cfg otelconftelemetry.MetricsConfig, mp metric.MeterProvider) { - if cfg.Level == configtelemetry.LevelNone || len(cfg.Readers) == 0 { - logger.Info("Skipped telemetry setup.") - return - } - - if lmp, ok := mp.(interface { - LogAboutServers(logger *zap.Logger, cfg otelconftelemetry.MetricsConfig) - }); ok { - lmp.LogAboutServers(logger, cfg) - } -} - // 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. @@ -299,8 +261,8 @@ func (srv *Service) Shutdown(ctx context.Context) error { srv.telemetrySettings.Logger.Info("Shutdown complete.") - if err := srv.sdk.Shutdown(ctx); err != nil { - errs = multierr.Append(errs, fmt.Errorf("failed to shutdown telemetry: %w", err)) + if err := srv.telemetryProviders.Shutdown(ctx); err != nil { + errs = multierr.Append(errs, fmt.Errorf("failed to shutdown telemetry providers: %w", err)) } return errs @@ -344,17 +306,6 @@ func (srv *Service) Logger() *zap.Logger { return srv.telemetrySettings.Logger } -func pdataFromSdk(res *sdkresource.Resource) pcommon.Resource { - // pcommon.NewResource is the best way to generate a new resource currently and is safe to use outside of tests. - // Because the resource is signal agnostic, and we need a net new resource, not an existing one, this is the only - // method of creating it without exposing internal packages. - pcommonRes := pcommon.NewResource() - for _, keyValue := range res.Attributes() { - pcommonRes.Attributes().PutStr(string(keyValue.Key), keyValue.Value.AsString()) - } - return pcommonRes -} - func dropViewOption(selector *config.ViewSelector) config.View { return config.View{ Selector: selector, diff --git a/service/telemetry/otelconftelemetry/config_test.go b/service/telemetry/otelconftelemetry/config_test.go index ab0bc28638..8c1fce16ef 100644 --- a/service/telemetry/otelconftelemetry/config_test.go +++ b/service/telemetry/otelconftelemetry/config_test.go @@ -22,12 +22,12 @@ import ( func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct( - NewFactory(nil, nil).CreateDefaultConfig(), + NewFactory().CreateDefaultConfig(), )) } func TestUnmarshalDefaultConfig(t *testing.T) { - factory := NewFactory(nil, nil) + factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, confmap.New().Unmarshal(&cfg)) assert.Equal(t, factory.CreateDefaultConfig(), cfg) diff --git a/service/telemetry/otelconftelemetry/factory.go b/service/telemetry/otelconftelemetry/factory.go index b5b7d86d3e..35fb53d9ed 100644 --- a/service/telemetry/otelconftelemetry/factory.go +++ b/service/telemetry/otelconftelemetry/factory.go @@ -8,11 +8,6 @@ import ( "time" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" - "go.opentelemetry.io/otel/log" - "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/sdk/resource" - "go.opentelemetry.io/otel/trace" - "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/component" @@ -28,7 +23,7 @@ var useLocalHostAsDefaultMetricsAddressFeatureGate = featuregate.GlobalRegistry( featuregate.WithRegisterDescription("controls whether default Prometheus metrics server use localhost as the default host for their endpoints"), ) -// Factory is factory interface for telemetry. +// Factory is factory interface for telemetry providers. // This interface cannot be directly implemented. Implementations must // use the NewFactory to implement it. // @@ -36,17 +31,10 @@ var useLocalHostAsDefaultMetricsAddressFeatureGate = featuregate.GlobalRegistry( // See https://github.com/open-telemetry/opentelemetry-collector/issues/4970 type Factory interface { // CreateDefaultConfig creates the default configuration for the telemetry. - // TODO: Should we just inherit from component.Factory? CreateDefaultConfig() component.Config - // CreateLogger creates a logger. - CreateLogger(context.Context, telemetry.Settings, component.Config) (*zap.Logger, log.LoggerProvider, error) - - // CreateTracerProvider creates a TracerProvider. - CreateTracerProvider(context.Context, telemetry.Settings, component.Config) (trace.TracerProvider, error) - - // CreateMeterProvider creates a MeterProvider. - CreateMeterProvider(context.Context, telemetry.Settings, component.Config) (metric.MeterProvider, error) + // CreateProviders creates telemetry providers. + CreateProviders(context.Context, telemetry.Settings, component.Config) (telemetry.Providers, error) // unexportedFactoryFunc is used to prevent external implementations of Factory. unexportedFactoryFunc() @@ -56,24 +44,8 @@ type Factory interface { // // NOTE This API is experimental and will change soon - use at your own risk. // See https://github.com/open-telemetry/opentelemetry-collector/issues/4970 -// -// TODO remove the parameters once the factory is fully self-contained -// and is responsible for creating the SDK and resource itself. -func NewFactory(sdk *config.SDK, res *resource.Resource) Factory { - return newFactory(createDefaultConfig, - withLogger(func(_ context.Context, set telemetry.Settings, cfg component.Config) (*zap.Logger, log.LoggerProvider, error) { - c := *cfg.(*Config) - return newLogger(set, c, sdk, res) - }), - withTracerProvider(func(_ context.Context, _ telemetry.Settings, cfg component.Config) (trace.TracerProvider, error) { - c := *cfg.(*Config) - return newTracerProvider(c, sdk) - }), - withMeterProvider(func(_ context.Context, _ telemetry.Settings, cfg component.Config) (metric.MeterProvider, error) { - c := *cfg.(*Config) - return newMeterProvider(c, sdk) - }), - ) +func NewFactory() Factory { + return newFactory(createDefaultConfig, createProviders) } func createDefaultConfig() component.Config { diff --git a/service/telemetry/otelconftelemetry/factory_impl.go b/service/telemetry/otelconftelemetry/factory_impl.go index bcbd7e182e..8461125ece 100644 --- a/service/telemetry/otelconftelemetry/factory_impl.go +++ b/service/telemetry/otelconftelemetry/factory_impl.go @@ -6,14 +6,6 @@ package otelconftelemetry // import "go.opentelemetry.io/collector/service/telem import ( "context" - "go.opentelemetry.io/otel/log" - lognoop "go.opentelemetry.io/otel/log/noop" - "go.opentelemetry.io/otel/metric" - metricnoop "go.opentelemetry.io/otel/metric/noop" - "go.opentelemetry.io/otel/trace" - tracenoop "go.opentelemetry.io/otel/trace/noop" - "go.uber.org/zap" - "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/service/telemetry" ) @@ -38,72 +30,27 @@ var _ Factory = (*factory)(nil) // Factory is the implementation of Factory. type factory struct { createDefaultConfig component.CreateDefaultConfigFunc - createLoggerFunc - createTracerProviderFunc - createMeterProviderFunc + createProvidersFunc } func (f *factory) CreateDefaultConfig() component.Config { return f.createDefaultConfig() } -// createLoggerFunc is the equivalent of Factory.CreateLogger. -type createLoggerFunc func(context.Context, telemetry.Settings, component.Config) (*zap.Logger, log.LoggerProvider, error) +// createProvidersFunc is the equivalent of Factory.CreateProviders. +type createProvidersFunc func(context.Context, telemetry.Settings, component.Config) (telemetry.Providers, error) -// withLogger overrides the default no-op logger. -func withLogger(createLogger createLoggerFunc) factoryOption { - return factoryOptionFunc(func(o *factory) { - o.createLoggerFunc = createLogger - }) -} - -func (f *factory) CreateLogger(ctx context.Context, set telemetry.Settings, cfg component.Config) (*zap.Logger, log.LoggerProvider, error) { - if f.createLoggerFunc == nil { - return zap.NewNop(), lognoop.NewLoggerProvider(), nil - } - return f.createLoggerFunc(ctx, set, cfg) -} - -// createTracerProviderFunc is the equivalent of Factory.CreateTracerProvider. -type createTracerProviderFunc func(context.Context, telemetry.Settings, component.Config) (trace.TracerProvider, error) - -// withTracerProvider overrides the default no-op tracer provider. -func withTracerProvider(createTracerProvider createTracerProviderFunc) factoryOption { - return factoryOptionFunc(func(o *factory) { - o.createTracerProviderFunc = createTracerProvider - }) -} - -func (f *factory) CreateTracerProvider(ctx context.Context, set telemetry.Settings, cfg component.Config) (trace.TracerProvider, error) { - if f.createTracerProviderFunc == nil { - return tracenoop.NewTracerProvider(), nil - } - return f.createTracerProviderFunc(ctx, set, cfg) -} - -// createMeterProviderFunc is the equivalent of Factory.CreateMeterProvider. -type createMeterProviderFunc func(context.Context, telemetry.Settings, component.Config) (metric.MeterProvider, error) - -// withMeterProvider overrides the default no-op meter provider. -func withMeterProvider(createMeterProvider createMeterProviderFunc) factoryOption { - return factoryOptionFunc(func(o *factory) { - o.createMeterProviderFunc = createMeterProvider - }) -} - -func (f *factory) CreateMeterProvider(ctx context.Context, set telemetry.Settings, cfg component.Config) (metric.MeterProvider, error) { - if f.createMeterProviderFunc == nil { - return metricnoop.NewMeterProvider(), nil - } - return f.createMeterProviderFunc(ctx, set, cfg) +func (f *factory) CreateProviders(ctx context.Context, set telemetry.Settings, cfg component.Config) (telemetry.Providers, error) { + return f.createProvidersFunc(ctx, set, cfg) } func (f *factory) unexportedFactoryFunc() {} // newFactory returns a new Factory. -func newFactory(createDefaultConfig component.CreateDefaultConfigFunc, options ...factoryOption) Factory { +func newFactory(createDefaultConfig component.CreateDefaultConfigFunc, createProviders createProvidersFunc, options ...factoryOption) Factory { f := &factory{ createDefaultConfig: createDefaultConfig, + createProvidersFunc: createProviders, } for _, op := range options { op.applyTelemetryFactoryOption(f) diff --git a/service/telemetry/otelconftelemetry/factory_test.go b/service/telemetry/otelconftelemetry/factory_test.go index 435b6bb6a2..7c991df9ed 100644 --- a/service/telemetry/otelconftelemetry/factory_test.go +++ b/service/telemetry/otelconftelemetry/factory_test.go @@ -4,19 +4,13 @@ package otelconftelemetry import ( - "context" "strconv" "testing" - "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - config "go.opentelemetry.io/contrib/otelconf/v0.3.0" - "go.uber.org/zap/zapcore" - "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/featuregate" - "go.opentelemetry.io/collector/service/telemetry" ) func TestDefaultConfig(t *testing.T) { @@ -42,133 +36,10 @@ func TestDefaultConfig(t *testing.T) { // Restore previous value. require.NoError(t, featuregate.GlobalRegistry().Set(useLocalHostAsDefaultMetricsAddressFeatureGate.ID(), prev)) }() - cfg := NewFactory(nil, nil).CreateDefaultConfig() + cfg := NewFactory().CreateDefaultConfig() require.Len(t, cfg.(*Config).Metrics.Readers, 1) assert.Equal(t, tt.expected, *cfg.(*Config).Metrics.Readers[0].Pull.Exporter.Prometheus.Host) assert.Equal(t, 8888, *cfg.(*Config).Metrics.Readers[0].Pull.Exporter.Prometheus.Port) }) } } - -func TestTelemetryConfiguration(t *testing.T) { - tests := []struct { - name string - cfg *Config - success bool - }{ - { - name: "Valid config", - cfg: &Config{ - Logs: LogsConfig{ - Level: zapcore.DebugLevel, - Encoding: "console", - }, - Metrics: MetricsConfig{ - Level: configtelemetry.LevelBasic, - MeterProvider: config.MeterProvider{ - Readers: []config.MetricReader{ - { - Pull: &config.PullMetricReader{Exporter: config.PullMetricExporter{Prometheus: &config.Prometheus{ - Host: ptr("127.0.0.1"), - Port: ptr(3333), - }}}, - }, - }, - }, - }, - }, - success: true, - }, - { - name: "Invalid config", - cfg: &Config{ - Logs: LogsConfig{ - Level: zapcore.DebugLevel, - }, - Metrics: MetricsConfig{ - Level: configtelemetry.LevelBasic, - MeterProvider: config.MeterProvider{ - Readers: []config.MetricReader{ - { - Pull: &config.PullMetricReader{Exporter: config.PullMetricExporter{Prometheus: &config.Prometheus{ - Host: ptr("127.0.0.1"), - Port: ptr(3333), - }}}, - }, - }, - }, - }, - }, - success: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - f := NewFactory(nil, nil) - set := telemetry.Settings{} - logger, _, err := f.CreateLogger(context.Background(), set, tt.cfg) - if tt.success { - require.NoError(t, err) - assert.NotNil(t, logger) - } else { - require.Error(t, err) - assert.Nil(t, logger) - } - }) - } -} - -func TestSampledLogger(t *testing.T) { - tests := []struct { - name string - cfg *Config - }{ - { - name: "Default sampling", - cfg: &Config{ - Logs: LogsConfig{ - Encoding: "console", - }, - }, - }, - { - name: "Custom sampling", - cfg: &Config{ - Logs: LogsConfig{ - Level: zapcore.DebugLevel, - Encoding: "console", - Sampling: &LogsSamplingConfig{ - Enabled: true, - Tick: 1 * time.Second, - Initial: 100, - Thereafter: 100, - }, - }, - }, - }, - { - name: "Disable sampling", - cfg: &Config{ - Logs: LogsConfig{ - Level: zapcore.DebugLevel, - Encoding: "console", - Sampling: &LogsSamplingConfig{ - Enabled: false, - }, - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - f := NewFactory(nil, nil) - ctx := context.Background() - set := telemetry.Settings{} - logger, _, err := f.CreateLogger(ctx, set, tt.cfg) - require.NoError(t, err) - assert.NotNil(t, logger) - }) - } -} diff --git a/service/telemetry/otelconftelemetry/logger.go b/service/telemetry/otelconftelemetry/logger.go index c4077c7901..56d22c9422 100644 --- a/service/telemetry/otelconftelemetry/logger.go +++ b/service/telemetry/otelconftelemetry/logger.go @@ -6,7 +6,6 @@ package otelconftelemetry // import "go.opentelemetry.io/collector/service/telem import ( config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/otel/log" - "go.opentelemetry.io/otel/log/noop" "go.opentelemetry.io/otel/sdk/resource" "go.uber.org/zap" "go.uber.org/zap/zapcore" @@ -15,7 +14,7 @@ import ( ) // newLogger creates a Logger and a LoggerProvider from Config. -func newLogger(set telemetry.Settings, cfg Config, sdk *config.SDK, res *resource.Resource) (*zap.Logger, log.LoggerProvider, error) { +func newLogger(set telemetry.Settings, cfg *Config, sdk *config.SDK, res *resource.Resource) (*zap.Logger, log.LoggerProvider, error) { // Copied from NewProductionConfig. ec := zap.NewProductionEncoderConfig() ec.EncodeTime = zapcore.ISO8601TimeEncoder @@ -71,11 +70,6 @@ func newLogger(set telemetry.Settings, cfg Config, sdk *config.SDK, res *resourc })) } - var lp log.LoggerProvider - if sdk != nil { - lp = sdk.LoggerProvider() - } else { - lp = noop.NewLoggerProvider() - } + lp := sdk.LoggerProvider() return logger, lp, nil } diff --git a/service/telemetry/otelconftelemetry/logger_test.go b/service/telemetry/otelconftelemetry/logger_test.go index b6404f1146..b921b12453 100644 --- a/service/telemetry/otelconftelemetry/logger_test.go +++ b/service/telemetry/otelconftelemetry/logger_test.go @@ -16,15 +16,11 @@ import ( "github.com/stretchr/testify/require" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/otel/log" - sdkresource "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.18.0" - "go.uber.org/zap" "go.uber.org/zap/zapcore" - "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/plog/plogotlp" - "go.opentelemetry.io/collector/service/internal/resource" "go.opentelemetry.io/collector/service/telemetry" ) @@ -107,17 +103,14 @@ func TestNewLogger(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { buildInfo := component.BuildInfo{} - sdk, err := NewSDK(context.Background(), &tt.cfg, resource.New(buildInfo, nil)) - require.NoError(t, err) - defer func() { - require.NoError(t, sdk.Shutdown(context.Background())) - }() + factory := NewFactory() - _, _, err = newLogger(telemetry.Settings{}, tt.cfg, sdk, nil) + providers, err := factory.CreateProviders(context.Background(), telemetry.Settings{BuildInfo: buildInfo}, &tt.cfg) if tt.wantErr != nil { require.ErrorContains(t, err, tt.wantErr.Error()) } else { require.NoError(t, err) + require.NoError(t, providers.Shutdown(context.Background())) } }) } @@ -193,35 +186,26 @@ func TestNewLoggerWithResource(t *testing.T) { name: "resource with no attributes", buildInfo: component.BuildInfo{}, resourceConfig: nil, - wantFields: nil, + wantFields: map[string]string{ + // A random UUID is injected for service.instance.id by default + string(semconv.ServiceInstanceIDKey): "", // Just check presence + }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - observerCore, observedLogs := observer.New(zap.InfoLevel) - - set := telemetry.Settings{ - ZapOptions: []zap.Option{ - zap.WrapCore(func(core zapcore.Core) zapcore.Core { - return zapcore.NewTee(core, observerCore) - }), - }, - } - - var res *sdkresource.Resource - if tt.wantFields != nil { - res = resource.New(tt.buildInfo, tt.resourceConfig) - } - + set := telemetry.Settings{BuildInfo: tt.buildInfo} cfg := Config{ Logs: LogsConfig{ Level: zapcore.InfoLevel, Encoding: "json", }, + Resource: tt.resourceConfig, } - mylogger, _, _ := newLogger(set, cfg, nil, res) + tel, observedLogs := newTelemetryProviders(t, set, &cfg) + mylogger := tel.Logger() mylogger.Info("Test log message") require.Len(t, observedLogs.All(), 1) @@ -317,22 +301,15 @@ func newOTLPLoggerProvider(t *testing.T, level zapcore.Level, handler http.Handl Encoding: "json", Processors: processors, }, + Resource: map[string]*string{ + string(semconv.ServiceNameKey): ptr(service), + string(semconv.ServiceVersionKey): ptr(version), + testAttribute: ptr(testValue), + }, } - buildInfo := component.BuildInfo{} - res := resource.New(buildInfo, map[string]*string{ - string(semconv.ServiceNameKey): ptr(service), - string(semconv.ServiceVersionKey): ptr(version), - testAttribute: ptr(testValue), - }) - sdk, err := NewSDK(context.Background(), &cfg, res) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, sdk.Shutdown(context.Background())) - }) - - _, lp, err := newLogger(telemetry.Settings{}, cfg, sdk, res) - require.NoError(t, err) + tel, _ := newTelemetryProviders(t, telemetry.Settings{}, &cfg) + lp := tel.LoggerProvider() require.NotNil(t, lp) return lp } diff --git a/service/telemetry/otelconftelemetry/metrics.go b/service/telemetry/otelconftelemetry/metrics.go deleted file mode 100644 index 60369fa48f..0000000000 --- a/service/telemetry/otelconftelemetry/metrics.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" - -import ( - "errors" - - config "go.opentelemetry.io/contrib/otelconf/v0.3.0" - "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/noop" - - "go.opentelemetry.io/collector/config/configtelemetry" -) - -// newMeterProvider creates a new MeterProvider from Config. -func newMeterProvider(cfg Config, sdk *config.SDK) (metric.MeterProvider, error) { - if cfg.Metrics.Level == configtelemetry.LevelNone || len(cfg.Metrics.Readers) == 0 { - return noop.NewMeterProvider(), nil - } - - if sdk != nil { - return sdk.MeterProvider(), nil - } - return nil, errors.New("no sdk set") -} diff --git a/service/telemetry/otelconftelemetry/metrics_test.go b/service/telemetry/otelconftelemetry/metrics_test.go index 8deb47414b..55ba81ee40 100644 --- a/service/telemetry/otelconftelemetry/metrics_test.go +++ b/service/telemetry/otelconftelemetry/metrics_test.go @@ -19,10 +19,9 @@ import ( "go.opentelemetry.io/otel/metric" semconv "go.opentelemetry.io/otel/semconv/v1.26.0" - "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/service/internal/promtest" - "go.opentelemetry.io/collector/service/internal/resource" + "go.opentelemetry.io/collector/service/telemetry" ) const ( @@ -93,32 +92,27 @@ func TestTelemetryInit(t *testing.T) { } { prom := promtest.GetAvailableLocalAddressPrometheus(t) endpoint := fmt.Sprintf("http://%s:%d/metrics", *prom.Host, *prom.Port) - cfg := Config{ - Metrics: MetricsConfig{ - Level: configtelemetry.LevelDetailed, - MeterProvider: config.MeterProvider{ - Readers: []config.MetricReader{{ - Pull: &config.PullMetricReader{ - Exporter: config.PullMetricExporter{Prometheus: prom}, - }, - }}, - }, + + cfg := createDefaultConfig().(*Config) + cfg.Metrics = MetricsConfig{ + Level: configtelemetry.LevelDetailed, + MeterProvider: config.MeterProvider{ + Readers: []config.MetricReader{{ + Pull: &config.PullMetricReader{ + Exporter: config.PullMetricExporter{Prometheus: prom}, + }, + }}, }, } - t.Run(tt.name, func(t *testing.T) { - res := resource.New(component.BuildInfo{}, map[string]*string{ - string(semconv.ServiceNameKey): ptr("otelcol"), - string(semconv.ServiceVersionKey): ptr("latest"), - string(semconv.ServiceInstanceIDKey): ptr(testInstanceID), - }) - sdk, err := NewSDK(context.Background(), &cfg, res) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, sdk.Shutdown(context.Background())) - }) + cfg.Resource = map[string]*string{ + string(semconv.ServiceNameKey): ptr("otelcol"), + string(semconv.ServiceVersionKey): ptr("latest"), + string(semconv.ServiceInstanceIDKey): ptr(testInstanceID), + } - mp, err := newMeterProvider(cfg, sdk) - require.NoError(t, err) + t.Run(tt.name, func(t *testing.T) { + providers, _ := newTelemetryProviders(t, telemetry.Settings{}, cfg) + mp := providers.MeterProvider() createTestMetrics(t, mp) @@ -203,16 +197,14 @@ func TestTelemetryMetricsDisabled(t *testing.T) { Periodic: &config.PeriodicMetricReader{Exporter: config.PushMetricExporter{OTLP: &config.OTLPMetric{}}}, }} - res := resource.New(component.BuildInfo{}, nil) - _, err := NewSDK(context.Background(), cfg, res) - require.EqualError(t, err, "no valid metric exporter") + factory := NewFactory() + _, err := factory.CreateProviders(context.Background(), telemetry.Settings{}, cfg) + require.EqualError(t, err, "failed to create SDK: no valid metric exporter") // Setting Metrics.Level to LevelNone disables metrics, // so the invalid configuration should not cause an error. cfg.Metrics.Level = configtelemetry.LevelNone - sdk, err := NewSDK(context.Background(), cfg, res) - require.NoError(t, err) - assert.NoError(t, sdk.Shutdown(context.Background())) + _, _ = newTelemetryProviders(t, telemetry.Settings{}, cfg) } // Test that the MeterProvider implements the 'Enabled' functionality. @@ -224,15 +216,8 @@ func TestInstrumentEnabled(t *testing.T) { Pull: &config.PullMetricReader{Exporter: config.PullMetricExporter{Prometheus: prom}}, }} - sdk, err := NewSDK(context.Background(), cfg, resource.New(component.BuildInfo{}, nil)) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, sdk.Shutdown(context.Background())) - }) - require.NoError(t, err) - - meterProvider, err := newMeterProvider(*cfg, sdk) - require.NoError(t, err) + providers, _ := newTelemetryProviders(t, telemetry.Settings{}, cfg) + meterProvider := providers.MeterProvider() meter := meterProvider.Meter("go.opentelemetry.io/collector/service/telemetry") diff --git a/service/telemetry/otelconftelemetry/sdk.go b/service/telemetry/otelconftelemetry/sdk.go deleted file mode 100644 index a8288485db..0000000000 --- a/service/telemetry/otelconftelemetry/sdk.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" - -import ( - "context" - - config "go.opentelemetry.io/contrib/otelconf/v0.3.0" - "go.opentelemetry.io/otel/sdk/resource" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" - - "go.opentelemetry.io/collector/config/configtelemetry" -) - -// NewSDK creates a new OpenTelemetry SDK with the provided configuration. -func NewSDK(ctx context.Context, cfg *Config, res *resource.Resource) (*config.SDK, error) { - mpConfig := cfg.Metrics.MeterProvider - if cfg.Metrics.Level == configtelemetry.LevelNone { - mpConfig.Readers = nil - } - - var resourceAttrs []config.AttributeNameValue - for _, r := range res.Attributes() { - resourceAttrs = append(resourceAttrs, config.AttributeNameValue{ - Name: string(r.Key), Value: r.Value.AsString(), - }) - } - - sdk, err := config.NewSDK( - config.WithContext(ctx), - config.WithOpenTelemetryConfiguration( - config.OpenTelemetryConfiguration{ - LoggerProvider: &config.LoggerProvider{ - Processors: cfg.Logs.Processors, - }, - MeterProvider: &mpConfig, - TracerProvider: &cfg.Traces.TracerProvider, - Resource: &config.Resource{ - SchemaUrl: ptr(semconv.SchemaURL), - Attributes: resourceAttrs, - }, - }, - ), - ) - if err != nil { - return nil, err - } - return &sdk, nil -} diff --git a/service/telemetry/otelconftelemetry/telemetry.go b/service/telemetry/otelconftelemetry/telemetry.go new file mode 100644 index 0000000000..c9802872c3 --- /dev/null +++ b/service/telemetry/otelconftelemetry/telemetry.go @@ -0,0 +1,158 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" + +import ( + "context" + "fmt" + + config "go.opentelemetry.io/contrib/otelconf/v0.3.0" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/log" + "go.opentelemetry.io/otel/metric" + noopmetric "go.opentelemetry.io/otel/metric/noop" + sdkresource "go.opentelemetry.io/otel/sdk/resource" + semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + "go.opentelemetry.io/otel/trace" + "go.uber.org/multierr" + "go.uber.org/zap" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configtelemetry" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/service/internal/resource" + "go.opentelemetry.io/collector/service/telemetry" +) + +type otelconfTelemetry struct { + sdk *config.SDK + resource pcommon.Resource + logger *zap.Logger + loggerProvider log.LoggerProvider + meterProvider metric.MeterProvider + tracerProvider trace.TracerProvider +} + +func createProviders( + ctx context.Context, set telemetry.Settings, componentConfig component.Config, +) (_ telemetry.Providers, resultErr error) { + cfg := componentConfig.(*Config) + res := resource.New(set.BuildInfo, cfg.Resource) + sdk, err := newSDK(ctx, set, cfg, res) + if err != nil { + return nil, fmt.Errorf("failed to create SDK: %w", err) + } + defer func() { + if resultErr != nil { + resultErr = multierr.Append(resultErr, sdk.Shutdown(ctx)) + } + }() + + logger, loggerProvider, err := newLogger(set, cfg, sdk, res) + if err != nil { + return nil, fmt.Errorf("failed to create logger provider: %w", err) + } + + var meterProvider metric.MeterProvider + if cfg.Metrics.Level == configtelemetry.LevelNone { + logger.Info("Internal metrics telemetry disabled") + meterProvider = noopmetric.NewMeterProvider() + } else { + meterProvider = sdk.MeterProvider() + } + + var tracerProvider trace.TracerProvider + if cfg.Traces.Level == configtelemetry.LevelNone { + logger.Info("Internal trace telemetry disabled") + tracerProvider = &noopNoContextTracerProvider{} + } else { + propagator, err := textMapPropagatorFromConfig(cfg.Traces.Propagators) + if err != nil { + return nil, fmt.Errorf("error creating propagator: %w", err) + } + otel.SetTextMapPropagator(propagator) + tracerProvider = sdk.TracerProvider() + } + + pcommonRes := pcommon.NewResource() + for _, keyValue := range res.Attributes() { + pcommonRes.Attributes().PutStr(string(keyValue.Key), keyValue.Value.AsString()) + } + + return &otelconfTelemetry{ + sdk: sdk, + resource: pcommonRes, + logger: logger, + loggerProvider: loggerProvider, + meterProvider: meterProvider, + tracerProvider: tracerProvider, + }, nil +} + +func (t *otelconfTelemetry) Resource() pcommon.Resource { + return t.resource +} + +func (t *otelconfTelemetry) Logger() *zap.Logger { + return t.logger +} + +func (t *otelconfTelemetry) LoggerProvider() log.LoggerProvider { + return t.loggerProvider +} + +func (t *otelconfTelemetry) MeterProvider() metric.MeterProvider { + return t.meterProvider +} + +func (t *otelconfTelemetry) TracerProvider() trace.TracerProvider { + return t.tracerProvider +} + +func (t *otelconfTelemetry) Shutdown(ctx context.Context) error { + if t.sdk != nil { + err := t.sdk.Shutdown(ctx) + t.sdk = nil + if err != nil { + return fmt.Errorf("failed to shutdown SDK: %w", err) + } + } + return nil +} + +func newSDK(ctx context.Context, _ telemetry.Settings, cfg *Config, res *sdkresource.Resource) (*config.SDK, error) { + mpConfig := cfg.Metrics.MeterProvider + if cfg.Metrics.Level == configtelemetry.LevelNone { + mpConfig.Readers = nil + } + + // Merge the BuildInfo-based resource attributes with the user-defined resource attributes. + resourceAttrs := make([]config.AttributeNameValue, 0, res.Len()) + for _, r := range res.Attributes() { + resourceAttrs = append(resourceAttrs, config.AttributeNameValue{ + Name: string(r.Key), Value: r.Value.AsString(), + }) + } + + sdk, err := config.NewSDK( + config.WithContext(ctx), + config.WithOpenTelemetryConfiguration( + config.OpenTelemetryConfiguration{ + LoggerProvider: &config.LoggerProvider{ + Processors: cfg.Logs.Processors, + }, + MeterProvider: &mpConfig, + TracerProvider: &cfg.Traces.TracerProvider, + Resource: &config.Resource{ + SchemaUrl: ptr(semconv.SchemaURL), + Attributes: resourceAttrs, + }, + }, + ), + ) + if err != nil { + return nil, err + } + return &sdk, nil +} diff --git a/service/telemetry/otelconftelemetry/telemetry_test.go b/service/telemetry/otelconftelemetry/telemetry_test.go new file mode 100644 index 0000000000..7becefa07c --- /dev/null +++ b/service/telemetry/otelconftelemetry/telemetry_test.go @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package otelconftelemetry + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest/observer" + + "go.opentelemetry.io/collector/service/telemetry" +) + +func newTelemetryProviders(t *testing.T, set telemetry.Settings, cfg *Config) (telemetry.Providers, *observer.ObservedLogs) { + t.Helper() + + core, observedLogs := observer.New(zapcore.DebugLevel) + set.ZapOptions = append(set.ZapOptions, zap.WrapCore(func(zapcore.Core) zapcore.Core { return core })) + + if len(cfg.Metrics.Readers) == 1 && cfg.Metrics.Readers[0].Pull != nil && + cfg.Metrics.Readers[0].Pull.Exporter.Prometheus != nil && + cfg.Metrics.Readers[0].Pull.Exporter.Prometheus.Port != nil && + *cfg.Metrics.Readers[0].Pull.Exporter.Prometheus.Port == 8888 { + // Replace the default port with 0 to bind to an ephemeral port, + // avoiding flaky tests. + *cfg.Metrics.Readers[0].Pull.Exporter.Prometheus.Port = 0 + } + + factory := NewFactory() + providers, err := factory.CreateProviders(context.Background(), set, cfg) + require.NoError(t, err) + require.NotNil(t, providers) + t.Cleanup(func() { + assert.NoError(t, providers.Shutdown(context.Background())) + }) + return providers, observedLogs +} diff --git a/service/telemetry/otelconftelemetry/tracer.go b/service/telemetry/otelconftelemetry/tracer.go index 9625a8dbe3..ae0d3cdfae 100644 --- a/service/telemetry/otelconftelemetry/tracer.go +++ b/service/telemetry/otelconftelemetry/tracer.go @@ -7,15 +7,12 @@ import ( "context" "errors" - config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/contrib/propagators/b3" - "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/embedded" "go.opentelemetry.io/otel/trace/noop" - "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/featuregate" ) @@ -51,24 +48,6 @@ func (n *noopNoContextTracerProvider) Tracer(_ string, _ ...trace.TracerOption) return &noopNoContextTracer{} } -// newTracerProvider creates a new TracerProvider from Config. -func newTracerProvider(cfg Config, sdk *config.SDK) (trace.TracerProvider, error) { - if cfg.Traces.Level == configtelemetry.LevelNone { - return &noopNoContextTracerProvider{}, nil - } - - if tp, err := textMapPropagatorFromConfig(cfg.Traces.Propagators); err == nil { - otel.SetTextMapPropagator(tp) - } else { - return nil, err - } - - if sdk != nil { - return sdk.TracerProvider(), nil - } - return nil, errors.New("no sdk set") -} - func textMapPropagatorFromConfig(props []string) (propagation.TextMapPropagator, error) { var textMapPropagators []propagation.TextMapPropagator for _, prop := range props { diff --git a/service/telemetry/otelconftelemetry/tracer_test.go b/service/telemetry/otelconftelemetry/tracer_test.go index 5f32b0d1ec..10ef7a6361 100644 --- a/service/telemetry/otelconftelemetry/tracer_test.go +++ b/service/telemetry/otelconftelemetry/tracer_test.go @@ -20,7 +20,7 @@ import ( "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" - "go.opentelemetry.io/collector/service/internal/resource" + "go.opentelemetry.io/collector/service/telemetry" ) func TestTracerProvider(t *testing.T) { @@ -42,16 +42,9 @@ func TestTracerProvider(t *testing.T) { cfg.Traces.Processors = []config.SpanProcessor{newOTLPSimpleSpanProcessor(srv)} buildInfo := component.BuildInfo{Command: "otelcol", Version: "latest"} - sdk, err := NewSDK(context.Background(), cfg, resource.New(buildInfo, cfg.Resource)) - require.NoError(t, err) - defer func() { - assert.NoError(t, sdk.Shutdown(context.Background())) - }() - - provider, err := newTracerProvider(*cfg, sdk) - require.NoError(t, err) - require.NotNil(t, provider) + providers, _ := newTelemetryProviders(t, telemetry.Settings{BuildInfo: buildInfo}, cfg) + provider := providers.TracerProvider() tracer := provider.Tracer("test_tracer") _, span := tracer.Start(context.Background(), "test_span") span.End() @@ -73,14 +66,9 @@ func TestTelemetry_TracerProvider_Propagators(t *testing.T) { cfg.Traces.Processors = []config.SpanProcessor{newOTLPSimpleSpanProcessor(srv)} buildInfo := component.BuildInfo{Command: "otelcol", Version: "latest"} - sdk, err := NewSDK(context.Background(), cfg, resource.New(buildInfo, cfg.Resource)) - require.NoError(t, err) - defer func() { - assert.NoError(t, sdk.Shutdown(context.Background())) - }() + providers, _ := newTelemetryProviders(t, telemetry.Settings{BuildInfo: buildInfo}, cfg) - provider, err := newTracerProvider(*cfg, sdk) - require.NoError(t, err) + provider := providers.TracerProvider() propagator := otel.GetTextMapPropagator() require.NotNil(t, propagator) @@ -111,14 +99,9 @@ func TestTelemetry_TracerProviderDisabled(t *testing.T) { } buildInfo := component.BuildInfo{Command: "otelcol", Version: "latest"} - sdk, err := NewSDK(context.Background(), cfg, resource.New(buildInfo, cfg.Resource)) - require.NoError(t, err) - defer func() { - assert.NoError(t, sdk.Shutdown(context.Background())) - }() + providers, _ := newTelemetryProviders(t, telemetry.Settings{BuildInfo: buildInfo}, cfg) - provider, err := newTracerProvider(*cfg, sdk) - require.NoError(t, err) + provider := providers.TracerProvider() tracer := provider.Tracer("test_tracer") _, span := tracer.Start(context.Background(), "test_span") span.End() @@ -126,7 +109,7 @@ func TestTelemetry_TracerProviderDisabled(t *testing.T) { } t.Run("level_none", func(t *testing.T) { - cfg := &Config{} + cfg := createDefaultConfig().(*Config) cfg.Traces.Level = configtelemetry.LevelNone test(t, cfg) }) diff --git a/service/telemetry/telemetry.go b/service/telemetry/telemetry.go index 79076766a3..422ac4037e 100644 --- a/service/telemetry/telemetry.go +++ b/service/telemetry/telemetry.go @@ -4,23 +4,67 @@ package telemetry // import "go.opentelemetry.io/collector/service/telemetry" import ( + "context" + + "go.opentelemetry.io/otel/log" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/service/telemetry/internal/migration" ) -// Settings holds configuration for building Telemetry. -type Settings struct { - BuildInfo component.BuildInfo - ZapOptions []zap.Option -} - -// TODO create abstract Telemetry interface and Factory interfaces -// that are implemented by otelconftelemetry. -// See https://github.com/open-telemetry/opentelemetry-collector/issues/4970 - // NOTE TracesConfig will be removed once opentelemetry-collector-contrib // has been updated to use otelconftelemetry instead; use at your own risk. // See https://github.com/open-telemetry/opentelemetry-collector/issues/4970 type TracesConfig = migration.TracesConfigV030 + +// Providers is an interface for internal telemetry providers. +// +// NOTE this interface is experimental and may change in the future. +type Providers interface { + // Shutdown gracefully shuts down the telemetry providers. + Shutdown(context.Context) error + + // Resource returns a pcommon.Resource representing the collector. + // This may be used by components in their internal telemetry. + Resource() pcommon.Resource + + // Logger returns a zap.Logger that may be used by components to + // log their internal operations. + // + // NOTE: from the perspective of the Telemetry implementation, + // this Logger and the LoggerProvider are independent. However, + // the service package will arrange for logs written to this + // logger to be copied to the LoggerProvider. The effective + // level of the logger will be the lower of the Logger's and + // the LoggerProvider's levels. + Logger() *zap.Logger + + // LoggerProvider returns a log.LoggerProvider that may be used + // for components to log their internal operations. + LoggerProvider() log.LoggerProvider + + // MeterProvider returns a metric.MeterProvider that may be used + // by components to record metrics relating to their internal + // operations. + MeterProvider() metric.MeterProvider + + // TracerProvider returns a trace.TracerProvider that may be used + // by components to trace their internal operations. + TracerProvider() trace.TracerProvider +} + +// Settings holds configuration for building Telemetry. +type Settings struct { + // BuildInfo contains build information about the collector. + BuildInfo component.BuildInfo + + // ZapOptions contains options for creating the zap logger. + ZapOptions []zap.Option +} + +// TODO create abstract Factory interface that is implemented by otelconftelemetry. +// See https://github.com/open-telemetry/opentelemetry-collector/issues/4970