@@ -26,25 +26,33 @@ import (
2626 "github.com/open-telemetry/opentelemetry-collector/observability"
2727)
2828
29- // PushTraceData is a helper function that is similar to ConsumeTraceData but also returns
30- // the number of dropped spans.
31- type PushTraceData func (ctx context.Context , td consumerdata.TraceData ) (droppedSpans int , err error )
29+ // Suffix to use for span names emitted by exporter for observability purposes.
30+ const spanNameSuffix = ".ExportTraceData"
3231
32+ // traceDataPusher is a helper function that is similar to ConsumeTraceData but also
33+ // returns the number of dropped spans.
34+ type traceDataPusher func (ctx context.Context , td consumerdata.TraceData ) (droppedSpans int , err error )
35+
36+ // otlpTraceDataPusher is a helper function that is similar to ConsumeTraceData but also
37+ // returns the number of dropped spans.
38+ type otlpTraceDataPusher func (ctx context.Context , td consumerdata.OTLPTraceData ) (droppedSpans int , err error )
39+
40+ // traceExporter implements the exporter with additional helper options.
3341type traceExporter struct {
3442 exporterFullName string
35- pushTraceData PushTraceData
43+ dataPusher traceDataPusher
3644 shutdown Shutdown
3745}
3846
39- var _ ( exporter.TraceExporter ) = (* traceExporter )(nil )
47+ var _ exporter.TraceExporter = (* traceExporter )(nil )
4048
4149func (te * traceExporter ) Start (host component.Host ) error {
4250 return nil
4351}
4452
4553func (te * traceExporter ) ConsumeTraceData (ctx context.Context , td consumerdata.TraceData ) error {
4654 exporterCtx := observability .ContextWithExporterName (ctx , te .exporterFullName )
47- _ , err := te .pushTraceData (exporterCtx , td )
55+ _ , err := te .dataPusher (exporterCtx , td )
4856 return err
4957}
5058
@@ -53,28 +61,34 @@ func (te *traceExporter) Shutdown() error {
5361 return te .shutdown ()
5462}
5563
56- // NewTraceExporter creates an TraceExporter that can record metrics and can wrap every request with a Span.
57- // If no options are passed it just adds the exporter format as a tag in the Context.
58- // TODO: Add support for retries.
59- func NewTraceExporter (config configmodels.Exporter , pushTraceData PushTraceData , options ... ExporterOption ) (exporter.TraceExporter , error ) {
64+ // NewTraceExporter creates an TraceExporter that can record metrics and can wrap every
65+ // request with a Span. If no options are passed it just adds the exporter format as a
66+ // tag in the Context.
67+ func NewTraceExporter (
68+ config configmodels.Exporter ,
69+ dataPusher traceDataPusher ,
70+ options ... ExporterOption ,
71+ ) (exporter.TraceExporter , error ) {
72+
6073 if config == nil {
6174 return nil , errNilConfig
6275 }
6376
64- if pushTraceData == nil {
77+ if dataPusher == nil {
6578 return nil , errNilPushTraceData
6679 }
6780
6881 opts := newExporterOptions (options ... )
6982 if opts .recordMetrics {
70- pushTraceData = pushTraceDataWithMetrics ( pushTraceData )
83+ dataPusher = dataPusher . withMetrics ( )
7184 }
7285
7386 if opts .recordTrace {
74- pushTraceData = pushTraceDataWithSpan (pushTraceData , config .Name ()+ ".ExportTraceData" )
87+ spanName := config .Name () + spanNameSuffix
88+ dataPusher = dataPusher .withSpan (spanName )
7589 }
7690
77- // The default shutdown function returns nil .
91+ // The default shutdown function does nothing .
7892 if opts .shutdown == nil {
7993 opts .shutdown = func () error {
8094 return nil
@@ -83,27 +97,31 @@ func NewTraceExporter(config configmodels.Exporter, pushTraceData PushTraceData,
8397
8498 return & traceExporter {
8599 exporterFullName : config .Name (),
86- pushTraceData : pushTraceData ,
100+ dataPusher : dataPusher ,
87101 shutdown : opts .shutdown ,
88102 }, nil
89103}
90104
91- func pushTraceDataWithMetrics (next PushTraceData ) PushTraceData {
105+ // withMetrics wraps the current pusher into a function that records the metrics of the
106+ // pusher execution.
107+ func (p traceDataPusher ) withMetrics () traceDataPusher {
92108 return func (ctx context.Context , td consumerdata.TraceData ) (int , error ) {
93- // TODO: Add retry logic here if we want to support because we need to record special metrics .
94- droppedSpans , err := next (ctx , td )
109+ // Forward the data to the next consumer (this pusher is the next) .
110+ droppedSpans , err := p (ctx , td )
95111 // TODO: How to record the reason of dropping?
96112 observability .RecordMetricsForTraceExporter (ctx , len (td .Spans ), droppedSpans )
97113 return droppedSpans , err
98114 }
99115}
100116
101- func pushTraceDataWithSpan (next PushTraceData , spanName string ) PushTraceData {
117+ // withSpan wraps the current pusher into a function that records a span during
118+ // pusher execution.
119+ func (p traceDataPusher ) withSpan (spanName string ) traceDataPusher {
102120 return func (ctx context.Context , td consumerdata.TraceData ) (int , error ) {
103121 ctx , span := trace .StartSpan (ctx , spanName )
104122 defer span .End ()
105- // Call next stage .
106- droppedSpans , err := next (ctx , td )
123+ // Forward the data to the next consumer (this pusher is the next) .
124+ droppedSpans , err := p (ctx , td )
107125 if span .IsRecordingEvents () {
108126 span .AddAttributes (
109127 trace .Int64Attribute (numReceivedSpansAttribute , int64 (len (td .Spans ))),
@@ -116,3 +134,108 @@ func pushTraceDataWithSpan(next PushTraceData, spanName string) PushTraceData {
116134 return droppedSpans , err
117135 }
118136}
137+
138+ type otlpTraceExporter struct {
139+ exporterFullName string
140+ dataPusher otlpTraceDataPusher
141+ shutdown Shutdown
142+ }
143+
144+ var _ exporter.OTLPTraceExporter = (* otlpTraceExporter )(nil )
145+
146+ func (te * otlpTraceExporter ) Start (host component.Host ) error {
147+ return nil
148+ }
149+
150+ func (te * otlpTraceExporter ) ConsumeOTLPTrace (
151+ ctx context.Context ,
152+ td consumerdata.OTLPTraceData ,
153+ ) error {
154+ exporterCtx := observability .ContextWithExporterName (ctx , te .exporterFullName )
155+ _ , err := te .dataPusher (exporterCtx , td )
156+ return err
157+ }
158+
159+ // Shutdown stops the exporter and is invoked during shutdown.
160+ func (te * otlpTraceExporter ) Shutdown () error {
161+ return te .shutdown ()
162+ }
163+
164+ // NewOTLPTraceExporter creates an OTLPTraceExporter that can record metrics and can wrap
165+ // every request with a Span.
166+ func NewOTLPTraceExporter (
167+ config configmodels.Exporter ,
168+ dataPusher otlpTraceDataPusher ,
169+ options ... ExporterOption ,
170+ ) (exporter.OTLPTraceExporter , error ) {
171+
172+ if config == nil {
173+ return nil , errNilConfig
174+ }
175+
176+ if dataPusher == nil {
177+ return nil , errNilPushTraceData
178+ }
179+
180+ opts := newExporterOptions (options ... )
181+ if opts .recordMetrics {
182+ dataPusher = dataPusher .withMetrics ()
183+ }
184+
185+ if opts .recordTrace {
186+ spanName := config .Name () + spanNameSuffix
187+ dataPusher = dataPusher .withSpan (spanName )
188+ }
189+
190+ // The default shutdown function does nothing.
191+ if opts .shutdown == nil {
192+ opts .shutdown = func () error {
193+ return nil
194+ }
195+ }
196+
197+ return & otlpTraceExporter {
198+ exporterFullName : config .Name (),
199+ dataPusher : dataPusher ,
200+ shutdown : opts .shutdown ,
201+ }, nil
202+ }
203+
204+ // withMetrics wraps the current pusher into a function that records the metrics of the
205+ // pusher execution.
206+ func (p otlpTraceDataPusher ) withMetrics () otlpTraceDataPusher {
207+ return func (ctx context.Context , td consumerdata.OTLPTraceData ) (int , error ) {
208+ // Forward the data to the next consumer (this pusher is the next).
209+ droppedSpans , err := p (ctx , td )
210+
211+ // Record the results as metrics.
212+ observability .RecordMetricsForTraceExporter (ctx , td .SpanCount (), droppedSpans )
213+
214+ return droppedSpans , err
215+ }
216+ }
217+
218+ // withSpan wraps the current pusher into a function that records a span during
219+ // pusher execution.
220+ func (p otlpTraceDataPusher ) withSpan (spanName string ) otlpTraceDataPusher {
221+ return func (ctx context.Context , td consumerdata.OTLPTraceData ) (int , error ) {
222+ // Start a span.
223+ ctx , span := trace .StartSpan (ctx , spanName )
224+
225+ // End the span after this function is done.
226+ defer span .End ()
227+
228+ // Forward the data to the next consumer (this pusher is the next).
229+ droppedSpans , err := p (ctx , td )
230+ if span .IsRecordingEvents () {
231+ span .AddAttributes (
232+ trace .Int64Attribute (numReceivedSpansAttribute , int64 (td .SpanCount ())),
233+ trace .Int64Attribute (numDroppedSpansAttribute , int64 (droppedSpans )),
234+ )
235+ if err != nil {
236+ span .SetStatus (errToStatus (err ))
237+ }
238+ }
239+ return droppedSpans , err
240+ }
241+ }
0 commit comments