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	export "go.opentelemetry.io/otel/sdk/export/trace"
23)
24
25// simpleSpanProcessor is a SpanProcessor that synchronously sends all
26// completed Spans to a trace.Exporter immediately.
27type simpleSpanProcessor struct {
28	exporterMu sync.RWMutex
29	exporter   export.SpanExporter
30	stopOnce   sync.Once
31}
32
33var _ SpanProcessor = (*simpleSpanProcessor)(nil)
34
35// NewSimpleSpanProcessor returns a new SpanProcessor that will synchronously
36// send completed spans to the exporter immediately.
37func NewSimpleSpanProcessor(exporter export.SpanExporter) SpanProcessor {
38	ssp := &simpleSpanProcessor{
39		exporter: exporter,
40	}
41	return ssp
42}
43
44// OnStart does nothing.
45func (ssp *simpleSpanProcessor) OnStart(context.Context, ReadWriteSpan) {}
46
47// OnEnd immediately exports a ReadOnlySpan.
48func (ssp *simpleSpanProcessor) OnEnd(s ReadOnlySpan) {
49	ssp.exporterMu.RLock()
50	defer ssp.exporterMu.RUnlock()
51
52	if ssp.exporter != nil && s.SpanContext().IsSampled() {
53		ss := s.Snapshot()
54		if err := ssp.exporter.ExportSpans(context.Background(), []*export.SpanSnapshot{ss}); err != nil {
55			otel.Handle(err)
56		}
57	}
58}
59
60// Shutdown shuts down the exporter this SimpleSpanProcessor exports to.
61func (ssp *simpleSpanProcessor) Shutdown(ctx context.Context) error {
62	var err error
63	ssp.stopOnce.Do(func() {
64		ssp.exporterMu.Lock()
65		exporter := ssp.exporter
66		// Set exporter to nil so subsequent calls to OnEnd are ignored
67		// gracefully.
68		ssp.exporter = nil
69		ssp.exporterMu.Unlock()
70
71		// Clear the ssp.exporter prior to shutting it down so if that creates
72		// a span that needs to be exported there is no deadlock.
73		err = exporter.Shutdown(ctx)
74	})
75	return err
76}
77
78// ForceFlush does nothing as there is no data to flush.
79func (ssp *simpleSpanProcessor) ForceFlush(context.Context) error {
80	return nil
81}
82