pomerium/config/trace.go
Caleb Doxsey f822c9a5d2
config: allow reloading of telemetry settings (#1255)
* metrics: support dynamic configuration settings

* add test

* trace: update configuration when settings change

* config: allow logging options to be configured when settings change

* envoy: allow changing log settings

* fix unexpected doc change

* fix tests

* pick a port at random

* update based on review
2020-08-12 08:14:15 -06:00

112 lines
3 KiB
Go

package config
import (
"fmt"
"reflect"
"sync"
octrace "go.opencensus.io/trace"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/telemetry"
"github.com/pomerium/pomerium/internal/telemetry/trace"
"github.com/pomerium/pomerium/internal/urlutil"
)
// TracingOptions are the options for tracing.
type TracingOptions = trace.TracingOptions
// NewTracingOptions builds a new TracingOptions from core Options
func NewTracingOptions(o *Options) (*TracingOptions, error) {
tracingOpts := TracingOptions{
Provider: o.TracingProvider,
Service: telemetry.ServiceName(o.Services),
JaegerAgentEndpoint: o.TracingJaegerAgentEndpoint,
SampleRate: o.TracingSampleRate,
}
switch o.TracingProvider {
case trace.JaegerTracingProviderName:
if o.TracingJaegerCollectorEndpoint != "" {
jaegerCollectorEndpoint, err := urlutil.ParseAndValidateURL(o.TracingJaegerCollectorEndpoint)
if err != nil {
return nil, fmt.Errorf("config: invalid jaeger endpoint url: %w", err)
}
tracingOpts.JaegerCollectorEndpoint = jaegerCollectorEndpoint
tracingOpts.JaegerAgentEndpoint = o.TracingJaegerAgentEndpoint
}
case trace.ZipkinTracingProviderName:
zipkinEndpoint, err := urlutil.ParseAndValidateURL(o.ZipkinEndpoint)
if err != nil {
return nil, fmt.Errorf("config: invalid zipkin endpoint url: %w", err)
}
tracingOpts.ZipkinEndpoint = zipkinEndpoint
case "":
return &TracingOptions{}, nil
default:
return nil, fmt.Errorf("config: provider %s unknown", o.TracingProvider)
}
return &tracingOpts, nil
}
// A TraceManager manages setting up a trace exporter based on configuration options.
type TraceManager struct {
mu sync.Mutex
traceOpts *TracingOptions
exporter octrace.Exporter
}
// NewTraceManager creates a new TraceManager.
func NewTraceManager(src Source) *TraceManager {
mgr := &TraceManager{}
src.OnConfigChange(mgr.OnConfigChange)
mgr.OnConfigChange(src.GetConfig())
return mgr
}
// Close closes any underlying trace exporter.
func (mgr *TraceManager) Close() error {
mgr.mu.Lock()
defer mgr.mu.Unlock()
if mgr.exporter != nil {
trace.UnregisterTracing(mgr.exporter)
}
return nil
}
// OnConfigChange updates the manager whenever the configuration is changed.
func (mgr *TraceManager) OnConfigChange(cfg *Config) {
mgr.mu.Lock()
defer mgr.mu.Unlock()
traceOpts, err := NewTracingOptions(cfg.Options)
if err != nil {
log.Error().Err(err).Msg("trace: failed to build tracing options")
return
}
if reflect.DeepEqual(traceOpts, mgr.traceOpts) {
log.Debug().Msg("no change detected in trace options")
return
}
mgr.traceOpts = traceOpts
if mgr.exporter != nil {
trace.UnregisterTracing(mgr.exporter)
mgr.exporter = nil
}
if !traceOpts.Enabled() {
return
}
log.Info().Interface("options", traceOpts).Msg("trace: starting exporter")
mgr.exporter, err = trace.RegisterTracing(traceOpts)
if err != nil {
log.Error().Err(err).Msg("trace: failed to register exporter")
return
}
}