github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/telemetry.go (about) 1 package main 2 3 import ( 4 "context" 5 "os" 6 7 "github.com/terramate-io/tf/version" 8 "go.opentelemetry.io/contrib/exporters/autoexport" 9 "go.opentelemetry.io/otel" 10 "go.opentelemetry.io/otel/propagation" 11 "go.opentelemetry.io/otel/sdk/resource" 12 sdktrace "go.opentelemetry.io/otel/sdk/trace" 13 semconv "go.opentelemetry.io/otel/semconv/v1.4.0" 14 "go.opentelemetry.io/otel/trace" 15 ) 16 17 // If this environment variable is set to "otlp" when running Terraform CLI 18 // then we'll enable an experimental OTLP trace exporter. 19 // 20 // BEWARE! This is not a committed external interface. 21 // 22 // Everything about this is experimental and subject to change in future 23 // releases. Do not depend on anything about the structure of this output. 24 // This mechanism might be removed altogether if a different strategy seems 25 // better based on experience with this experiment. 26 const openTelemetryExporterEnvVar = "OTEL_TRACES_EXPORTER" 27 28 // tracer is the OpenTelemetry tracer to use for traces in package main only. 29 var tracer trace.Tracer 30 31 func init() { 32 tracer = otel.Tracer("github.com/hashicorp/terraform") 33 } 34 35 // openTelemetryInit initializes the optional OpenTelemetry exporter. 36 // 37 // By default we don't export telemetry information at all, since Terraform is 38 // a CLI tool and so we don't assume we're running in an environment with 39 // a telemetry collector available. 40 // 41 // However, for those running Terraform in automation we allow setting 42 // the standard OpenTelemetry environment variable OTEL_TRACES_EXPORTER=otlp 43 // to enable an OTLP exporter, which is in turn configured by all of the 44 // standard OTLP exporter environment variables: 45 // 46 // https://opentelemetry.io/docs/specs/otel/protocol/exporter/#configuration-options 47 // 48 // We don't currently support any other telemetry export protocols, because 49 // OTLP has emerged as a de-facto standard and each other exporter we support 50 // means another relatively-heavy external dependency. OTLP happens to use 51 // protocol buffers and gRPC, which Terraform would depend on for other reasons 52 // anyway. 53 func openTelemetryInit() error { 54 // We'll check the environment variable ourselves first, because the 55 // "autoexport" helper we're about to use is built under the assumption 56 // that exporting should always be enabled and so will expect to find 57 // an OTLP server on localhost if no environment variables are set at all. 58 if os.Getenv(openTelemetryExporterEnvVar) != "otlp" { 59 return nil // By default we just discard all telemetry calls 60 } 61 62 otelResource := resource.NewWithAttributes( 63 semconv.SchemaURL, 64 semconv.ServiceNameKey.String("Terraform CLI"), 65 semconv.ServiceVersionKey.String(version.Version), 66 ) 67 68 // If the environment variable was set to explicitly enable telemetry 69 // then we'll enable it, using the "autoexport" library to automatically 70 // handle the details based on the other OpenTelemetry standard environment 71 // variables. 72 exp, err := autoexport.NewSpanExporter(context.Background()) 73 if err != nil { 74 return err 75 } 76 sp := sdktrace.NewSimpleSpanProcessor(exp) 77 provider := sdktrace.NewTracerProvider( 78 sdktrace.WithSpanProcessor(sp), 79 sdktrace.WithResource(otelResource), 80 ) 81 otel.SetTracerProvider(provider) 82 83 pgtr := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}) 84 otel.SetTextMapPropagator(pgtr) 85 86 return nil 87 }