Skip to content

Commit 331fa14

Browse files
committed
service/telemetry: introduce Factory interface
1 parent 822643b commit 331fa14

File tree

4 files changed

+172
-86
lines changed

4 files changed

+172
-86
lines changed

service/telemetry/otelconftelemetry/factory.go

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry"
55

66
import (
7-
"context"
87
"time"
98

109
config "go.opentelemetry.io/contrib/otelconf/v0.3.0"
@@ -23,29 +22,10 @@ var useLocalHostAsDefaultMetricsAddressFeatureGate = featuregate.GlobalRegistry(
2322
featuregate.WithRegisterDescription("controls whether default Prometheus metrics server use localhost as the default host for their endpoints"),
2423
)
2524

26-
// Factory is factory interface for telemetry providers.
27-
// This interface cannot be directly implemented. Implementations must
28-
// use the NewFactory to implement it.
29-
//
30-
// NOTE This API is experimental and will change soon - use at your own risk.
31-
// See https://github.com/open-telemetry/opentelemetry-collector/issues/4970
32-
type Factory interface {
33-
// CreateDefaultConfig creates the default configuration for the telemetry.
34-
CreateDefaultConfig() component.Config
35-
36-
// CreateProviders creates telemetry providers.
37-
CreateProviders(context.Context, telemetry.Settings, component.Config) (telemetry.Providers, error)
38-
39-
// unexportedFactoryFunc is used to prevent external implementations of Factory.
40-
unexportedFactoryFunc()
41-
}
42-
43-
// NewFactory creates a new Factory.
44-
//
45-
// NOTE This API is experimental and will change soon - use at your own risk.
46-
// See https://github.com/open-telemetry/opentelemetry-collector/issues/4970
47-
func NewFactory() Factory {
48-
return newFactory(createDefaultConfig, createProviders)
25+
// NewFactory creates a new telemetry.Factory that uses otelconf
26+
// to configure opentelemetry-go SDK telemetry providers.
27+
func NewFactory() telemetry.Factory {
28+
return telemetry.NewFactory(createDefaultConfig, createProviders)
4929
}
5030

5131
func createDefaultConfig() component.Config {

service/telemetry/otelconftelemetry/factory_impl.go

Lines changed: 0 additions & 59 deletions
This file was deleted.

service/telemetry/telemetry.go

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import (
77
"context"
88

99
"go.opentelemetry.io/otel/log"
10+
nooplog "go.opentelemetry.io/otel/log/noop"
1011
"go.opentelemetry.io/otel/metric"
12+
noopmetric "go.opentelemetry.io/otel/metric/noop"
1113
"go.opentelemetry.io/otel/trace"
14+
nooptrace "go.opentelemetry.io/otel/trace/noop"
1215
"go.uber.org/zap"
1316

1417
"go.opentelemetry.io/collector/component"
@@ -35,7 +38,7 @@ type Providers interface {
3538
// Logger returns a zap.Logger that may be used by components to
3639
// log their internal operations.
3740
//
38-
// NOTE: from the perspective of the Telemetry implementation,
41+
// NOTE: from the perspective of the Providers implementation,
3942
// this Logger and the LoggerProvider are independent. However,
4043
// the service package will arrange for logs written to this
4144
// logger to be copied to the LoggerProvider. The effective
@@ -57,7 +60,7 @@ type Providers interface {
5760
TracerProvider() trace.TracerProvider
5861
}
5962

60-
// Settings holds configuration for building Telemetry.
63+
// Settings holds configuration for building Providers.
6164
type Settings struct {
6265
// BuildInfo contains build information about the collector.
6366
BuildInfo component.BuildInfo
@@ -66,5 +69,94 @@ type Settings struct {
6669
ZapOptions []zap.Option
6770
}
6871

69-
// TODO create abstract Factory interface that is implemented by otelconftelemetry.
72+
// Factory is a factory interface for internal telemetry.
73+
//
74+
// This interface cannot be directly implemented. Implementations must
75+
// use the NewFactory to implement it.
76+
//
77+
// NOTE This API is experimental and will change soon - use at your own risk.
7078
// See https://github.com/open-telemetry/opentelemetry-collector/issues/4970
79+
type Factory interface {
80+
// CreateDefaultConfig creates the default configuration for the telemetry.
81+
CreateDefaultConfig() component.Config
82+
83+
// CreateProviders creates the logger, meter, and tracer providers for
84+
// the collector's internal telemetry.
85+
CreateProviders(context.Context, Settings, component.Config) (Providers, error)
86+
87+
// unexportedFactoryFunc is used to prevent external implementations of Factory.
88+
unexportedFactoryFunc()
89+
}
90+
91+
type FactoryOption interface {
92+
applyOption(*factory)
93+
}
94+
95+
// factoryOptionFunc is an FactoryOption created through a function.
96+
type factoryOptionFunc func(*factory)
97+
98+
func (f factoryOptionFunc) applyOption(o *factory) {
99+
f(o)
100+
}
101+
102+
type factory struct {
103+
component.CreateDefaultConfigFunc
104+
createProvidersFunc CreateProvidersFunc
105+
}
106+
107+
// NewFactory returns a Factory.
108+
//
109+
// If createProviders is nil, then the returned Factory's CreateProviders
110+
// method will return a Providers with noop telemetry providers.
111+
func NewFactory(
112+
createDefaultConfig component.CreateDefaultConfigFunc,
113+
createProviders CreateProvidersFunc,
114+
opts ...FactoryOption,
115+
) Factory {
116+
f := &factory{
117+
CreateDefaultConfigFunc: createDefaultConfig,
118+
createProvidersFunc: createProviders,
119+
}
120+
for _, opt := range opts {
121+
opt.applyOption(f)
122+
}
123+
return f
124+
}
125+
126+
// CreateProvidersFunc is the equivalent of Factory.CreateProviders.
127+
type CreateProvidersFunc func(context.Context, Settings, component.Config) (Providers, error)
128+
129+
func (*factory) unexportedFactoryFunc() {}
130+
131+
func (f *factory) CreateProviders(ctx context.Context, settings Settings, cfg component.Config) (Providers, error) {
132+
if f.createProvidersFunc == nil {
133+
return nopProviders{}, nil
134+
}
135+
return f.createProvidersFunc(ctx, settings, cfg)
136+
}
137+
138+
type nopProviders struct{}
139+
140+
func (nopProviders) Shutdown(context.Context) error {
141+
return nil
142+
}
143+
144+
func (nopProviders) Resource() pcommon.Resource {
145+
return pcommon.NewResource()
146+
}
147+
148+
func (nopProviders) Logger() *zap.Logger {
149+
return zap.NewNop()
150+
}
151+
152+
func (nopProviders) LoggerProvider() log.LoggerProvider {
153+
return nooplog.NewLoggerProvider()
154+
}
155+
156+
func (nopProviders) MeterProvider() metric.MeterProvider {
157+
return noopmetric.NewMeterProvider()
158+
}
159+
160+
func (nopProviders) TracerProvider() trace.TracerProvider {
161+
return nooptrace.NewTracerProvider()
162+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package telemetry // import "go.opentelemetry.io/collector/service/telemetry"
5+
6+
import (
7+
"context"
8+
"errors"
9+
"testing"
10+
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
nooplog "go.opentelemetry.io/otel/log/noop"
14+
noopmetric "go.opentelemetry.io/otel/metric/noop"
15+
nooptrace "go.opentelemetry.io/otel/trace/noop"
16+
"go.uber.org/zap"
17+
18+
"go.opentelemetry.io/collector/component"
19+
"go.opentelemetry.io/collector/pdata/pcommon"
20+
)
21+
22+
func TestNewFactory(t *testing.T) {
23+
type contextKey struct{}
24+
var config component.Config = new(struct{})
25+
settings := Settings{BuildInfo: component.NewDefaultBuildInfo()}
26+
ctx := context.WithValue(context.Background(), contextKey{}, 123)
27+
28+
var providers struct {
29+
Providers
30+
}
31+
createProvidersFunc := func(ctx context.Context, set Settings, cfg component.Config) (Providers, error) {
32+
assert.Equal(t, 123, ctx.Value(contextKey{}))
33+
assert.Equal(t, settings, set)
34+
assert.Equal(t, config, cfg)
35+
return &providers, errors.New("not implemented")
36+
}
37+
factory := NewFactory(func() component.Config { return config }, createProvidersFunc)
38+
require.NotNil(t, factory)
39+
40+
assert.Equal(t, config, factory.CreateDefaultConfig())
41+
result, err := factory.CreateProviders(ctx, settings, config)
42+
assert.Equal(t, &providers, result)
43+
assert.EqualError(t, err, "not implemented")
44+
}
45+
46+
func TestNewFactory_Nop(t *testing.T) {
47+
// If the createProvidersFunc is nil, the factory will return
48+
// a Providers implementation with no-op providers.
49+
factory := NewFactory(nil, nil)
50+
require.NotNil(t, factory)
51+
52+
providers, err := factory.CreateProviders(context.Background(), Settings{}, nil)
53+
require.NoError(t, err)
54+
require.NotNil(t, providers)
55+
56+
assert.Equal(t, pcommon.NewResource(), providers.Resource())
57+
assert.Equal(t, zap.NewNop(), providers.Logger())
58+
assert.Equal(t, nooplog.NewLoggerProvider(), providers.LoggerProvider())
59+
assert.Equal(t, noopmetric.NewMeterProvider(), providers.MeterProvider())
60+
assert.Equal(t, nooptrace.NewTracerProvider(), providers.TracerProvider())
61+
assert.NoError(t, providers.Shutdown(context.Background()))
62+
}
63+
64+
func TestNewFactory_Options(t *testing.T) {
65+
var called []string
66+
factory := NewFactory(nil, nil, factoryOptionFunc(func(*factory) {
67+
called = append(called, "option1")
68+
}), factoryOptionFunc(func(*factory) {
69+
called = append(called, "option2")
70+
}))
71+
require.NotNil(t, factory)
72+
assert.Equal(t, []string{"option1", "option2"}, called)
73+
}

0 commit comments

Comments
 (0)