1// Copyright The OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package trace // import "go.opentelemetry.io/otel/sdk/trace"
16
17import (
18	"context"
19	"sync"
20
21	"go.opentelemetry.io/otel"
22)
23
24// simpleSpanProcessor is a SpanProcessor that synchronously sends all
25// completed Spans to a trace.Exporter immediately.
26type simpleSpanProcessor struct {
27	exporterMu sync.RWMutex
28	exporter   SpanExporter
29	stopOnce   sync.Once
30}
31
32var _ SpanProcessor = (*simpleSpanProcessor)(nil)
33
34// NewSimpleSpanProcessor returns a new SpanProcessor that will synchronously
35// send completed spans to the exporter immediately.
36func NewSimpleSpanProcessor(exporter SpanExporter) SpanProcessor {
37	ssp := &simpleSpanProcessor{
38		exporter: exporter,
39	}
40	return ssp
41}
42
43// OnStart does nothing.
44func (ssp *simpleSpanProcessor) OnStart(context.Context, ReadWriteSpan) {}
45
46// OnEnd immediately exports a ReadOnlySpan.
47func (ssp *simpleSpanProcessor) OnEnd(s ReadOnlySpan) {
48	ssp.exporterMu.RLock()
49	defer ssp.exporterMu.RUnlock()
50
51	if ssp.exporter != nil && s.SpanContext().TraceFlags().IsSampled() {
52		ss := s.Snapshot()
53		if err := ssp.exporter.ExportSpans(context.Background(), []*SpanSnapshot{ss}); err != nil {
54			otel.Handle(err)
55		}
56	}
57}
58
59// Shutdown shuts down the exporter this SimpleSpanProcessor exports to.
60func (ssp *simpleSpanProcessor) Shutdown(ctx context.Context) error {
61	var err error
62	ssp.stopOnce.Do(func() {
63		ssp.exporterMu.Lock()
64		exporter := ssp.exporter
65		// Set exporter to nil so subsequent calls to OnEnd are ignored
66		// gracefully.
67		ssp.exporter = nil
68		ssp.exporterMu.Unlock()
69
70		// Clear the ssp.exporter prior to shutting it down so if that creates
71		// a span that needs to be exported there is no deadlock.
72		err = exporter.Shutdown(ctx)
73	})
74	return err
75}
76
77// ForceFlush does nothing as there is no data to flush.
78func (ssp *simpleSpanProcessor) ForceFlush(context.Context) error {
79	return nil
80}
81