Skip to content

Commit 89b9e4f

Browse files
committed
[exporterhelper] Make panics into errors
1 parent fc08135 commit 89b9e4f

File tree

3 files changed

+84
-34
lines changed

3 files changed

+84
-34
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
7+
component: exporterhelper
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Invalid exporterhelper options now make the exporter creation error out instead of panicking.
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [9717]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: [api]

exporter/exporterhelper/common.go

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporte
55

66
import (
77
"context"
8+
"fmt"
89

910
"go.uber.org/multierr"
1011
"go.uber.org/zap"
@@ -42,55 +43,74 @@ func (b *baseRequestSender) setNextSender(nextSender requestSender) {
4243
type obsrepSenderFactory func(obsrep *ObsReport) requestSender
4344

4445
// Option apply changes to baseExporter.
45-
type Option func(*baseExporter)
46+
type Option interface {
47+
apply(*baseExporter) error
48+
}
49+
50+
var _ Option = (optionFuncNoErr)(nil)
51+
52+
type optionFuncNoErr func(*baseExporter)
53+
54+
func (o optionFuncNoErr) apply(be *baseExporter) error {
55+
o(be)
56+
return nil
57+
}
58+
59+
var _ Option = (optionFunc)(nil)
60+
61+
type optionFunc func(*baseExporter) error
62+
63+
func (o optionFunc) apply(be *baseExporter) error {
64+
return o(be)
65+
}
4666

4767
// WithStart overrides the default Start function for an exporter.
4868
// The default start function does nothing and always returns nil.
4969
func WithStart(start component.StartFunc) Option {
50-
return func(o *baseExporter) {
70+
return optionFuncNoErr(func(o *baseExporter) {
5171
o.StartFunc = start
52-
}
72+
})
5373
}
5474

5575
// WithShutdown overrides the default Shutdown function for an exporter.
5676
// The default shutdown function does nothing and always returns nil.
5777
func WithShutdown(shutdown component.ShutdownFunc) Option {
58-
return func(o *baseExporter) {
78+
return optionFuncNoErr(func(o *baseExporter) {
5979
o.ShutdownFunc = shutdown
60-
}
80+
})
6181
}
6282

6383
// WithTimeout overrides the default TimeoutSettings for an exporter.
6484
// The default TimeoutSettings is 5 seconds.
6585
func WithTimeout(timeoutSettings TimeoutSettings) Option {
66-
return func(o *baseExporter) {
86+
return optionFuncNoErr(func(o *baseExporter) {
6787
o.timeoutSender.cfg = timeoutSettings
68-
}
88+
})
6989
}
7090

7191
// WithRetry overrides the default configretry.BackOffConfig for an exporter.
7292
// The default configretry.BackOffConfig is to disable retries.
7393
func WithRetry(config configretry.BackOffConfig) Option {
74-
return func(o *baseExporter) {
94+
return optionFuncNoErr(func(o *baseExporter) {
7595
if !config.Enabled {
7696
o.exportFailureMessage += " Try enabling retry_on_failure config option to retry on retryable errors."
7797
return
7898
}
7999
o.retrySender = newRetrySender(config, o.set)
80-
}
100+
})
81101
}
82102

83103
// WithQueue overrides the default QueueSettings for an exporter.
84104
// The default QueueSettings is to disable queueing.
85105
// This option cannot be used with the new exporter helpers New[Traces|Metrics|Logs]RequestExporter.
86106
func WithQueue(config QueueSettings) Option {
87-
return func(o *baseExporter) {
107+
return optionFunc(func(o *baseExporter) error {
88108
if o.marshaler == nil || o.unmarshaler == nil {
89-
panic("WithQueue option is not available for the new request exporters, use WithRequestQueue instead")
109+
return fmt.Errorf("WithQueue option is not available for the new request exporters, use WithRequestQueue instead")
90110
}
91111
if !config.Enabled {
92112
o.exportFailureMessage += " Try enabling sending_queue to survive temporary failures."
93-
return
113+
return nil
94114
}
95115
qf := exporterqueue.NewPersistentQueueFactory[Request](config.StorageID, exporterqueue.PersistentQueueSettings[Request]{
96116
Marshaler: o.marshaler,
@@ -105,53 +125,55 @@ func WithQueue(config QueueSettings) Option {
105125
QueueSize: config.QueueSize,
106126
})
107127
o.queueSender = newQueueSender(q, o.set, config.NumConsumers, o.exportFailureMessage)
108-
}
128+
return nil
129+
})
109130
}
110131

111132
// WithRequestQueue enables queueing for an exporter.
112133
// This option should be used with the new exporter helpers New[Traces|Metrics|Logs]RequestExporter.
113134
// This API is at the early stage of development and may change without backward compatibility
114135
// until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved.
115136
func WithRequestQueue(cfg exporterqueue.Config, queueFactory exporterqueue.Factory[Request]) Option {
116-
return func(o *baseExporter) {
137+
return optionFunc(func(o *baseExporter) error {
117138
if o.marshaler != nil || o.unmarshaler != nil {
118-
panic("WithRequestQueue option must be used with the new request exporters only, use WithQueue instead")
139+
return fmt.Errorf("WithRequestQueue option must be used with the new request exporters only, use WithQueue instead")
119140
}
120141
if !cfg.Enabled {
121142
o.exportFailureMessage += " Try enabling sending_queue to survive temporary failures."
122-
return
143+
return nil
123144
}
124145
set := exporterqueue.Settings{
125146
DataType: o.signal,
126147
ExporterSettings: o.set,
127148
}
128149
o.queueSender = newQueueSender(queueFactory(context.Background(), set, cfg), o.set, cfg.NumConsumers, o.exportFailureMessage)
129-
}
150+
return nil
151+
})
130152
}
131153

132154
// WithCapabilities overrides the default Capabilities() function for a Consumer.
133155
// The default is non-mutable data.
134156
// TODO: Verify if we can change the default to be mutable as we do for processors.
135157
func WithCapabilities(capabilities consumer.Capabilities) Option {
136-
return func(o *baseExporter) {
158+
return optionFuncNoErr(func(o *baseExporter) {
137159
o.consumerOptions = append(o.consumerOptions, consumer.WithCapabilities(capabilities))
138-
}
160+
})
139161
}
140162

141163
// withMarshaler is used to set the request marshaler for the new exporter helper.
142164
// It must be provided as the first option when creating a new exporter helper.
143165
func withMarshaler(marshaler exporterqueue.Marshaler[Request]) Option {
144-
return func(o *baseExporter) {
166+
return optionFuncNoErr(func(o *baseExporter) {
145167
o.marshaler = marshaler
146-
}
168+
})
147169
}
148170

149171
// withUnmarshaler is used to set the request unmarshaler for the new exporter helper.
150172
// It must be provided as the first option when creating a new exporter helper.
151173
func withUnmarshaler(unmarshaler exporterqueue.Unmarshaler[Request]) Option {
152-
return func(o *baseExporter) {
174+
return optionFuncNoErr(func(o *baseExporter) {
153175
o.unmarshaler = unmarshaler
154-
}
176+
})
155177
}
156178

157179
// baseExporter contains common fields between different exporter types.
@@ -199,8 +221,12 @@ func newBaseExporter(set exporter.CreateSettings, signal component.DataType, osf
199221
}
200222

201223
for _, op := range options {
202-
op(be)
224+
err = multierr.Append(err, op.apply(be))
225+
}
226+
if err != nil {
227+
return nil, err
203228
}
229+
204230
be.connectSenders()
205231

206232
return be, nil

exporter/exporterhelper/common_test.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,15 @@ func TestQueueOptionsWithRequestExporter(t *testing.T) {
7171
require.Nil(t, err)
7272
require.Nil(t, bs.marshaler)
7373
require.Nil(t, bs.unmarshaler)
74-
require.Panics(t, func() {
75-
_, _ = newBaseExporter(exportertest.NewNopCreateSettings(), defaultType, newNoopObsrepSender,
76-
WithRetry(configretry.NewDefaultBackOffConfig()), WithQueue(NewDefaultQueueSettings()))
77-
})
78-
require.Panics(t, func() {
79-
_, _ = newBaseExporter(exportertest.NewNopCreateSettings(), defaultType, newNoopObsrepSender,
80-
withMarshaler(mockRequestMarshaler), withUnmarshaler(mockRequestUnmarshaler(&mockRequest{})),
81-
WithRetry(configretry.NewDefaultBackOffConfig()),
82-
WithRequestQueue(exporterqueue.NewDefaultConfig(), exporterqueue.NewMemoryQueueFactory[Request]()))
83-
})
74+
_, err = newBaseExporter(exportertest.NewNopCreateSettings(), defaultType, newNoopObsrepSender,
75+
WithRetry(configretry.NewDefaultBackOffConfig()), WithQueue(NewDefaultQueueSettings()))
76+
require.Error(t, err)
77+
78+
_, err = newBaseExporter(exportertest.NewNopCreateSettings(), defaultType, newNoopObsrepSender,
79+
withMarshaler(mockRequestMarshaler), withUnmarshaler(mockRequestUnmarshaler(&mockRequest{})),
80+
WithRetry(configretry.NewDefaultBackOffConfig()),
81+
WithRequestQueue(exporterqueue.NewDefaultConfig(), exporterqueue.NewMemoryQueueFactory[Request]()))
82+
require.Error(t, err)
8483
}
8584

8685
func TestBaseExporterLogging(t *testing.T) {

0 commit comments

Comments
 (0)