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.Error(ctx).Err(err).Msg("trace: failed to build tracing options")
		return
	}
	if reflect.DeepEqual(traceOpts, mgr.traceOpts) {
		log.Debug(ctx).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.Info(ctx).Interface("options", traceOpts).Msg("trace: starting exporter")
	mgr.provider, err = trace.GetProvider(traceOpts)
	if err != nil {
		log.Error(ctx).Err(err).Msg("trace: failed to register exporter")
		return
	}
	err = mgr.provider.Register(traceOpts)
	if err != nil {
		log.Error(ctx).Err(err).Msg("trace: failed to register exporter")
		return
	}
}
OnConfigChange updates the manager whenever the configuration is changed.
package config
import (
	"context"
	"fmt"
	"reflect"
	"sync"
	"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"
	"github.com/rs/zerolog"
)
type TracingOptions = trace.TracingOptions
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.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
}
type TraceManager struct {
	mu        sync.Mutex
	traceOpts *TracingOptions
	provider  trace.Provider
}
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
}
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
}