-
Notifications
You must be signed in to change notification settings - Fork 435
/
tracer_provider.go
117 lines (106 loc) · 4.44 KB
/
tracer_provider.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2023 Datadog, Inc.
// Package opentelemetry provides a wrapper on top of the Datadog tracer that can be used with OpenTelemetry.
// This feature is currently in beta.
// It also provides a wrapper around TracerProvider to propagate a list of tracer.StartOption
// that are specific to Datadog's APM product. To use it, simply call "NewTracerProvider".
//
// provider := opentelemetry.NewTracerProvider(tracer.WithService("opentelemetry_service"))
//
// When using Datadog, the OpenTelemetry span name is what is called operation name in Datadog's terms.
// Below is an example setting the tracer provider, initializing a tracer, and creating a span.
//
// otel.SetTracerProvider(opentelemetry.NewTracerProvider())
// tracer := otel.Tracer("")
// ctx, sp := tracer.Start(context.Background(), "span_name")
// yourCode(ctx)
// sp.End()
//
// Not every feature provided by OpenTelemetry is supported with this wrapper today, and any new API methods
// added to the OpenTelemetry API will default to being a no-op until implemented by this library. See the
// OpenTelemetry package docs for more details: https://pkg.go.dev/go.opentelemetry.io/otel/trace#hdr-API_Implementations.
// This package seeks to implement a minimal set of functions within
// the OpenTelemetry Tracing API (https://opentelemetry.io/docs/reference/specification/trace/api)
// to allow users to send traces to Datadog using existing OpenTelemetry code with minimal changes to the application.
// Span events (https://opentelemetry.io/docs/concepts/signals/traces/#span-events) are not supported at this time.
package opentelemetry
import (
"sync"
"sync/atomic"
"time"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/internal"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
"gopkg.in/DataDog/dd-trace-go.v1/internal/log"
oteltrace "go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/noop"
)
var _ oteltrace.TracerProvider = (*TracerProvider)(nil)
// TracerProvider provides implementation of OpenTelemetry TracerProvider interface.
// TracerProvider provides Tracers that are used by instrumentation code to
// trace computational workflows.
// WithInstrumentationVersion and WithSchemaURL TracerOptions are not supported.
type TracerProvider struct {
noop.TracerProvider // https://pkg.go.dev/go.opentelemetry.io/otel/trace#hdr-API_Implementations
tracer *oteltracer
stopped uint32 // stopped indicates whether the tracerProvider has been shutdown.
sync.Once
}
// NewTracerProvider returns an instance of an OpenTelemetry TracerProvider,
// and initializes the Datadog Tracer with the provided start options.
// This TracerProvider only supports a singleton tracer, and repeated calls to
// the Tracer() method will return the same instance each time.
func NewTracerProvider(opts ...tracer.StartOption) *TracerProvider {
tracer.Start(opts...)
p := &TracerProvider{}
t := &oteltracer{
DD: internal.GetGlobalTracer(),
provider: p,
}
p.tracer = t
return p
}
// Tracer returns the singleton tracer created when NewTracerProvider was called, ignoring
// the provided name and any provided options to this method.
// If the TracerProvider has already been shut down, this will return a no-op tracer.
func (p *TracerProvider) Tracer(_ string, _ ...oteltrace.TracerOption) oteltrace.Tracer {
if atomic.LoadUint32(&p.stopped) != 0 {
return noop.NewTracerProvider().Tracer("")
}
return p.tracer
}
// Shutdown stops the started tracer. Subsequent calls are valid but become no-op.
func (p *TracerProvider) Shutdown() error {
p.Once.Do(func() {
tracer.Stop()
atomic.StoreUint32(&p.stopped, 1)
})
return nil
}
// ForceFlush flushes any buffered traces. Flush is in effect only if a tracer
// is started.
func (p *TracerProvider) ForceFlush(timeout time.Duration, callback func(ok bool)) {
p.forceFlush(timeout, callback, tracer.Flush)
}
func (p *TracerProvider) forceFlush(timeout time.Duration, callback func(ok bool), flush func()) {
if atomic.LoadUint32(&p.stopped) != 0 {
log.Warn("Cannot perform (*TracerProvider).Flush since the tracer is already stopped.")
return
}
done := make(chan struct{})
go func() {
flush()
done <- struct{}{}
}()
for {
select {
case <-time.After(timeout):
callback(false)
return
case <-done:
callback(true)
return
}
}
}