caching/vendor/knative.dev/pkg/tracing/opencensus.go

137 lines
3.1 KiB
Go

package tracing
import (
"errors"
"sync"
zipkinmodel "github.com/openzipkin/zipkin-go/model"
zipkinreporter "github.com/openzipkin/zipkin-go/reporter"
"go.opencensus.io/exporter/zipkin"
"go.opencensus.io/trace"
"knative.dev/pkg/tracing/config"
)
// 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
}
}