Skip to content

Commit

Permalink
Add helper exporter factory to reduce boilerplate (#1351)
Browse files Browse the repository at this point in the history
Signed-off-by: Bogdan Drutu <bogdandrutu@gmail.com>
  • Loading branch information
bogdandrutu authored Jul 17, 2020
1 parent 558df2e commit 9a08d4d
Show file tree
Hide file tree
Showing 15 changed files with 307 additions and 103 deletions.
129 changes: 129 additions & 0 deletions exporter/exporterhelper/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package exporterhelper

import (
"context"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configerror"
"go.opentelemetry.io/collector/config/configmodels"
)

// FactoryOption apply changes to ExporterOptions.
type FactoryOption func(o *factory)

// CreateDefaultConfig is the equivalent of component.ExporterFactory.CreateDefaultConfig()
type CreateDefaultConfig func() configmodels.Exporter

// CreateTraceExporter is the equivalent of component.ExporterFactory.CreateTraceExporter()
type CreateTraceExporter func(context.Context, component.ExporterCreateParams, configmodels.Exporter) (component.TraceExporter, error)

// CreateMetricsExporter is the equivalent of component.ExporterFactory.CreateMetricsExporter()
type CreateMetricsExporter func(context.Context, component.ExporterCreateParams, configmodels.Exporter) (component.MetricsExporter, error)

// CreateMetricsExporter is the equivalent of component.ExporterFactory.CreateLogExporter()
type CreateLogExporter func(context.Context, component.ExporterCreateParams, configmodels.Exporter) (component.LogExporter, error)

// factory is the factory for Jaeger gRPC exporter.
type factory struct {
cfgType configmodels.Type
createDefaultConfig CreateDefaultConfig
createTraceExporter CreateTraceExporter
createMetricsExporter CreateMetricsExporter
createLogExporter CreateLogExporter
}

var _ component.LogExporterFactory = new(factory)

// WithTraces overrides the default "error not supported" implementation for CreateTraceReceiver.
func WithTraces(createTraceExporter CreateTraceExporter) FactoryOption {
return func(o *factory) {
o.createTraceExporter = createTraceExporter
}
}

// WithMetrics overrides the default "error not supported" implementation for CreateMetricsReceiver.
func WithMetrics(createMetricsExporter CreateMetricsExporter) FactoryOption {
return func(o *factory) {
o.createMetricsExporter = createMetricsExporter
}
}

// WithLogs overrides the default "error not supported" implementation for CreateLogReceiver.
func WithLogs(createLogExporter CreateLogExporter) FactoryOption {
return func(o *factory) {
o.createLogExporter = createLogExporter
}
}

// NewFactory returns a component.ExporterFactory that only supports all types.
func NewFactory(
cfgType configmodels.Type,
createDefaultConfig CreateDefaultConfig,
options ...FactoryOption) component.ExporterFactory {
f := &factory{
cfgType: cfgType,
createDefaultConfig: createDefaultConfig,
}
for _, opt := range options {
opt(f)
}
return f
}

// Type gets the type of the Exporter config created by this factory.
func (f *factory) Type() configmodels.Type {
return f.cfgType
}

// CreateDefaultConfig creates the default configuration for processor.
func (f *factory) CreateDefaultConfig() configmodels.Exporter {
return f.createDefaultConfig()
}

// CreateTraceExporter creates a component.TraceExporter based on this config.
func (f *factory) CreateTraceExporter(
ctx context.Context,
params component.ExporterCreateParams,
cfg configmodels.Exporter) (component.TraceExporter, error) {
if f.createTraceExporter != nil {
return f.createTraceExporter(ctx, params, cfg)
}
return nil, configerror.ErrDataTypeIsNotSupported
}

// CreateMetricsExporter creates a consumer.MetricsConsumer based on this config.
func (f *factory) CreateMetricsExporter(
ctx context.Context,
params component.ExporterCreateParams,
cfg configmodels.Exporter) (component.MetricsExporter, error) {
if f.createMetricsExporter != nil {
return f.createMetricsExporter(ctx, params, cfg)
}
return nil, configerror.ErrDataTypeIsNotSupported
}

// CreateLogExporter creates a metrics processor based on this config.
func (f *factory) CreateLogExporter(
ctx context.Context,
params component.ExporterCreateParams,
cfg configmodels.Exporter,
) (component.LogExporter, error) {
if f.createLogExporter != nil {
return f.createLogExporter(ctx, params, cfg)
}
return nil, configerror.ErrDataTypeIsNotSupported
}
94 changes: 94 additions & 0 deletions exporter/exporterhelper/factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package exporterhelper

import (
"context"
"testing"

"github.com/stretchr/testify/assert"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configerror"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/exporter/exportertest"
)

const typeStr = "test"

var (
defaultCfg = &configmodels.ExporterSettings{
TypeVal: typeStr,
NameVal: typeStr,
}
nopTracesExporter = exportertest.NewNopTraceExporter()
nopMetricsExporter = exportertest.NewNopMetricsExporter()
nopLogsExporter = exportertest.NewNopLogsExporter()
)

func TestNewFactory(t *testing.T) {
factory := NewFactory(
typeStr,
defaultConfig)
assert.EqualValues(t, typeStr, factory.Type())
assert.EqualValues(t, defaultCfg, factory.CreateDefaultConfig())
_, err := factory.CreateTraceExporter(context.Background(), component.ExporterCreateParams{}, defaultCfg)
assert.Equal(t, configerror.ErrDataTypeIsNotSupported, err)
_, err = factory.CreateMetricsExporter(context.Background(), component.ExporterCreateParams{}, defaultCfg)
assert.Equal(t, configerror.ErrDataTypeIsNotSupported, err)
lfactory := factory.(component.LogExporterFactory)
_, err = lfactory.CreateLogExporter(context.Background(), component.ExporterCreateParams{}, defaultCfg)
assert.Equal(t, configerror.ErrDataTypeIsNotSupported, err)
}

func TestNewFactory_WithConstructors(t *testing.T) {
factory := NewFactory(
typeStr,
defaultConfig,
WithTraces(createTraceExporter),
WithMetrics(createMetricsExporter),
WithLogs(createLogExporter))
assert.EqualValues(t, typeStr, factory.Type())
assert.EqualValues(t, defaultCfg, factory.CreateDefaultConfig())

te, err := factory.CreateTraceExporter(context.Background(), component.ExporterCreateParams{}, defaultCfg)
assert.NoError(t, err)
assert.Same(t, nopTracesExporter, te)

me, err := factory.CreateMetricsExporter(context.Background(), component.ExporterCreateParams{}, defaultCfg)
assert.NoError(t, err)
assert.Same(t, nopMetricsExporter, me)

lfactory := factory.(component.LogExporterFactory)
le, err := lfactory.CreateLogExporter(context.Background(), component.ExporterCreateParams{}, defaultCfg)
assert.NoError(t, err)
assert.Same(t, nopLogsExporter, le)
}

func defaultConfig() configmodels.Exporter {
return defaultCfg
}

func createTraceExporter(context.Context, component.ExporterCreateParams, configmodels.Exporter) (component.TraceExporter, error) {
return nopTracesExporter, nil
}

func createMetricsExporter(context.Context, component.ExporterCreateParams, configmodels.Exporter) (component.MetricsExporter, error) {
return nopMetricsExporter, nil
}

func createLogExporter(context.Context, component.ExporterCreateParams, configmodels.Exporter) (component.LogExporter, error) {
return nopLogsExporter, nil
}
2 changes: 1 addition & 1 deletion exporter/jaegerexporter/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestLoadConfig(t *testing.T) {
factories, err := config.ExampleComponents()
assert.NoError(t, err)

factory := &Factory{}
factory := NewFactory()
factories.Exporters[typeStr] = factory
cfg, err := config.LoadConfigFile(t, path.Join(".", "testdata", "config.yaml"), factories)

Expand Down
2 changes: 1 addition & 1 deletion exporter/jaegerexporter/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func TestMutualTLS(t *testing.T) {
defer server.GracefulStop()

// Create gRPC trace exporter
factory := &Factory{}
factory := NewFactory()
cfg := factory.CreateDefaultConfig().(*Config)
cfg.GRPCClientSettings = configgrpc.GRPCClientSettings{
Endpoint: serverAddr.String(),
Expand Down
30 changes: 9 additions & 21 deletions exporter/jaegerexporter/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,25 @@ import (
"fmt"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configerror"
"go.opentelemetry.io/collector/config/configgrpc"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/exporter/exporterhelper"
)

const (
// The value of "type" key in configuration.
typeStr = "jaeger"
)

// Factory is the factory for Jaeger gRPC exporter.
type Factory struct {
// NewFactory creates a factory for Jaeger exporter
func NewFactory() component.ExporterFactory {
return exporterhelper.NewFactory(
typeStr,
createDefaultConfig,
exporterhelper.WithTraces(createTraceExporter))
}

// Type gets the type of the Exporter config created by this factory.
func (f *Factory) Type() configmodels.Type {
return typeStr
}

// CreateDefaultConfig creates the default configuration for exporter.
func (f *Factory) CreateDefaultConfig() configmodels.Exporter {
func createDefaultConfig() configmodels.Exporter {
return &Config{
ExporterSettings: configmodels.ExporterSettings{
TypeVal: typeStr,
Expand All @@ -52,8 +50,7 @@ func (f *Factory) CreateDefaultConfig() configmodels.Exporter {
}
}

// CreateTraceExporter creates a trace exporter based on this config.
func (f *Factory) CreateTraceExporter(
func createTraceExporter(
_ context.Context,
_ component.ExporterCreateParams,
config configmodels.Exporter,
Expand All @@ -75,12 +72,3 @@ func (f *Factory) CreateTraceExporter(

return exp, nil
}

// CreateMetricsExporter creates a metrics exporter based on this config.
func (f *Factory) CreateMetricsExporter(
_ context.Context,
_ component.ExporterCreateParams,
_ configmodels.Exporter,
) (component.MetricsExporter, error) {
return nil, configerror.ErrDataTypeIsNotSupported
}
6 changes: 3 additions & 3 deletions exporter/jaegerexporter/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ import (
)

func TestCreateDefaultConfig(t *testing.T) {
factory := Factory{}
factory := NewFactory()
cfg := factory.CreateDefaultConfig()
assert.NotNil(t, cfg, "failed to create default config")
assert.NoError(t, configcheck.ValidateConfig(cfg))
}

func TestCreateMetricsExporter(t *testing.T) {
factory := Factory{}
factory := NewFactory()
cfg := factory.CreateDefaultConfig()

params := component.ExporterCreateParams{Logger: zap.NewNop()}
Expand All @@ -43,7 +43,7 @@ func TestCreateMetricsExporter(t *testing.T) {
}

func TestCreateInstanceViaFactory(t *testing.T) {
factory := Factory{}
factory := NewFactory()

cfg := factory.CreateDefaultConfig()

Expand Down
2 changes: 1 addition & 1 deletion exporter/loggingexporter/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestLoadConfig(t *testing.T) {
factories, err := config.ExampleComponents()
assert.NoError(t, err)

factory := &Factory{}
factory := NewFactory()
factories.Exporters[typeStr] = factory
cfg, err := config.LoadConfigFile(t, path.Join(".", "testdata", "config.yaml"), factories)

Expand Down
Loading

0 comments on commit 9a08d4d

Please sign in to comment.