opentelemetry-collector/exporter/exporterhelper/tracehelper.go

122 lines
3.5 KiB
Go

// Copyright The 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.uber.org/zap"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/config/configtelemetry"
"go.opentelemetry.io/collector/consumer/consumererror"
"go.opentelemetry.io/collector/consumer/pdata"
"go.opentelemetry.io/collector/obsreport"
)
// traceDataPusher is a helper function that is similar to ConsumeTraceData but also
// returns the number of dropped spans.
type traceDataPusher func(ctx context.Context, td pdata.Traces) (droppedSpans int, err error)
type tracesRequest struct {
baseRequest
td pdata.Traces
pusher traceDataPusher
}
func newTracesRequest(ctx context.Context, td pdata.Traces, pusher traceDataPusher) request {
return &tracesRequest{
baseRequest: baseRequest{ctx: ctx},
td: td,
pusher: pusher,
}
}
func (req *tracesRequest) onPartialError(partialErr consumererror.PartialError) request {
return newTracesRequest(req.ctx, partialErr.GetTraces(), req.pusher)
}
func (req *tracesRequest) export(ctx context.Context) (int, error) {
return req.pusher(ctx, req.td)
}
func (req *tracesRequest) count() int {
return req.td.SpanCount()
}
type traceExporter struct {
*baseExporter
pusher traceDataPusher
}
func (texp *traceExporter) ConsumeTraces(ctx context.Context, td pdata.Traces) error {
exporterCtx := obsreport.ExporterContext(ctx, texp.cfg.Name())
req := newTracesRequest(exporterCtx, td, texp.pusher)
_, err := texp.sender.send(req)
return err
}
// NewTraceExporter creates a TracesExporter that records observability metrics and wraps every request with a Span.
func NewTraceExporter(
cfg configmodels.Exporter,
logger *zap.Logger,
dataPusher traceDataPusher,
options ...Option,
) (component.TracesExporter, error) {
if cfg == nil {
return nil, errNilConfig
}
if logger == nil {
return nil, errNilLogger
}
if dataPusher == nil {
return nil, errNilPushTraceData
}
be := newBaseExporter(cfg, logger, options...)
be.wrapConsumerSender(func(nextSender requestSender) requestSender {
return &tracesExporterWithObservability{
obsrep: obsreport.NewExporterObsReport(configtelemetry.GetMetricsLevelFlagValue(), cfg.Name()),
nextSender: nextSender,
}
})
return &traceExporter{
baseExporter: be,
pusher: dataPusher,
}, nil
}
type tracesExporterWithObservability struct {
obsrep *obsreport.ExporterObsReport
nextSender requestSender
}
func (tewo *tracesExporterWithObservability) send(req request) (int, error) {
req.setContext(tewo.obsrep.StartTracesExportOp(req.context()))
// Forward the data to the next consumer (this pusher is the next).
droppedSpans, err := tewo.nextSender.send(req)
// TODO: this is not ideal: it should come from the next function itself.
// temporarily loading it from internal format. Once full switch is done
// to new metrics will remove this.
tewo.obsrep.EndTracesExportOp(req.context(), req.count(), err)
return droppedSpans, err
}