pomerium/config/trace.go
Joe Kralicky 6502d68162
config: set default tracing sample rate to 1.0 (#5422)
The previous default sample rate of 0.0001 is very low, so traces are
unlikely to be visible after enabling them until many thousands of
requests have been sent. This could be confusing to users.
2025-01-14 13:50:22 -05:00

129 lines
3.5 KiB
Go

package config
import (
"context"
"fmt"
"reflect"
"sync"
"github.com/rs/zerolog"
"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) {
sampleRate := 1.0
if o.TracingSampleRate != nil {
sampleRate = *o.TracingSampleRate
}
tracingOpts := TracingOptions{
Provider: o.TracingProvider,
Service: telemetry.ServiceName(o.Services),
JaegerAgentEndpoint: o.TracingJaegerAgentEndpoint,
SampleRate: sampleRate,
}
switch o.TracingProvider {
case trace.DatadogTracingProviderName:
tracingOpts.DatadogAddress = o.TracingDatadogAddress
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
provider trace.Provider
}
// NewTraceManager creates a new TraceManager.
func NewTraceManager(ctx context.Context, src Source) *TraceManager {
ctx = log.WithContext(ctx, func(c zerolog.Context) zerolog.Context {
return c.Str("service", "trace_manager")
})
mgr := &TraceManager{}
src.OnConfigChange(ctx, mgr.OnConfigChange)
mgr.OnConfigChange(ctx, src.GetConfig())
return mgr
}
// Close closes any underlying trace exporter.
func (mgr *TraceManager) Close() error {
mgr.mu.Lock()
defer mgr.mu.Unlock()
var err error
if mgr.provider != nil {
err = mgr.provider.Unregister()
}
return err
}
// OnConfigChange updates the manager whenever the configuration is changed.
func (mgr *TraceManager) OnConfigChange(ctx context.Context, cfg *Config) {
mgr.mu.Lock()
defer mgr.mu.Unlock()
traceOpts, err := NewTracingOptions(cfg.Options)
if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("trace: failed to build tracing options")
return
}
if reflect.DeepEqual(traceOpts, mgr.traceOpts) {
log.Ctx(ctx).Debug().Msg("no change detected in trace options")
return
}
mgr.traceOpts = traceOpts
if mgr.provider != nil {
_ = mgr.provider.Unregister()
mgr.provider = nil
}
if !traceOpts.Enabled() {
return
}
log.Ctx(ctx).Info().Interface("options", traceOpts).Msg("trace: starting exporter")
mgr.provider, err = trace.GetProvider(traceOpts)
if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("trace: failed to register exporter")
return
}
err = mgr.provider.Register(traceOpts)
if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("trace: failed to register exporter")
return
}
}