123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- // 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 trace // import "go.opentelemetry.io/otel/sdk/trace"
- import (
- "context"
- "sync"
- "go.opentelemetry.io/otel"
- )
- // simpleSpanProcessor is a SpanProcessor that synchronously sends all
- // completed Spans to a trace.Exporter immediately.
- type simpleSpanProcessor struct {
- exporterMu sync.RWMutex
- exporter SpanExporter
- stopOnce sync.Once
- }
- var _ SpanProcessor = (*simpleSpanProcessor)(nil)
- // NewSimpleSpanProcessor returns a new SpanProcessor that will synchronously
- // send completed spans to the exporter immediately.
- //
- // This SpanProcessor is not recommended for production use. The synchronous
- // nature of this SpanProcessor make it good for testing, debugging, or
- // showing examples of other feature, but it will be slow and have a high
- // computation resource usage overhead. The BatchSpanProcessor is recommended
- // for production use instead.
- func NewSimpleSpanProcessor(exporter SpanExporter) SpanProcessor {
- ssp := &simpleSpanProcessor{
- exporter: exporter,
- }
- return ssp
- }
- // OnStart does nothing.
- func (ssp *simpleSpanProcessor) OnStart(context.Context, ReadWriteSpan) {}
- // OnEnd immediately exports a ReadOnlySpan.
- func (ssp *simpleSpanProcessor) OnEnd(s ReadOnlySpan) {
- ssp.exporterMu.RLock()
- defer ssp.exporterMu.RUnlock()
- if ssp.exporter != nil && s.SpanContext().TraceFlags().IsSampled() {
- if err := ssp.exporter.ExportSpans(context.Background(), []ReadOnlySpan{s}); err != nil {
- otel.Handle(err)
- }
- }
- }
- // Shutdown shuts down the exporter this SimpleSpanProcessor exports to.
- func (ssp *simpleSpanProcessor) Shutdown(ctx context.Context) error {
- var err error
- ssp.stopOnce.Do(func() {
- stopFunc := func(exp SpanExporter) (<-chan error, func()) {
- done := make(chan error)
- return done, func() { done <- exp.Shutdown(ctx) }
- }
- // The exporter field of the simpleSpanProcessor needs to be zeroed to
- // signal it is shut down, meaning all subsequent calls to OnEnd will
- // be gracefully ignored. This needs to be done synchronously to avoid
- // any race condition.
- //
- // A closure is used to keep reference to the exporter and then the
- // field is zeroed. This ensures the simpleSpanProcessor is shut down
- // before the exporter. This order is important as it avoids a
- // potential deadlock. If the exporter shut down operation generates a
- // span, that span would need to be exported. Meaning, OnEnd would be
- // called and try acquiring the lock that is held here.
- ssp.exporterMu.Lock()
- done, shutdown := stopFunc(ssp.exporter)
- ssp.exporter = nil
- ssp.exporterMu.Unlock()
- go shutdown()
- // Wait for the exporter to shut down or the deadline to expire.
- select {
- case err = <-done:
- case <-ctx.Done():
- // It is possible for the exporter to have immediately shut down
- // and the context to be done simultaneously. In that case this
- // outer select statement will randomly choose a case. This will
- // result in a different returned error for similar scenarios.
- // Instead, double check if the exporter shut down at the same
- // time and return that error if so. This will ensure consistency
- // as well as ensure the caller knows the exporter shut down
- // successfully (they can already determine if the deadline is
- // expired given they passed the context).
- select {
- case err = <-done:
- default:
- err = ctx.Err()
- }
- }
- })
- return err
- }
- // ForceFlush does nothing as there is no data to flush.
- func (ssp *simpleSpanProcessor) ForceFlush(context.Context) error {
- return nil
- }
- // MarshalLog is the marshaling function used by the logging system to represent this Span Processor.
- func (ssp *simpleSpanProcessor) MarshalLog() interface{} {
- return struct {
- Type string
- Exporter SpanExporter
- }{
- Type: "SimpleSpanProcessor",
- Exporter: ssp.exporter,
- }
- }
|