Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 4 additions & 24 deletions service/telemetry/otelconftelemetry/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry"

import (
"context"
"time"

config "go.opentelemetry.io/contrib/otelconf/v0.3.0"
Expand All @@ -23,29 +22,10 @@ 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 providers.
// This interface cannot be directly implemented. Implementations must
// use the NewFactory to implement it.
//
// NOTE This API is experimental and will change soon - use at your own risk.
// See https://github.com/open-telemetry/opentelemetry-collector/issues/4970
type Factory interface {
// CreateDefaultConfig creates the default configuration for the telemetry.
CreateDefaultConfig() component.Config

// CreateProviders creates telemetry providers.
CreateProviders(context.Context, telemetry.Settings, component.Config) (telemetry.Providers, error)

// unexportedFactoryFunc is used to prevent external implementations of Factory.
unexportedFactoryFunc()
}

// NewFactory creates a new Factory.
//
// NOTE This API is experimental and will change soon - use at your own risk.
// See https://github.com/open-telemetry/opentelemetry-collector/issues/4970
func NewFactory() Factory {
return newFactory(createDefaultConfig, createProviders)
// NewFactory creates a new telemetry.Factory that uses otelconf
// to configure opentelemetry-go SDK telemetry providers.
func NewFactory() telemetry.Factory {
return telemetry.NewFactory(createDefaultConfig, createProviders)
}

func createDefaultConfig() component.Config {
Expand Down
59 changes: 0 additions & 59 deletions service/telemetry/otelconftelemetry/factory_impl.go

This file was deleted.

98 changes: 95 additions & 3 deletions service/telemetry/telemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import (
"context"

"go.opentelemetry.io/otel/log"
nooplog "go.opentelemetry.io/otel/log/noop"
"go.opentelemetry.io/otel/metric"
noopmetric "go.opentelemetry.io/otel/metric/noop"
"go.opentelemetry.io/otel/trace"
nooptrace "go.opentelemetry.io/otel/trace/noop"
"go.uber.org/zap"

"go.opentelemetry.io/collector/component"
Expand All @@ -35,7 +38,7 @@ type Providers interface {
// Logger returns a zap.Logger that may be used by components to
// log their internal operations.
//
// NOTE: from the perspective of the Telemetry implementation,
// NOTE: from the perspective of the Providers 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
Expand All @@ -57,7 +60,7 @@ type Providers interface {
TracerProvider() trace.TracerProvider
}

// Settings holds configuration for building Telemetry.
// Settings holds configuration for building Providers.
type Settings struct {
// BuildInfo contains build information about the collector.
BuildInfo component.BuildInfo
Expand All @@ -66,5 +69,94 @@ type Settings struct {
ZapOptions []zap.Option
}

// TODO create abstract Factory interface that is implemented by otelconftelemetry.
// Factory is a factory interface for internal telemetry.
//
// This interface cannot be directly implemented. Implementations must
// use the NewFactory to implement it.
//
// NOTE This API is experimental and will change soon - use at your own risk.
// See https://github.com/open-telemetry/opentelemetry-collector/issues/4970
type Factory interface {
// CreateDefaultConfig creates the default configuration for the telemetry.
CreateDefaultConfig() component.Config

// CreateProviders creates the logger, meter, and tracer providers for
// the collector's internal telemetry.
CreateProviders(context.Context, Settings, component.Config) (Providers, error)

// unexportedFactoryFunc is used to prevent external implementations of Factory.
unexportedFactoryFunc()
}

type FactoryOption interface {
applyOption(*factory)
}

// factoryOptionFunc is an FactoryOption created through a function.
type factoryOptionFunc func(*factory)

func (f factoryOptionFunc) applyOption(o *factory) {
f(o)
}

type factory struct {
component.CreateDefaultConfigFunc
createProvidersFunc CreateProvidersFunc
}

// NewFactory returns a Factory.
//
// If createProviders is nil, then the returned Factory's CreateProviders
// method will return a Providers with noop telemetry providers.
func NewFactory(
createDefaultConfig component.CreateDefaultConfigFunc,
createProviders CreateProvidersFunc,
opts ...FactoryOption,
) Factory {
f := &factory{
CreateDefaultConfigFunc: createDefaultConfig,
createProvidersFunc: createProviders,
}
for _, opt := range opts {
opt.applyOption(f)
}
return f
}

// CreateProvidersFunc is the equivalent of Factory.CreateProviders.
type CreateProvidersFunc func(context.Context, Settings, component.Config) (Providers, error)

func (*factory) unexportedFactoryFunc() {}

func (f *factory) CreateProviders(ctx context.Context, settings Settings, cfg component.Config) (Providers, error) {
if f.createProvidersFunc == nil {
return nopProviders{}, nil
}
return f.createProvidersFunc(ctx, settings, cfg)
}

type nopProviders struct{}

func (nopProviders) Shutdown(context.Context) error {
return nil
}

func (nopProviders) Resource() pcommon.Resource {
return pcommon.NewResource()
}

func (nopProviders) Logger() *zap.Logger {
return zap.NewNop()
}

func (nopProviders) LoggerProvider() log.LoggerProvider {
return nooplog.NewLoggerProvider()
}

func (nopProviders) MeterProvider() metric.MeterProvider {
return noopmetric.NewMeterProvider()
}

func (nopProviders) TracerProvider() trace.TracerProvider {
return nooptrace.NewTracerProvider()
}
73 changes: 73 additions & 0 deletions service/telemetry/telemetry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package telemetry // import "go.opentelemetry.io/collector/service/telemetry"

import (
"context"
"errors"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
nooplog "go.opentelemetry.io/otel/log/noop"
noopmetric "go.opentelemetry.io/otel/metric/noop"
nooptrace "go.opentelemetry.io/otel/trace/noop"
"go.uber.org/zap"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/pdata/pcommon"
)

func TestNewFactory(t *testing.T) {
type contextKey struct{}
var config component.Config = new(struct{})
settings := Settings{BuildInfo: component.NewDefaultBuildInfo()}
ctx := context.WithValue(context.Background(), contextKey{}, 123)

var providers struct {
Providers
}
createProvidersFunc := func(ctx context.Context, set Settings, cfg component.Config) (Providers, error) {
assert.Equal(t, 123, ctx.Value(contextKey{}))
assert.Equal(t, settings, set)
assert.Equal(t, config, cfg)
return &providers, errors.New("not implemented")
}
factory := NewFactory(func() component.Config { return config }, createProvidersFunc)
require.NotNil(t, factory)

assert.Equal(t, config, factory.CreateDefaultConfig())
result, err := factory.CreateProviders(ctx, settings, config)
assert.Equal(t, &providers, result)
assert.EqualError(t, err, "not implemented")
}

func TestNewFactory_Nop(t *testing.T) {
// If the createProvidersFunc is nil, the factory will return
// a Providers implementation with no-op providers.
factory := NewFactory(nil, nil)
require.NotNil(t, factory)

providers, err := factory.CreateProviders(context.Background(), Settings{}, nil)
require.NoError(t, err)
require.NotNil(t, providers)

assert.Equal(t, pcommon.NewResource(), providers.Resource())
assert.Equal(t, zap.NewNop(), providers.Logger())
assert.Equal(t, nooplog.NewLoggerProvider(), providers.LoggerProvider())
assert.Equal(t, noopmetric.NewMeterProvider(), providers.MeterProvider())
assert.Equal(t, nooptrace.NewTracerProvider(), providers.TracerProvider())
assert.NoError(t, providers.Shutdown(context.Background()))
}

func TestNewFactory_Options(t *testing.T) {
var called []string
factory := NewFactory(nil, nil, factoryOptionFunc(func(*factory) {
called = append(called, "option1")
}), factoryOptionFunc(func(*factory) {
called = append(called, "option2")
}))
require.NotNil(t, factory)
assert.Equal(t, []string{"option1", "option2"}, called)
}
Loading