@@ -31,38 +31,38 @@ var (
31
31
okStatus = trace.Status {Code : trace .StatusCodeOK }
32
32
)
33
33
34
+ // Settings for timeout. The timeout applies to individual attempts to send data to the backend.
34
35
type TimeoutSettings struct {
35
- // Timeout is the timeout for each operation .
36
+ // Timeout is the timeout for every attempt to send data to the backend .
36
37
Timeout time.Duration `mapstructure:"timeout"`
37
38
}
38
39
40
+ // CreateDefaultTimeoutSettings returns the default settings for TimeoutSettings.
39
41
func CreateDefaultTimeoutSettings () TimeoutSettings {
40
42
return TimeoutSettings {
41
43
Timeout : 5 * time .Second ,
42
44
}
43
45
}
44
46
45
- type settings struct {
46
- configmodels.Exporter
47
- TimeoutSettings
48
- QueuedSettings
49
- RetrySettings
50
- }
51
-
47
+ // request is an abstraction of an individual request (batch of data) independent of the type of the data (traces, metrics, logs).
52
48
type request interface {
49
+ // context returns the Context of the requests.
53
50
context () context.Context
51
+ // setContext updates the Context of the requests.
54
52
setContext (context.Context )
55
53
export (ctx context.Context ) (int , error )
56
- // Returns a new queue request that contains the items left to be exported .
54
+ // Returns a new request that contains the items left to be sent .
57
55
onPartialError (consumererror.PartialError ) request
58
- // Returns the cnt of spans/metric points or log records.
56
+ // Returns the count of spans/metric points or log records.
59
57
count () int
60
58
}
61
59
60
+ // requestSender is an abstraction of a sender for a request independent of the type of the data (traces, metrics, logs).
62
61
type requestSender interface {
63
62
send (req request ) (int , error )
64
63
}
65
64
65
+ // baseRequest is a base implementation for the request.
66
66
type baseRequest struct {
67
67
ctx context.Context
68
68
}
@@ -81,139 +81,151 @@ type Start func(context.Context, component.Host) error
81
81
// Shutdown specifies the function invoked when the exporter is being shutdown.
82
82
type Shutdown func (context.Context ) error
83
83
84
+ // internalOptions represents all the options that users can configure.
85
+ type internalOptions struct {
86
+ TimeoutSettings
87
+ QueueSettings
88
+ RetrySettings
89
+ Start
90
+ Shutdown
91
+ }
92
+
93
+ // fromConfiguredOptions returns the internal options starting from the default and applying all configured options.
94
+ func fromConfiguredOptions (options ... ExporterOption ) * internalOptions {
95
+ // Start from the default options:
96
+ opts := & internalOptions {
97
+ TimeoutSettings : CreateDefaultTimeoutSettings (),
98
+ // TODO: Enable queuing by default (call CreateDefaultQueueSettings)
99
+ QueueSettings : QueueSettings {Disabled : true },
100
+ // TODO: Enable retry by default (call CreateDefaultRetrySettings)
101
+ RetrySettings : RetrySettings {Disabled : true },
102
+ Start : func (ctx context.Context , host component.Host ) error { return nil },
103
+ Shutdown : func (ctx context.Context ) error { return nil },
104
+ }
105
+
106
+ for _ , op := range options {
107
+ op (opts )
108
+ }
109
+
110
+ return opts
111
+ }
112
+
84
113
// ExporterOption apply changes to internalOptions.
85
- type ExporterOption func (* baseExporter )
114
+ type ExporterOption func (* internalOptions )
86
115
87
116
// WithShutdown overrides the default Shutdown function for an exporter.
88
117
// The default shutdown function does nothing and always returns nil.
89
118
func WithShutdown (shutdown Shutdown ) ExporterOption {
90
- return func (o * baseExporter ) {
91
- o .shutdown = shutdown
119
+ return func (o * internalOptions ) {
120
+ o .Shutdown = shutdown
92
121
}
93
122
}
94
123
95
124
// WithStart overrides the default Start function for an exporter.
96
125
// The default shutdown function does nothing and always returns nil.
97
126
func WithStart (start Start ) ExporterOption {
98
- return func (o * baseExporter ) {
99
- o .start = start
127
+ return func (o * internalOptions ) {
128
+ o .Start = start
100
129
}
101
130
}
102
131
103
- // WithShutdown overrides the default TimeoutSettings for an exporter.
132
+ // WithTimeout overrides the default TimeoutSettings for an exporter.
104
133
// The default TimeoutSettings is 5 seconds.
105
- func WithTimeout (timeout TimeoutSettings ) ExporterOption {
106
- return func (o * baseExporter ) {
107
- o .cfg . TimeoutSettings = timeout
134
+ func WithTimeout (timeoutSettings TimeoutSettings ) ExporterOption {
135
+ return func (o * internalOptions ) {
136
+ o .TimeoutSettings = timeoutSettings
108
137
}
109
138
}
110
139
111
140
// WithRetry overrides the default RetrySettings for an exporter.
112
141
// The default RetrySettings is to disable retries.
113
- func WithRetry (retry RetrySettings ) ExporterOption {
114
- return func (o * baseExporter ) {
115
- o .cfg . RetrySettings = retry
142
+ func WithRetry (retrySettings RetrySettings ) ExporterOption {
143
+ return func (o * internalOptions ) {
144
+ o .RetrySettings = retrySettings
116
145
}
117
146
}
118
147
119
- // WithQueued overrides the default QueuedSettings for an exporter.
120
- // The default QueuedSettings is to disable queueing.
121
- func WithQueued ( queued QueuedSettings ) ExporterOption {
122
- return func (o * baseExporter ) {
123
- o .cfg . QueuedSettings = queued
148
+ // WithQueue overrides the default QueueSettings for an exporter.
149
+ // The default QueueSettings is to disable queueing.
150
+ func WithQueue ( queueSettings QueueSettings ) ExporterOption {
151
+ return func (o * internalOptions ) {
152
+ o .QueueSettings = queueSettings
124
153
}
125
154
}
126
155
127
- // internalOptions contains internalOptions concerning how an Exporter is configured .
156
+ // baseExporter contains common fields between different exporter types .
128
157
type baseExporter struct {
129
- cfg * settings
158
+ cfg configmodels. Exporter
130
159
sender requestSender
131
- rSender * retrySender
132
- qSender * queuedSender
160
+ qrSender * queuedRetrySender
133
161
start Start
134
162
shutdown Shutdown
135
163
startOnce sync.Once
136
164
shutdownOnce sync.Once
137
165
}
138
166
139
- // Construct the internalOptions from multiple ExporterOption.
140
167
func newBaseExporter (cfg configmodels.Exporter , options ... ExporterOption ) * baseExporter {
168
+ opts := fromConfiguredOptions (options ... )
141
169
be := & baseExporter {
142
- cfg : & settings {
143
- Exporter : cfg ,
144
- TimeoutSettings : CreateDefaultTimeoutSettings (),
145
- // TODO: Enable queuing by default (call CreateDefaultQueuedSettings
146
- QueuedSettings : QueuedSettings {Disabled : true },
147
- // TODO: Enable retry by default (call CreateDefaultRetrySettings)
148
- RetrySettings : RetrySettings {Disabled : true },
149
- },
170
+ cfg : cfg ,
171
+ start : opts .Start ,
172
+ shutdown : opts .Shutdown ,
150
173
}
151
174
152
- for _ , op := range options {
153
- op (be )
154
- }
155
-
156
- if be .start == nil {
157
- be .start = func (ctx context.Context , host component.Host ) error { return nil }
158
- }
159
-
160
- if be .shutdown == nil {
161
- be .shutdown = func (ctx context.Context ) error { return nil }
162
- }
163
-
164
- be .sender = & timeoutSender {cfg : & be .cfg .TimeoutSettings }
165
-
166
- be .rSender = newRetrySender (& be .cfg .RetrySettings , be .sender )
167
- be .sender = be .rSender
168
-
169
- be .qSender = newQueuedSender (& be .cfg .QueuedSettings , be .sender )
170
- be .sender = be .qSender
175
+ be .qrSender = newQueuedRetrySender (opts .QueueSettings , opts .RetrySettings , & timeoutSender {cfg : opts .TimeoutSettings })
176
+ be .sender = be .qrSender
171
177
172
178
return be
173
179
}
174
180
181
+ // wrapConsumerSender wraps the consumer sender (the sender that uses retries and timeout) with the given wrapper.
182
+ // This can be used to wrap with observability (create spans, record metrics) the consumer sender.
183
+ func (be * baseExporter ) wrapConsumerSender (f func (consumer requestSender ) requestSender ) {
184
+ be .qrSender .consumerSender = f (be .qrSender .consumerSender )
185
+ }
186
+
187
+ // Start all senders and exporter and is invoked during service start.
175
188
func (be * baseExporter ) Start (ctx context.Context , host component.Host ) error {
176
189
err := componenterror .ErrAlreadyStarted
177
190
be .startOnce .Do (func () {
178
- // First start the nextSender
191
+ // First start the wrapped exporter.
179
192
err = be .start (ctx , host )
180
193
if err != nil {
194
+ // TODO: Log errors, or check if it is recorded by the caller.
181
195
return
182
196
}
183
197
184
- // If no error then start the queuedSender
185
- be .qSender .start ()
198
+ // If no error then start the queuedRetrySender.
199
+ be .qrSender .start ()
186
200
})
187
201
return err
188
202
}
189
203
190
- // Shutdown stops the nextSender and is invoked during shutdown.
204
+ // Shutdown all senders and exporter and is invoked during service shutdown.
191
205
func (be * baseExporter ) Shutdown (ctx context.Context ) error {
192
206
err := componenterror .ErrAlreadyStopped
193
207
be .shutdownOnce .Do (func () {
194
- // First stop the retry goroutines
195
- be .rSender .shutdown ()
196
-
197
- // All operations will try to export once but will not retry because retrying was disabled when be.rSender stopped.
198
- be .qSender .shutdown ()
199
-
200
- // Last shutdown the nextSender itself.
208
+ // First shutdown the queued retry sender
209
+ be .qrSender .shutdown ()
210
+ // Last shutdown the wrapped exporter itself.
201
211
err = be .shutdown (ctx )
202
212
})
203
213
return err
204
214
}
205
215
216
+ // timeoutSender is a request sender that adds a `timeout` to every request that passes this sender.
206
217
type timeoutSender struct {
207
- cfg * TimeoutSettings
218
+ cfg TimeoutSettings
208
219
}
209
220
210
- func (te * timeoutSender ) send (req request ) (int , error ) {
221
+ // send implements the requestSender interface
222
+ func (ts * timeoutSender ) send (req request ) (int , error ) {
211
223
// Intentionally don't overwrite the context inside the request, because in case of retries deadline will not be
212
224
// updated because this deadline most likely is before the next one.
213
225
ctx := req .context ()
214
- if te .cfg .Timeout > 0 {
226
+ if ts .cfg .Timeout > 0 {
215
227
var cancelFunc func ()
216
- ctx , cancelFunc = context .WithTimeout (req .context (), te .cfg .Timeout )
228
+ ctx , cancelFunc = context .WithTimeout (req .context (), ts .cfg .Timeout )
217
229
defer cancelFunc ()
218
230
}
219
231
return req .export (ctx )
0 commit comments