forked from knative/pkg
/
opencensus.go
136 lines (111 loc) · 3.16 KB
/
opencensus.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package tracing
import (
"errors"
"sync"
"github.com/knative/pkg/tracing/config"
zipkinmodel "github.com/openzipkin/zipkin-go/model"
zipkinreporter "github.com/openzipkin/zipkin-go/reporter"
"go.opencensus.io/exporter/zipkin"
"go.opencensus.io/trace"
)
// ConfigOption is the interface for adding additional exporters and configuring opencensus tracing.
type ConfigOption func(*config.Config)
// OpenCensusTracer is responsible for managing and updating configuration of OpenCensus tracing
type OpenCensusTracer struct {
curCfg *config.Config
configOptions []ConfigOption
zipkinReporter zipkinreporter.Reporter
zipkinExporter trace.Exporter
}
// OpenCensus tracing keeps state in globals and therefore we can only run one OpenCensusTracer
var (
octMutex sync.Mutex
globalOct *OpenCensusTracer
)
func NewOpenCensusTracer(configOptions ...ConfigOption) *OpenCensusTracer {
return &OpenCensusTracer{
configOptions: configOptions,
}
}
func (oct *OpenCensusTracer) ApplyConfig(cfg *config.Config) error {
err := oct.acquireGlobal()
defer octMutex.Unlock()
if err != nil {
return err
}
// Short circuit if our config hasnt changed
if oct.curCfg != nil && oct.curCfg.Equals(cfg) {
return nil
}
// Apply config options
for _, configOpt := range oct.configOptions {
configOpt(cfg)
}
// Set config
trace.ApplyConfig(*createOCTConfig(cfg))
return nil
}
func (oct *OpenCensusTracer) Finish() error {
err := oct.acquireGlobal()
defer octMutex.Unlock()
if err != nil {
return errors.New("Finish called on OpenTracer which is not the global OpenCensusTracer.")
}
for _, configOpt := range oct.configOptions {
configOpt(nil)
}
globalOct = nil
return nil
}
func (oct *OpenCensusTracer) acquireGlobal() error {
octMutex.Lock()
if globalOct == nil {
globalOct = oct
} else if globalOct != oct {
return errors.New("A OpenCensusTracer already exists and only one can be run at a time.")
}
return nil
}
func createOCTConfig(cfg *config.Config) *trace.Config {
octCfg := trace.Config{}
if cfg.Enable {
if cfg.Debug {
octCfg.DefaultSampler = trace.AlwaysSample()
} else {
octCfg.DefaultSampler = trace.ProbabilitySampler(cfg.SampleRate)
}
} else {
octCfg.DefaultSampler = trace.NeverSample()
}
return &octCfg
}
func WithZipkinExporter(reporterFact ZipkinReporterFactory, endpoint *zipkinmodel.Endpoint) ConfigOption {
return func(cfg *config.Config) {
var (
reporter zipkinreporter.Reporter
exporter trace.Exporter
)
if cfg != nil && cfg.Enable {
// Initialize our reporter / exporter
// do this before cleanup to minimize time where we have duplicate exporters
reporter, err := reporterFact(cfg)
if err != nil {
// TODO(greghaynes) log this error
return
}
exporter := zipkin.NewExporter(reporter, endpoint)
trace.RegisterExporter(exporter)
}
// We know this is set because we are called with acquireGlobal lock held
oct := globalOct
if oct.zipkinExporter != nil {
trace.UnregisterExporter(oct.zipkinExporter)
}
if oct.zipkinReporter != nil {
// TODO(greghaynes) log this error
_ = oct.zipkinReporter.Close()
}
oct.zipkinReporter = reporter
oct.zipkinExporter = exporter
}
}