package trace import ( "context" "fmt" "contrib.go.opencensus.io/exporter/jaeger" ocZipkin "contrib.go.opencensus.io/exporter/zipkin" "github.com/openzipkin/zipkin-go" zipkinHTTP "github.com/openzipkin/zipkin-go/reporter/http" "go.opencensus.io/trace" "github.com/pomerium/pomerium/internal/log" ) const ( // JaegerTracingProviderName is the name of the tracing provider Jaeger. JaegerTracingProviderName = "jaeger" // ZipkinTracingProviderName is the name of the tracing provider Zipkin. ZipkinTracingProviderName = "zipkin" ) // TracingOptions contains the configurations settings for a http server. type TracingOptions struct { // Shared Provider string Service string Debug bool // Jaeger // CollectorEndpoint is the full url to the Jaeger HTTP Thrift collector. // For example, http://localhost:14268/api/traces JaegerCollectorEndpoint string `mapstructure:"tracing_jaeger_collector_endpoint"` // AgentEndpoint instructs exporter to send spans to jaeger-agent at this address. // For example, localhost:6831. JaegerAgentEndpoint string `mapstructure:"tracing_jaeger_agent_endpoint"` // Zipkin // ZipkinEndpoint configures the zipkin collector URI // Example: http://zipkin:9411/api/v2/spans ZipkinEndpoint string `mapstructure:"tracing_zipkin_endpoint"` } // RegisterTracing creates a new trace exporter from TracingOptions. func RegisterTracing(opts *TracingOptions) error { var err error switch opts.Provider { case JaegerTracingProviderName: err = registerJaeger(opts) case ZipkinTracingProviderName: err = registerZipkin(opts) default: return fmt.Errorf("telemetry/trace: provider %s unknown", opts.Provider) } if err != nil { return err } if opts.Debug { log.Debug().Msg("telemetry/trace: debug on, sample everything") trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) } log.Debug().Interface("Opts", opts).Msg("telemetry/trace: exporter created") return nil } func registerJaeger(opts *TracingOptions) error { jex, err := jaeger.NewExporter( jaeger.Options{ AgentEndpoint: opts.JaegerAgentEndpoint, CollectorEndpoint: opts.JaegerCollectorEndpoint, ServiceName: opts.Service, }) if err != nil { return err } trace.RegisterExporter(jex) return nil } func registerZipkin(opts *TracingOptions) error { localEndpoint, err := zipkin.NewEndpoint(opts.Service, "") if err != nil { return fmt.Errorf("telemetry/trace: could not create local endpoint: %w", err) } reporter := zipkinHTTP.NewReporter(opts.ZipkinEndpoint) exporter := ocZipkin.NewExporter(reporter, localEndpoint) trace.RegisterExporter(exporter) return nil } // StartSpan starts a new child span of the current span in the context. If // there is no span in the context, creates a new trace and span. // // Returned context contains the newly created span. You can use it to // propagate the returned span in process. func StartSpan(ctx context.Context, name string, o ...trace.StartOption) (context.Context, *trace.Span) { return trace.StartSpan(ctx, name, o...) }