-
Notifications
You must be signed in to change notification settings - Fork 738
fix(otel): restore distributed tracing for the controller and agent runtimes #2663
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
adc5a81
1c5e693
a356d71
5aad890
2ec7260
788bdba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package telemetry_test | ||
|
|
||
| import ( | ||
| "context" | ||
| "net/http" | ||
| "testing" | ||
|
|
||
| "go.opentelemetry.io/otel" | ||
| "go.opentelemetry.io/otel/propagation" | ||
| sdktrace "go.opentelemetry.io/otel/sdk/trace" | ||
|
|
||
| "github.com/kagent-dev/kagent/go/core/internal/telemetry" | ||
| ) | ||
|
|
||
| // restoreGlobals puts the process-wide OTEL registrations back after a test. | ||
| func restoreGlobals(t *testing.T) { | ||
| t.Helper() | ||
| tracerProvider := otel.GetTracerProvider() | ||
| propagator := otel.GetTextMapPropagator() | ||
| t.Cleanup(func() { | ||
| otel.SetTracerProvider(tracerProvider) | ||
| otel.SetTextMapPropagator(propagator) | ||
| }) | ||
| } | ||
|
|
||
| func TestInitTracerProviderDisabled(t *testing.T) { | ||
| restoreGlobals(t) | ||
| t.Setenv("OTEL_TRACING_ENABLED", "false") | ||
|
|
||
| before := otel.GetTracerProvider() | ||
| shutdown, err := telemetry.InitTracerProvider(context.Background(), "test") | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| if err := shutdown(context.Background()); err != nil { | ||
| t.Fatalf("shutdown: %v", err) | ||
| } | ||
| if otel.GetTracerProvider() != before { | ||
| t.Fatal("disabled tracing replaced the global TracerProvider") | ||
| } | ||
| } | ||
|
|
||
| func TestInitTracerProviderRegistersGlobals(t *testing.T) { | ||
| restoreGlobals(t) | ||
| t.Setenv("OTEL_TRACING_ENABLED", "true") | ||
| // "none" selects a noop exporter, so the test dials no collector. | ||
| t.Setenv("OTEL_TRACES_EXPORTER", "none") | ||
|
Comment on lines
+46
to
+47
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! |
||
|
|
||
| shutdown, err := telemetry.InitTracerProvider(context.Background(), "test") | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| t.Cleanup(func() { _ = shutdown(context.Background()) }) | ||
|
|
||
| if _, ok := otel.GetTracerProvider().(*sdktrace.TracerProvider); !ok { | ||
| t.Fatalf("global TracerProvider = %T, want *sdktrace.TracerProvider", otel.GetTracerProvider()) | ||
| } | ||
|
|
||
| ctx, span := otel.Tracer("test").Start(context.Background(), "span") | ||
| defer span.End() | ||
| header := http.Header{} | ||
| otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(header)) | ||
| if header.Get("traceparent") == "" { | ||
| t.Fatal("registered propagator did not inject traceparent") | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package translator | ||
|
|
||
| import ( | ||
| "os" | ||
|
|
||
| corev1 "k8s.io/api/core/v1" | ||
| ) | ||
|
|
||
| // These are the tracing settings read by the runtime; trace-specific values | ||
| // take precedence over their generic OTLP counterparts. | ||
| // Keep this list explicit: headers may contain credentials and resource | ||
| // attributes belong to the controller rather than its agent runtimes. | ||
| var otelEnvNames = []string{ | ||
| "OTEL_TRACING_ENABLED", | ||
| "OTEL_EXPORTER_OTLP_ENDPOINT", | ||
| "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", | ||
| "OTEL_EXPORTER_OTLP_PROTOCOL", | ||
| "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL", | ||
| } | ||
|
|
||
| // OtelEnvFromProcess returns the controller's supported tracing configuration | ||
| // for the agent runtime. | ||
| func OtelEnvFromProcess() []corev1.EnvVar { | ||
| envVars := make([]corev1.EnvVar, 0, len(otelEnvNames)) | ||
| for _, name := range otelEnvNames { | ||
| if value, found := os.LookupEnv(name); found { | ||
| envVars = append(envVars, corev1.EnvVar{Name: name, Value: value}) | ||
| } | ||
| } | ||
| return envVars | ||
| } | ||
|
Comment on lines
+23
to
+31
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know that we had a similar logic before it got removed, but wondering if we should go with an explicit allow-list for OTel env vars instead. What I mainly want to avoid is silently adding potentially unwanted data as plaintext e.g. when someone decides to propagate There might also be a problem if someone is setting a e.g.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good idea, added the allow list. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package translator_test | ||
|
|
||
| import ( | ||
| "reflect" | ||
| "testing" | ||
|
|
||
| "github.com/kagent-dev/kagent/go/core/v2/translator" | ||
| corev1 "k8s.io/api/core/v1" | ||
| ) | ||
|
|
||
| func TestOtelEnvFromProcess(t *testing.T) { | ||
| t.Setenv("OTEL_TRACING_ENABLED", "true") | ||
| t.Setenv("OTEL_EXPORTER_OTLP_ENDPOINT", "collector:4317") | ||
| t.Setenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "http://collector:4317") | ||
| t.Setenv("OTEL_EXPORTER_OTLP_PROTOCOL", "http/protobuf") | ||
| t.Setenv("OTEL_EXPORTER_OTLP_TRACES_PROTOCOL", "grpc") | ||
| t.Setenv("OTEL_EXPORTER_OTLP_HEADERS", "authorization=secret") | ||
| t.Setenv("OTEL_RESOURCE_ATTRIBUTES", "service.name=controller") | ||
| t.Setenv("OTEL_SERVICE_NAME", "controller") | ||
|
|
||
| got := translator.OtelEnvFromProcess() | ||
| want := []corev1.EnvVar{ | ||
| {Name: "OTEL_TRACING_ENABLED", Value: "true"}, | ||
| {Name: "OTEL_EXPORTER_OTLP_ENDPOINT", Value: "collector:4317"}, | ||
| {Name: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", Value: "http://collector:4317"}, | ||
| {Name: "OTEL_EXPORTER_OTLP_PROTOCOL", Value: "http/protobuf"}, | ||
| {Name: "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL", Value: "grpc"}, | ||
| } | ||
| if !reflect.DeepEqual(got, want) { | ||
| t.Errorf("OtelEnvFromProcess() = %#v, want %#v", got, want) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great thing to call out, thanks!