fix: Use standard env variables for opentelemtry (#2194)

Opentelemetry defines standard variables which are supported by multiple observability platforms.

[1] https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md
[2] https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md

By defining support for standard env vars, Fission open telemetry support can be leveraged with different
platforms such as NewRelic, SigNoz, DataDog etc.

Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
This commit is contained in:
Sanket Sudake
2021-09-16 17:48:26 +05:30
committed by GitHub
parent 33473a4528
commit 4a0bd1aa21
15 changed files with 253 additions and 250 deletions
+73 -19
View File
@@ -3,8 +3,11 @@ package otel
import (
"context"
"os"
"strconv"
"strings"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
@@ -12,31 +15,58 @@ import (
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
apiv1 "k8s.io/api/core/v1"
)
func getSpanProcessor(ctx context.Context, logger *zap.Logger) (*sdktrace.SpanProcessor, error) {
collectorEndpoint := os.Getenv("OTEL_COLLECTOR_ENDPOINT")
if collectorEndpoint == "" {
logger.Info("skipping trace exporter registration")
const (
OtelEnvPrefix = "OTEL_"
OtelEndpointEnvVar = "OTEL_EXPORTER_OTLP_ENDPOINT"
OtelInsecureEnvVar = "OTEL_EXPORTER_OTLP_INSECURE"
)
type OtelConfig struct {
endpoint string
insecure bool
}
func parseOtelConfig() OtelConfig {
config := OtelConfig{}
config.endpoint = os.Getenv(OtelEndpointEnvVar)
insecure, err := strconv.ParseBool(os.Getenv(OtelInsecureEnvVar))
if err != nil {
insecure = false
}
config.insecure = insecure
return config
}
func getTraceExporter(ctx context.Context, logger *zap.Logger) (*otlptrace.Exporter, error) {
otelConfig := parseOtelConfig()
if otelConfig.endpoint == "" {
logger.Info("OTEL_EXPORTER_OTLP_ENDPOINT not set, skipping Opentelemtry tracing")
return nil, nil
}
traceExporter, err := otlptracegrpc.New(ctx,
otlptracegrpc.WithInsecure(),
otlptracegrpc.WithEndpoint(collectorEndpoint),
grpcOpts := []otlptracegrpc.Option{
otlptracegrpc.WithEndpoint(otelConfig.endpoint),
otlptracegrpc.WithDialOption(grpc.WithBlock()),
)
}
if otelConfig.insecure {
grpcOpts = append(grpcOpts, otlptracegrpc.WithInsecure())
} else {
grpcOpts = append(grpcOpts, otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")))
}
exporter, err := otlptracegrpc.New(ctx, grpcOpts...)
if err != nil {
return nil, err
}
bsp := sdktrace.NewBatchSpanProcessor(traceExporter)
return &bsp, nil
return exporter, nil
}
// Initializes an OTLP exporter, and configures the corresponding trace and metric providers.
func InitProvider(logger *zap.Logger, serviceName string) (func(), error) {
ctx := context.Background()
func InitProvider(ctx context.Context, logger *zap.Logger, serviceName string) (func(context.Context), error) {
res, err := resource.New(ctx,
resource.WithAttributes(
semconv.ServiceNameKey.String(serviceName),
@@ -46,26 +76,50 @@ func InitProvider(logger *zap.Logger, serviceName string) (func(), error) {
return nil, err
}
tracerProvider := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithResource(res),
)
bsp, err := getSpanProcessor(ctx, logger)
traceExporter, err := getTraceExporter(ctx, logger)
if err != nil {
return nil, err
}
if bsp != nil {
tracerProvider.RegisterSpanProcessor(*bsp)
if traceExporter != nil {
bsp := sdktrace.NewBatchSpanProcessor(traceExporter)
tracerProvider.RegisterSpanProcessor(bsp)
}
otel.SetTracerProvider(tracerProvider)
otel.SetTextMapPropagator(propagation.TraceContext{})
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{}, propagation.Baggage{}))
// Shutdown will flush any remaining spans and shut down the exporter.
return func() {
return func(ctx context.Context) {
err := tracerProvider.Shutdown(ctx)
if err != nil {
logger.Fatal("error shutting down trace provider", zap.Error(err))
}
if traceExporter != nil {
if err = traceExporter.Shutdown(ctx); err != nil {
logger.Fatal("error shutting down trace exporter", zap.Error(err))
}
}
}, nil
}
// OtelEnvForContainer returns a list of environment variables
// for the container, which start with prefix OTEL_
func OtelEnvForContainer() []apiv1.EnvVar {
otelEnvs := []apiv1.EnvVar{}
for _, e := range os.Environ() {
if strings.HasPrefix(e, OtelEnvPrefix) {
pair := strings.SplitN(e, "=", 2)
otelEnvs = append(otelEnvs, apiv1.EnvVar{
Name: pair[0],
Value: pair[1],
})
}
}
return otelEnvs
}
+5 -1
View File
@@ -11,7 +11,11 @@ import (
)
func TracingEnabled(logger *zap.Logger) bool {
openTracingEnabled, err := strconv.ParseBool(os.Getenv("OPENTRACING_ENABLED"))
tracingEnabled := os.Getenv("TRACING_ENABLED")
if len(tracingEnabled) == 0 {
return false
}
openTracingEnabled, err := strconv.ParseBool(tracingEnabled)
if err != nil {
if logger != nil {
logger.Error("Error parsing OpenTracing enabled flag", zap.Error(err))