-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from luthersystems/opttrace
Add opttrace package.
- Loading branch information
Showing
3 changed files
with
203 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
package opttrace | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/url" | ||
"strings" | ||
|
||
"go.opentelemetry.io/otel/attribute" | ||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace" | ||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" | ||
"go.opentelemetry.io/otel/sdk/resource" | ||
sdktrace "go.opentelemetry.io/otel/sdk/trace" | ||
"go.opentelemetry.io/otel/trace" | ||
"go.opentelemetry.io/otel/trace/noop" | ||
) | ||
|
||
const tracerName = "opttrace" | ||
|
||
var noopTracerProvider = noop.NewTracerProvider() | ||
|
||
// Tracer provides a tracing interface that generates traces only if configured | ||
// with a trace exporter | ||
type Tracer struct { | ||
exportTP *sdktrace.TracerProvider | ||
} | ||
|
||
// Option provides Tracer configuration options | ||
type Option func(*config) error | ||
|
||
type config struct { | ||
otlpEndpointURI string | ||
sampler sdktrace.Sampler | ||
syncExport bool | ||
batchOpts []sdktrace.BatchSpanProcessorOption | ||
exporter sdktrace.SpanExporter | ||
} | ||
|
||
// WithOTLPExporter configured an OTLP trace exporter | ||
func WithOTLPExporter(endpointURI string) Option { | ||
return func(c *config) error { | ||
c.otlpEndpointURI = endpointURI | ||
return nil | ||
} | ||
} | ||
|
||
// WithSampler sets the sampler to be used by the underlying tracing | ||
// provider. If not set, it takes the default of sampling based on whether the | ||
// parent span was sampled. | ||
func WithSampler(sampler sdktrace.Sampler) Option { | ||
return func(c *config) error { | ||
c.sampler = sampler | ||
return nil | ||
} | ||
} | ||
|
||
// WithBatchOptions allows overriding the default span batch processing options. | ||
func WithBatchOptions(opts []sdktrace.BatchSpanProcessorOption) Option { | ||
return func(c *config) error { | ||
c.batchOpts = opts | ||
return nil | ||
} | ||
} | ||
|
||
// WithSyncExport can be used in tests and disables batch span processing. | ||
func WithSyncExport() Option { | ||
return func(c *config) error { | ||
c.syncExport = true | ||
return nil | ||
} | ||
} | ||
|
||
// WithExporter sets a span exporter other than standard one provided by | ||
// WithOTLPExporter. | ||
func WithExporter(exp sdktrace.SpanExporter) Option { | ||
return func(c *config) error { | ||
c.exporter = exp | ||
return nil | ||
} | ||
} | ||
|
||
// New creates a Tracer that will create spans if configured with an exporter. | ||
// If not, the Span method will use a no-op tracing provider. When enabled, the | ||
// spans will have the supplied service name. The context is used to initialize | ||
// a configured OTLP exporter, if any. | ||
func New(ctx context.Context, serviceName string, opts ...Option) (*Tracer, error) { | ||
c := &config{} | ||
for _, opt := range opts { | ||
err := opt(c) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
var err error | ||
exp := c.exporter | ||
if exp == nil { | ||
if c.otlpEndpointURI == "" { | ||
return &Tracer{}, nil | ||
} | ||
exp, err = otlpExporter(ctx, c.otlpEndpointURI) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
resources, err := resource.New(ctx, | ||
resource.WithAttributes( | ||
attribute.String("service.name", serviceName)), | ||
resource.WithFromEnv(), | ||
resource.WithProcess(), | ||
resource.WithOS(), | ||
resource.WithContainer(), | ||
resource.WithHost(), | ||
) | ||
if err != nil { | ||
return nil, fmt.Errorf("resource lookup: %v", err) | ||
} | ||
tpOpts := []sdktrace.TracerProviderOption{ | ||
sdktrace.WithResource(resources), | ||
} | ||
if c.sampler != nil { | ||
tpOpts = append(tpOpts, sdktrace.WithSampler(c.sampler)) | ||
} | ||
if c.syncExport { | ||
tpOpts = append(tpOpts, sdktrace.WithSyncer(exp)) | ||
} else { | ||
tpOpts = append(tpOpts, | ||
sdktrace.WithBatcher(exp, c.batchOpts...)) | ||
} | ||
return &Tracer{ | ||
exportTP: sdktrace.NewTracerProvider(tpOpts...), | ||
}, nil | ||
} | ||
|
||
func otlpExporter(ctx context.Context, traceURI string) (*otlptrace.Exporter, error) { | ||
u, err := url.Parse(traceURI) | ||
if err != nil { | ||
return nil, fmt.Errorf("invalid profiler endpoint URI: %v", err) | ||
} | ||
otlpOpts := []otlptracegrpc.Option{ | ||
otlptracegrpc.WithEndpoint(u.Host), | ||
} | ||
if strings.ToLower(u.Scheme) != "https" { | ||
otlpOpts = append(otlpOpts, otlptracegrpc.WithInsecure()) | ||
} | ||
return otlptracegrpc.New(ctx, otlpOpts...) | ||
} | ||
|
||
// Span creates a new trace span and returns the supplied context with span | ||
// added. The returned span must be ended to avoid leaking resources. | ||
func (t Tracer) Span(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { | ||
if t.exportTP == nil { | ||
return noopTracerProvider.Tracer(tracerName).Start(ctx, spanName, opts...) | ||
} | ||
return t.exportTP.Tracer(tracerName).Start(ctx, spanName, opts...) | ||
} | ||
|
||
// Shutdown releases all resources allocated by the tracing provider. | ||
func (t Tracer) Shutdown(ctx context.Context) error { | ||
if t.exportTP != nil { | ||
return t.exportTP.Shutdown(ctx) | ||
} | ||
return nil | ||
} |