Skip to content

Commit

Permalink
Support OTEL_TRACES_EXPORTER in distro
Browse files Browse the repository at this point in the history
  • Loading branch information
MrAlias committed Dec 17, 2021
1 parent c3eadb8 commit 46c0f33
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 35 deletions.
141 changes: 128 additions & 13 deletions distro/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package distro

import (
"context"
"fmt"
"net/url"
"os"
Expand All @@ -24,7 +25,10 @@ import (
"go.opentelemetry.io/contrib/propagators/b3"
"go.opentelemetry.io/contrib/propagators/jaeger"
"go.opentelemetry.io/contrib/propagators/ot"
jaegerexporter "go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

// Environment variable keys that set values of the configuration.
Expand All @@ -35,23 +39,61 @@ const (
// OpenTelemetry TextMapPropagator to set as global.
otelPropagatorsKey = "OTEL_PROPAGATORS"

// OpenTelemetry trace exporter to use.
otelTracesExporterKey = "OTEL_TRACES_EXPORTER"

// FIXME: support OTEL_SPAN_LINK_COUNT_LIMIT
// FIXME: support OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT
// FIXME: support OTEL_TRACES_EXPORTER
)

// config is the configuration used to create and operate an SDK.
type config struct {
// Default configuration values.
const (
defaultAccessToken = ""
defaultPropagator = "tracecontext,baggage"
defaultTraceExporter = "otlp"

defaultOTLPEndpoint = "localhost:4317"
defaultJaegerEndpoint = "http://127.0.0.1:9080/v1/trace"
)

type exporterConfig struct {
AccessToken string
Endpoint string
Propagator propagation.TextMapPropagator
}

// Validate ensures c is valid, otherwise returning an appropriate error.
func (c exporterConfig) Validate() error {
var errs []string

if c.Endpoint != "" {
if _, err := url.Parse(c.Endpoint); err != nil {
errs = append(errs, "invalid endpoint: %s", err.Error())
}
}

if len(errs) > 0 {
return fmt.Errorf("invalid exporter config: %v", errs)
}
return nil
}

// config is the configuration used to create and operate an SDK.
type config struct {
Propagator propagation.TextMapPropagator

ExportConfig *exporterConfig
TraceExporterFunc traceExporterFunc
}

// newConfig returns a validated config with Splunk defaults.
func newConfig(opts ...Option) (*config, error) {
c := &config{
AccessToken: envOr(accessTokenKey, ""),
Propagator: loadPropagator(envOr(otelPropagatorsKey, "tracecontext,baggage")),
Propagator: loadPropagator(envOr(otelPropagatorsKey, defaultPropagator)),

ExportConfig: &exporterConfig{
AccessToken: envOr(accessTokenKey, defaultAccessToken),
},
TraceExporterFunc: loadTraceExporter(envOr(otelTracesExporterKey, defaultTraceExporter)),
}

for _, o := range opts {
Expand All @@ -67,11 +109,7 @@ func newConfig(opts ...Option) (*config, error) {
func (c config) Validate() error {
var errs []string

if c.Endpoint != "" {
if _, err := url.Parse(c.Endpoint); err != nil {
errs = append(errs, "invalid endpoint: %s", err.Error())
}
}
errs = append(errs, c.ExportConfig.Validate().Error())

if len(errs) > 0 {
return fmt.Errorf("invalid config: %v", errs)
Expand Down Expand Up @@ -143,6 +181,63 @@ func loadPropagator(name string) propagation.TextMapPropagator {
}
}

type traceExporterFunc func(*exporterConfig) (sdktrace.SpanExporter, error)

// exporters maps environment variable values to trace exporter creation
// functions.
var exporters = map[string]traceExporterFunc{
// OTLP gRPC exporter.
"otlp": func(c *exporterConfig) (sdktrace.SpanExporter, error) {
var opts []otlptracegrpc.Option

endpoint := c.Endpoint
if endpoint == "" {
endpoint = defaultJaegerEndpoint
}
opts = append(opts, otlptracegrpc.WithEndpoint(endpoint))

if c.AccessToken != "" {
opts = append(opts, otlptracegrpc.WithHeaders(map[string]string{
"X-Sf-Token": c.AccessToken,
}))
}

return otlptracegrpc.New(context.Background(), opts...)
},
// Jaeger thrift exporter.
"jaeger-thrift-splunk": func(c *exporterConfig) (sdktrace.SpanExporter, error) {
var opts []jaegerexporter.CollectorEndpointOption

endpoint := c.Endpoint
if endpoint == "" {
endpoint = defaultJaegerEndpoint
}
opts = append(opts, jaegerexporter.WithEndpoint(endpoint))

if c.AccessToken != "" {
opts = append(
opts,
jaegerexporter.WithUsername("auth"),
jaegerexporter.WithPassword(c.AccessToken),
)
}

return jaegerexporter.New(
jaegerexporter.WithCollectorEndpoint(opts...),
)
},
// None, explicitly do not set an exporter.
"none": nil,
}

func loadTraceExporter(name string) traceExporterFunc {
tef, ok := exporters[name]
if !ok {
return exporters[defaultTraceExporter]
}
return tef
}

// envOr returns the environment variable value associated with key if it
// exists, otherwise it returns alt.
func envOr(key, alt string) string {
Expand All @@ -169,7 +264,7 @@ func (fn optionFunc) apply(c *config) {
// Setting an empty string results in no operation.
func WithEndpoint(endpoint string) Option {
return optionFunc(func(c *config) {
c.Endpoint = endpoint
c.ExportConfig.Endpoint = endpoint
})
}

Expand All @@ -178,7 +273,7 @@ func WithEndpoint(endpoint string) Option {
// Setting an empty string results in no operation.
func WithAccessToken(accessToken string) Option {
return optionFunc(func(c *config) {
c.AccessToken = accessToken
c.ExportConfig.AccessToken = accessToken
})
}

Expand All @@ -197,3 +292,23 @@ func WithPropagator(p propagation.TextMapPropagator) Option {
c.Propagator = p
})
}

// WithTraceExporter configures the OpenTelemetry trace SpanExporter used to
// deliver telemetry. This exporter is registered with the OpenTelemetry SDK
// using a batch span processor.
//
// The OTEL_TRACES_EXPORTER environment variable value is used if this Option
// is not provided. Valid values for this environment variable are "otlp" for
// an OTLP exporter, and "jaeger-thrift-splunk" for a Splunk specific Jaeger
// thrift exporter. If this environment variable is set to "none", no exporter
// is registered and Run will return an error stating this.
//
// By default, an OTLP exporter is used if this is not provided or the
// OTEL_TRACES_EXPORTER environment variable is not set.
func WithTraceExporter(e sdktrace.SpanExporter) Option {
return optionFunc(func(c *config) {
c.TraceExporterFunc = func(*exporterConfig) (sdktrace.SpanExporter, error) {
return e, nil
}
})
}
22 changes: 8 additions & 14 deletions distro/otel.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ package distro

import (
"context"
"errors"

global "go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/sdk/trace"
)

Expand All @@ -53,16 +53,15 @@ func Run(opts ...Option) (SDK, error) {
return SDK{}, err
}

var jeagerOpts []jaeger.CollectorEndpointOption
if c.Endpoint != "" {
jeagerOpts = append(jeagerOpts, jaeger.WithEndpoint(c.Endpoint))
}
if c.AccessToken != "" {
jeagerOpts = append(jeagerOpts, jaeger.WithUsername("auth"), jaeger.WithPassword(c.AccessToken))
if c.Propagator != nil {
// Only set the global TextMapPropagator if "none" was not specified.
global.SetTextMapPropagator(c.Propagator)
}

opt := jaeger.WithCollectorEndpoint(jeagerOpts...)
exp, err := jaeger.New(opt)
if c.TraceExporterFunc == nil {
return SDK{}, errors.New(`"none" exporter set`)
}
exp, err := c.TraceExporterFunc(c.ExportConfig)
if err != nil {
return SDK{}, err
}
Expand All @@ -74,11 +73,6 @@ func Run(opts ...Option) (SDK, error) {
)
global.SetTracerProvider(traceProvider)

if c.Propagator != nil {
// Only set the global TextMapPropagator if "none" was not specified.
global.SetTextMapPropagator(c.Propagator)
}

return SDK{
config: *c,
shutdownFunc: func(ctx context.Context) error {
Expand Down
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ require (
go.opentelemetry.io/contrib/propagators/b3 v1.2.0
go.opentelemetry.io/contrib/propagators/jaeger v1.2.0
go.opentelemetry.io/contrib/propagators/ot v1.2.0
go.opentelemetry.io/otel v1.2.0
go.opentelemetry.io/otel v1.3.0
go.opentelemetry.io/otel/exporters/jaeger v1.2.0
go.opentelemetry.io/otel/sdk v1.2.0
go.opentelemetry.io/otel/trace v1.2.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0
go.opentelemetry.io/otel/sdk v1.3.0
go.opentelemetry.io/otel/trace v1.3.0
)
Loading

0 comments on commit 46c0f33

Please sign in to comment.