From adc5a81338845ad813a13f43594b91dfd1284b12 Mon Sep 17 00:00:00 2001 From: Cody Hartsook Date: Tue, 1 Sep 2026 11:26:34 -0700 Subject: [PATCH 1/5] fix(otel): register the tracer provider in the controller entrypoint Signed-off-by: Cody Hartsook --- go/core/cmd/controller-v2/main.go | 16 +++++- go/core/internal/telemetry/tracing_test.go | 64 ++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 go/core/internal/telemetry/tracing_test.go diff --git a/go/core/cmd/controller-v2/main.go b/go/core/cmd/controller-v2/main.go index aeca8a3c6..f2833c4e1 100644 --- a/go/core/cmd/controller-v2/main.go +++ b/go/core/cmd/controller-v2/main.go @@ -42,6 +42,8 @@ import ( prompttemplateservice "github.com/kagent-dev/kagent/go/core/internal/service/prompttemplate" systemservice "github.com/kagent-dev/kagent/go/core/internal/service/system" toolservice "github.com/kagent-dev/kagent/go/core/internal/service/tool" + "github.com/kagent-dev/kagent/go/core/internal/telemetry" + "github.com/kagent-dev/kagent/go/core/internal/version" "github.com/kagent-dev/kagent/go/core/pkg/auth" "github.com/kagent-dev/kagent/go/core/pkg/migrations" "github.com/kagent-dev/kagent/go/core/v2/a2agateway" @@ -68,7 +70,6 @@ import ( func main() { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() - logLevel := zapcore.InfoLevel if value := os.Getenv("ZAP_LOG_LEVEL"); value != "" { if err := logLevel.Set(value); err != nil { @@ -76,6 +77,19 @@ func main() { } } ctrl.SetLogger(zap.New(zap.Level(logLevel))) + // otelgrpc snapshots the global TracerProvider and propagator when its handler + // is constructed, so tracing has to be registered before any server is built. + shutdownTracing, err := telemetry.InitTracerProvider(ctx, version.Version) + if err != nil { + log.Fatalf("initialize tracing: %v", err) + } + defer func() { + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := shutdownTracing(shutdownCtx); err != nil { + log.Printf("shutdown tracing: %v", err) + } + }() dbURL, err := database.ResolveURL(env("POSTGRES_DATABASE_URL", "postgres://postgres:kagent@kagent-postgresql.kagent.svc.cluster.local:5432/postgres"), os.Getenv("POSTGRES_DATABASE_URL_FILE")) if err != nil { diff --git a/go/core/internal/telemetry/tracing_test.go b/go/core/internal/telemetry/tracing_test.go new file mode 100644 index 000000000..ee25b17bb --- /dev/null +++ b/go/core/internal/telemetry/tracing_test.go @@ -0,0 +1,64 @@ +package telemetry + +import ( + "context" + "net/http" + "testing" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/propagation" + sdktrace "go.opentelemetry.io/otel/sdk/trace" +) + +// 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 := 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") + + shutdown, err := 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") + } +} From 1c5e693d2369d7ab02f2fb9a432574d3b543609b Mon Sep 17 00:00:00 2001 From: Cody Hartsook Date: Tue, 1 Sep 2026 14:59:12 -0700 Subject: [PATCH 2/5] fix(otel): forward controller OTEL environment to agent runtimes Signed-off-by: Cody Hartsook --- go/core/v2/translator/claude/compiler.go | 1 + go/core/v2/translator/claude/compiler_test.go | 22 ++++++++++ go/core/v2/translator/compiler_test.go | 36 +++++++++++++++++ go/core/v2/translator/kagent/compiler.go | 1 + go/core/v2/translator/otel.go | 30 ++++++++++++++ go/core/v2/translator/otel_test.go | 40 +++++++++++++++++++ 6 files changed, 130 insertions(+) create mode 100644 go/core/v2/translator/otel.go create mode 100644 go/core/v2/translator/otel_test.go diff --git a/go/core/v2/translator/claude/compiler.go b/go/core/v2/translator/claude/compiler.go index dcc80901c..1dfef4292 100644 --- a/go/core/v2/translator/claude/compiler.go +++ b/go/core/v2/translator/claude/compiler.go @@ -74,6 +74,7 @@ func (c *Compiler) Compile(ctx context.Context, input *v2translator.HarnessInput corev1.EnvVar{Name: claudeconfig.SandboxEnvName, Value: "1"}, corev1.EnvVar{Name: claudeconfig.PreResponseTraceFlushEnvName, Value: "true"}, ) + environment = append(environment, v2translator.OtelEnvFromProcess()...) localAgents, err := c.compileLocalAgents(input.Root) if err != nil { diff --git a/go/core/v2/translator/claude/compiler_test.go b/go/core/v2/translator/claude/compiler_test.go index 88439fe06..168990163 100644 --- a/go/core/v2/translator/claude/compiler_test.go +++ b/go/core/v2/translator/claude/compiler_test.go @@ -164,6 +164,28 @@ func TestCompileRejectsProviderOwnedHarnessEnvironment(t *testing.T) { } } +func TestCompileForwardsOtelEnvironment(t *testing.T) { + t.Setenv("OTEL_TRACING_ENABLED", "true") + model := v1alpha3.ModelConfigSpec{ + Provider: v1alpha3.ModelProviderAnthropic, Model: "claude-sonnet-4-5", + APIKeySecret: "model-auth", APIKeySecretKey: "api-key", + } + input, reader := testInput(t, model, map[string][]byte{"api-key": []byte("secret")}) + revision, err := NewCompiler(reader).Compile(context.Background(), input) + if err != nil { + t.Fatal(err) + } + for _, variable := range revision.Environment { + if variable.Name == "OTEL_TRACING_ENABLED" { + if variable.Value != "true" { + t.Fatalf("OTEL_TRACING_ENABLED = %q, want %q", variable.Value, "true") + } + return + } + } + t.Fatalf("OTEL_TRACING_ENABLED missing from revision environment: %+v", revision.Environment) +} + func TestCompileRootSkillsAndPluginSelections(t *testing.T) { model := v1alpha3.ModelConfigSpec{ Provider: v1alpha3.ModelProviderAnthropic, Model: "claude-sonnet-4-5", diff --git a/go/core/v2/translator/compiler_test.go b/go/core/v2/translator/compiler_test.go index f7217bc9f..b5477c31c 100644 --- a/go/core/v2/translator/compiler_test.go +++ b/go/core/v2/translator/compiler_test.go @@ -292,6 +292,42 @@ func TestCompileAgentTemplateResolvesCredentialsForSubstrate(t *testing.T) { } } +func TestCompileAgentTemplateForwardsOtelEnvironment(t *testing.T) { + t.Setenv("OTEL_TRACING_ENABLED", "true") + harness := &v1alpha3.Harness{ + ObjectMeta: metav1.ObjectMeta{Name: "kagent", Namespace: "test"}, + Spec: v1alpha3.HarnessSpec{ + Kagent: &v1alpha3.KagentHarness{}, + AllowedAgentTemplates: &v1alpha3.HarnessAgentTemplateAdmission{Selector: metav1.LabelSelector{}}, + Workload: v1alpha3.HarnessWorkload{Image: "example.com/kagent@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, + Substrate: v1alpha3.HarnessSubstratePolicy{ + WorkerPoolRef: corev1.LocalObjectReference{Name: "default"}, + SnapshotPolicy: v1alpha3.HarnessSnapshotPolicy{Location: "snapshots"}, + }, + }, + } + template := &v1alpha3.AgentTemplate{ + ObjectMeta: metav1.ObjectMeta{Name: "helper", Namespace: "test"}, + Spec: v1alpha3.AgentTemplateSpec{ + ModelConfig: v1alpha3.AgentTemplateLocalReference{Name: "default-model"}, + SystemPrompt: "help", + }, + } + spec, err := compiler(t, modelConfig()).CompileAgentTemplate(context.Background(), harness, template) + if err != nil { + t.Fatal(err) + } + for _, variable := range spec.Environment { + if variable.Name == "OTEL_TRACING_ENABLED" { + if variable.Value != "true" { + t.Fatalf("OTEL_TRACING_ENABLED = %q, want %q", variable.Value, "true") + } + return + } + } + t.Fatalf("OTEL_TRACING_ENABLED missing from runtime revision environment: %+v", spec.Environment) +} + func TestCompileAgentTemplateSharedAgent(t *testing.T) { selector := &v1alpha3.HarnessAgentTemplateAdmission{Selector: metav1.LabelSelector{MatchLabels: map[string]string{"runtime": "kagent"}}} harness := &v1alpha3.Harness{ diff --git a/go/core/v2/translator/kagent/compiler.go b/go/core/v2/translator/kagent/compiler.go index ab5e8d80d..3d563c6ba 100644 --- a/go/core/v2/translator/kagent/compiler.go +++ b/go/core/v2/translator/kagent/compiler.go @@ -73,6 +73,7 @@ func (c *Compiler) Compile(ctx context.Context, input *v2translator.HarnessInput corev1.EnvVar{Name: "KAGENT_A2A_GRPC_ADDRESS", Value: "[::]:80"}, corev1.EnvVar{Name: "KAGENT_PRE_RESPONSE_TRACE_FLUSH", Value: "true"}, ) + environment = append(environment, v2translator.OtelEnvFromProcess()...) environment = adkconfig.DedupeEnv(environment) provenance, err := c.config.BuildProvenance(ctx, harness, compiled.Templates, compiled.Models, environment) if err != nil { diff --git a/go/core/v2/translator/otel.go b/go/core/v2/translator/otel.go new file mode 100644 index 000000000..b024bd0e5 --- /dev/null +++ b/go/core/v2/translator/otel.go @@ -0,0 +1,30 @@ +package translator + +import ( + "os" + "slices" + "strings" + + corev1 "k8s.io/api/core/v1" +) + +// OtelEnvFromProcess returns the controller's own OTEL_ variables so harness +// compilers can forward them to the agent runtime, which reads its telemetry +// configuration from its process environment. +func OtelEnvFromProcess() []corev1.EnvVar { + var envVars []corev1.EnvVar + for _, envVar := range os.Environ() { + if !strings.HasPrefix(envVar, "OTEL_") { + continue + } + name, value, found := strings.Cut(envVar, "=") + if !found { + continue + } + envVars = append(envVars, corev1.EnvVar{Name: name, Value: value}) + } + slices.SortFunc(envVars, func(a, b corev1.EnvVar) int { + return strings.Compare(a.Name, b.Name) + }) + return envVars +} diff --git a/go/core/v2/translator/otel_test.go b/go/core/v2/translator/otel_test.go new file mode 100644 index 000000000..5949964ed --- /dev/null +++ b/go/core/v2/translator/otel_test.go @@ -0,0 +1,40 @@ +package translator + +import ( + "slices" + "strings" + "testing" +) + +func TestOtelEnvFromProcess(t *testing.T) { + t.Setenv("OTEL_TRACING_ENABLED", "true") + t.Setenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "http://collector:4317") + t.Setenv("KAGENT_NOT_FORWARDED", "value") + + got := OtelEnvFromProcess() + + values := map[string]string{} + for _, variable := range got { + if !strings.HasPrefix(variable.Name, "OTEL_") { + t.Errorf("forwarded non-OTEL variable %q", variable.Name) + } + values[variable.Name] = variable.Value + } + if values["OTEL_TRACING_ENABLED"] != "true" { + t.Errorf("OTEL_TRACING_ENABLED = %q, want %q", values["OTEL_TRACING_ENABLED"], "true") + } + if values["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"] != "http://collector:4317" { + t.Errorf("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = %q", values["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"]) + } + if _, ok := values["KAGENT_NOT_FORWARDED"]; ok { + t.Error("forwarded a variable outside the OTEL_ prefix") + } + + names := make([]string, 0, len(got)) + for _, variable := range got { + names = append(names, variable.Name) + } + if !slices.IsSorted(names) { + t.Errorf("variables are not sorted by name: %v", names) + } +} From a356d716665a7fe5637fd3c00022fce5eb532c06 Mon Sep 17 00:00:00 2001 From: Cody Hartsook Date: Tue, 1 Sep 2026 15:51:39 -0700 Subject: [PATCH 3/5] fix(otel): scope propagation to kagent runtime Signed-off-by: Cody Hartsook --- go/core/internal/telemetry/tracing_test.go | 8 ++++--- go/core/v2/translator/claude/compiler.go | 1 - go/core/v2/translator/claude/compiler_test.go | 22 ------------------- go/core/v2/translator/otel_test.go | 6 +++-- 4 files changed, 9 insertions(+), 28 deletions(-) diff --git a/go/core/internal/telemetry/tracing_test.go b/go/core/internal/telemetry/tracing_test.go index ee25b17bb..627ff2a2a 100644 --- a/go/core/internal/telemetry/tracing_test.go +++ b/go/core/internal/telemetry/tracing_test.go @@ -1,4 +1,4 @@ -package telemetry +package telemetry_test import ( "context" @@ -8,6 +8,8 @@ import ( "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. @@ -26,7 +28,7 @@ func TestInitTracerProviderDisabled(t *testing.T) { t.Setenv("OTEL_TRACING_ENABLED", "false") before := otel.GetTracerProvider() - shutdown, err := InitTracerProvider(context.Background(), "test") + shutdown, err := telemetry.InitTracerProvider(context.Background(), "test") if err != nil { t.Fatal(err) } @@ -44,7 +46,7 @@ func TestInitTracerProviderRegistersGlobals(t *testing.T) { // "none" selects a noop exporter, so the test dials no collector. t.Setenv("OTEL_TRACES_EXPORTER", "none") - shutdown, err := InitTracerProvider(context.Background(), "test") + shutdown, err := telemetry.InitTracerProvider(context.Background(), "test") if err != nil { t.Fatal(err) } diff --git a/go/core/v2/translator/claude/compiler.go b/go/core/v2/translator/claude/compiler.go index 1dfef4292..dcc80901c 100644 --- a/go/core/v2/translator/claude/compiler.go +++ b/go/core/v2/translator/claude/compiler.go @@ -74,7 +74,6 @@ func (c *Compiler) Compile(ctx context.Context, input *v2translator.HarnessInput corev1.EnvVar{Name: claudeconfig.SandboxEnvName, Value: "1"}, corev1.EnvVar{Name: claudeconfig.PreResponseTraceFlushEnvName, Value: "true"}, ) - environment = append(environment, v2translator.OtelEnvFromProcess()...) localAgents, err := c.compileLocalAgents(input.Root) if err != nil { diff --git a/go/core/v2/translator/claude/compiler_test.go b/go/core/v2/translator/claude/compiler_test.go index 168990163..88439fe06 100644 --- a/go/core/v2/translator/claude/compiler_test.go +++ b/go/core/v2/translator/claude/compiler_test.go @@ -164,28 +164,6 @@ func TestCompileRejectsProviderOwnedHarnessEnvironment(t *testing.T) { } } -func TestCompileForwardsOtelEnvironment(t *testing.T) { - t.Setenv("OTEL_TRACING_ENABLED", "true") - model := v1alpha3.ModelConfigSpec{ - Provider: v1alpha3.ModelProviderAnthropic, Model: "claude-sonnet-4-5", - APIKeySecret: "model-auth", APIKeySecretKey: "api-key", - } - input, reader := testInput(t, model, map[string][]byte{"api-key": []byte("secret")}) - revision, err := NewCompiler(reader).Compile(context.Background(), input) - if err != nil { - t.Fatal(err) - } - for _, variable := range revision.Environment { - if variable.Name == "OTEL_TRACING_ENABLED" { - if variable.Value != "true" { - t.Fatalf("OTEL_TRACING_ENABLED = %q, want %q", variable.Value, "true") - } - return - } - } - t.Fatalf("OTEL_TRACING_ENABLED missing from revision environment: %+v", revision.Environment) -} - func TestCompileRootSkillsAndPluginSelections(t *testing.T) { model := v1alpha3.ModelConfigSpec{ Provider: v1alpha3.ModelProviderAnthropic, Model: "claude-sonnet-4-5", diff --git a/go/core/v2/translator/otel_test.go b/go/core/v2/translator/otel_test.go index 5949964ed..af111d715 100644 --- a/go/core/v2/translator/otel_test.go +++ b/go/core/v2/translator/otel_test.go @@ -1,9 +1,11 @@ -package translator +package translator_test import ( "slices" "strings" "testing" + + "github.com/kagent-dev/kagent/go/core/v2/translator" ) func TestOtelEnvFromProcess(t *testing.T) { @@ -11,7 +13,7 @@ func TestOtelEnvFromProcess(t *testing.T) { t.Setenv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", "http://collector:4317") t.Setenv("KAGENT_NOT_FORWARDED", "value") - got := OtelEnvFromProcess() + got := translator.OtelEnvFromProcess() values := map[string]string{} for _, variable := range got { From 5aad89062051963ba4f1d103cadf2be9936f3099 Mon Sep 17 00:00:00 2001 From: Cody Hartsook Date: Wed, 2 Sep 2026 08:00:52 -0700 Subject: [PATCH 4/5] test: adapt otel compiler fixture to current API Signed-off-by: Cody Hartsook --- go/core/v2/translator/compiler_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/core/v2/translator/compiler_test.go b/go/core/v2/translator/compiler_test.go index b5477c31c..b62a86da2 100644 --- a/go/core/v2/translator/compiler_test.go +++ b/go/core/v2/translator/compiler_test.go @@ -309,7 +309,7 @@ func TestCompileAgentTemplateForwardsOtelEnvironment(t *testing.T) { template := &v1alpha3.AgentTemplate{ ObjectMeta: metav1.ObjectMeta{Name: "helper", Namespace: "test"}, Spec: v1alpha3.AgentTemplateSpec{ - ModelConfig: v1alpha3.AgentTemplateLocalReference{Name: "default-model"}, + ModelConfig: &corev1.LocalObjectReference{Name: "default-model"}, SystemPrompt: "help", }, } From 2ec726006fbf823b3938d5321ecba874a6c59f96 Mon Sep 17 00:00:00 2001 From: Cody Hartsook Date: Wed, 2 Sep 2026 08:23:55 -0700 Subject: [PATCH 5/5] fix(otel): allowlist runtime tracing environment Signed-off-by: Cody Hartsook --- go/core/v2/translator/otel.go | 35 +++++++++++++------------ go/core/v2/translator/otel_test.go | 42 ++++++++++++------------------ 2 files changed, 34 insertions(+), 43 deletions(-) diff --git a/go/core/v2/translator/otel.go b/go/core/v2/translator/otel.go index b024bd0e5..60dcbdc6b 100644 --- a/go/core/v2/translator/otel.go +++ b/go/core/v2/translator/otel.go @@ -2,29 +2,30 @@ package translator import ( "os" - "slices" - "strings" corev1 "k8s.io/api/core/v1" ) -// OtelEnvFromProcess returns the controller's own OTEL_ variables so harness -// compilers can forward them to the agent runtime, which reads its telemetry -// configuration from its process environment. +// 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 { - var envVars []corev1.EnvVar - for _, envVar := range os.Environ() { - if !strings.HasPrefix(envVar, "OTEL_") { - continue - } - name, value, found := strings.Cut(envVar, "=") - if !found { - continue + 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}) } - envVars = append(envVars, corev1.EnvVar{Name: name, Value: value}) } - slices.SortFunc(envVars, func(a, b corev1.EnvVar) int { - return strings.Compare(a.Name, b.Name) - }) return envVars } diff --git a/go/core/v2/translator/otel_test.go b/go/core/v2/translator/otel_test.go index af111d715..500d7699d 100644 --- a/go/core/v2/translator/otel_test.go +++ b/go/core/v2/translator/otel_test.go @@ -1,42 +1,32 @@ package translator_test import ( - "slices" - "strings" + "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("KAGENT_NOT_FORWARDED", "value") + 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() - - values := map[string]string{} - for _, variable := range got { - if !strings.HasPrefix(variable.Name, "OTEL_") { - t.Errorf("forwarded non-OTEL variable %q", variable.Name) - } - values[variable.Name] = variable.Value - } - if values["OTEL_TRACING_ENABLED"] != "true" { - t.Errorf("OTEL_TRACING_ENABLED = %q, want %q", values["OTEL_TRACING_ENABLED"], "true") - } - if values["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"] != "http://collector:4317" { - t.Errorf("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = %q", values["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"]) - } - if _, ok := values["KAGENT_NOT_FORWARDED"]; ok { - t.Error("forwarded a variable outside the OTEL_ prefix") - } - - names := make([]string, 0, len(got)) - for _, variable := range got { - names = append(names, variable.Name) + 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 !slices.IsSorted(names) { - t.Errorf("variables are not sorted by name: %v", names) + if !reflect.DeepEqual(got, want) { + t.Errorf("OtelEnvFromProcess() = %#v, want %#v", got, want) } }