Skip to content

Commit 6ea578c

Browse files
committed
[otlpexporter] Validate the configuration explicitly
1 parent aaf8b1e commit 6ea578c

File tree

6 files changed

+108
-36
lines changed

6 files changed

+108
-36
lines changed

exporter/otlpexporter/config.go

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
package otlpexporter // import "go.opentelemetry.io/collector/exporter/otlpexporter"
55

66
import (
7+
"errors"
8+
79
"go.opentelemetry.io/collector/component"
810
"go.opentelemetry.io/collector/config/configgrpc"
911
"go.opentelemetry.io/collector/config/configretry"
@@ -19,4 +21,11 @@ type Config struct {
1921
configgrpc.ClientConfig `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct.
2022
}
2123

24+
func (c *Config) Validate() error {
25+
if c.SanitizedEndpoint() == "" {
26+
return errors.New(`requires a non-empty "endpoint"`)
27+
}
28+
return nil
29+
}
30+
2231
var _ component.Config = (*Config)(nil)

exporter/otlpexporter/config_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,39 @@ func TestUnmarshalConfig(t *testing.T) {
7878
},
7979
}, cfg)
8080
}
81+
82+
func TestUnmarshalInvalidConfig(t *testing.T) {
83+
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "invalid_configs.yaml"))
84+
require.NoError(t, err)
85+
factory := NewFactory()
86+
for _, test := range []struct {
87+
name string
88+
errorMsg string
89+
}{
90+
{
91+
name: "no_endpoint",
92+
errorMsg: `requires a non-empty "endpoint"`,
93+
},
94+
{
95+
name: "http_endpoint",
96+
errorMsg: `requires a non-empty "endpoint"`,
97+
},
98+
{
99+
name: "invalid_timeout",
100+
errorMsg: `'timeout' must be non-negative`,
101+
},
102+
{
103+
name: "invalid_retry",
104+
errorMsg: `'randomization_factor' must be within [0, 1]`,
105+
},
106+
} {
107+
t.Run(test.name, func(t *testing.T) {
108+
cfg := factory.CreateDefaultConfig()
109+
sub, err := cm.Sub(test.name)
110+
require.NoError(t, err)
111+
assert.NoError(t, component.UnmarshalConfig(sub, cfg))
112+
assert.ErrorContains(t, component.ValidateConfig(cfg), test.errorMsg)
113+
})
114+
}
115+
116+
}

exporter/otlpexporter/factory.go

+3-12
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,7 @@ func createTracesExporter(
4848
set exporter.CreateSettings,
4949
cfg component.Config,
5050
) (exporter.Traces, error) {
51-
oce, err := newExporter(cfg, set)
52-
if err != nil {
53-
return nil, err
54-
}
51+
oce := newExporter(cfg, set)
5552
oCfg := cfg.(*Config)
5653
return exporterhelper.NewTracesExporter(ctx, set, cfg,
5754
oce.pushTraces,
@@ -68,10 +65,7 @@ func createMetricsExporter(
6865
set exporter.CreateSettings,
6966
cfg component.Config,
7067
) (exporter.Metrics, error) {
71-
oce, err := newExporter(cfg, set)
72-
if err != nil {
73-
return nil, err
74-
}
68+
oce := newExporter(cfg, set)
7569
oCfg := cfg.(*Config)
7670
return exporterhelper.NewMetricsExporter(ctx, set, cfg,
7771
oce.pushMetrics,
@@ -89,10 +83,7 @@ func createLogsExporter(
8983
set exporter.CreateSettings,
9084
cfg component.Config,
9185
) (exporter.Logs, error) {
92-
oce, err := newExporter(cfg, set)
93-
if err != nil {
94-
return nil, err
95-
}
86+
oce := newExporter(cfg, set)
9687
oCfg := cfg.(*Config)
9788
return exporterhelper.NewLogsExporter(ctx, set, cfg,
9889
oce.pushLogs,

exporter/otlpexporter/factory_test.go

+3-17
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,10 @@ func TestCreateMetricsExporter(t *testing.T) {
5050
func TestCreateTracesExporter(t *testing.T) {
5151
endpoint := testutil.GetAvailableLocalAddress(t)
5252
tests := []struct {
53-
name string
54-
config *Config
55-
mustFailOnCreate bool
56-
mustFailOnStart bool
53+
name string
54+
config *Config
55+
mustFailOnStart bool
5756
}{
58-
{
59-
name: "NoEndpoint",
60-
config: &Config{
61-
ClientConfig: configgrpc.ClientConfig{
62-
Endpoint: "",
63-
},
64-
},
65-
mustFailOnCreate: true,
66-
},
6757
{
6858
name: "UseSecure",
6959
config: &Config{
@@ -178,10 +168,6 @@ func TestCreateTracesExporter(t *testing.T) {
178168
factory := NewFactory()
179169
set := exportertest.NewNopCreateSettings()
180170
consumer, err := factory.CreateTracesExporter(context.Background(), set, tt.config)
181-
if tt.mustFailOnCreate {
182-
assert.NotNil(t, err)
183-
return
184-
}
185171
assert.NoError(t, err)
186172
assert.NotNil(t, consumer)
187173
err = consumer.Start(context.Background(), componenttest.NewNopHost())

exporter/otlpexporter/otlp.go

+2-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package otlpexporter // import "go.opentelemetry.io/collector/exporter/otlpexpor
55

66
import (
77
"context"
8-
"errors"
98
"fmt"
109
"runtime"
1110
"time"
@@ -49,17 +48,13 @@ type baseExporter struct {
4948

5049
// Crete new exporter and start it. The exporter will begin connecting but
5150
// this function may return before the connection is established.
52-
func newExporter(cfg component.Config, set exporter.CreateSettings) (*baseExporter, error) {
51+
func newExporter(cfg component.Config, set exporter.CreateSettings) *baseExporter {
5352
oCfg := cfg.(*Config)
5453

55-
if oCfg.Endpoint == "" {
56-
return nil, errors.New("OTLP exporter config requires an Endpoint")
57-
}
58-
5954
userAgent := fmt.Sprintf("%s/%s (%s/%s)",
6055
set.BuildInfo.Description, set.BuildInfo.Version, runtime.GOOS, runtime.GOARCH)
6156

62-
return &baseExporter{config: oCfg, settings: set.TelemetrySettings, userAgent: userAgent}, nil
57+
return &baseExporter{config: oCfg, settings: set.TelemetrySettings, userAgent: userAgent}
6358
}
6459

6560
// start actually creates the gRPC connection. The client construction is deferred till this point as this
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
no_endpoint:
2+
timeout: 10s
3+
sending_queue:
4+
enabled: true
5+
num_consumers: 2
6+
queue_size: 10
7+
retry_on_failure:
8+
enabled: true
9+
initial_interval: 10s
10+
randomization_factor: 0.7
11+
multiplier: 1.3
12+
max_interval: 60s
13+
max_elapsed_time: 10m
14+
http_endpoint:
15+
endpoint: http://
16+
timeout: 10s
17+
sending_queue:
18+
enabled: true
19+
num_consumers: 2
20+
queue_size: 10
21+
retry_on_failure:
22+
enabled: true
23+
initial_interval: 10s
24+
randomization_factor: 0.7
25+
multiplier: 1.3
26+
max_interval: 60s
27+
max_elapsed_time: 10m
28+
invalid_timeout:
29+
endpoint: example.com:443
30+
timeout: -5s
31+
sending_queue:
32+
enabled: true
33+
num_consumers: 2
34+
queue_size: 10
35+
retry_on_failure:
36+
enabled: true
37+
initial_interval: 10s
38+
randomization_factor: 0.7
39+
multiplier: 1.3
40+
max_interval: 60s
41+
max_elapsed_time: 10m
42+
invalid_retry:
43+
endpoint: example.com:443
44+
timeout: 30s
45+
sending_queue:
46+
enabled: true
47+
num_consumers: 2
48+
queue_size: 10
49+
retry_on_failure:
50+
enabled: true
51+
initial_interval: 10s
52+
randomization_factor: -5
53+
multiplier: 1.3
54+
max_interval: 60s
55+
max_elapsed_time: 10m

0 commit comments

Comments
 (0)