From a0ad8709ff6a2dcfbf121c955c762c6aadd01794 Mon Sep 17 00:00:00 2001 From: PratikDhanave Date: Wed, 23 Sep 2026 10:22:42 +0530 Subject: [PATCH] Add an agent OpenTelemetry tracing example Go has otelprovider but no sample. Add an example that installs a stdout OpenTelemetry tracer and wraps a Foundry agent with the otel middleware, so the agent run emits a gen_ai invoke_agent span (model, usage, finish reason) printed to stdout. Registered with cmd/verifyexamples (env-gated). --- cmd/verifyexamples/examples.go | 11 ++++ .../step01_agent_tracing/main.go | 58 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 examples/02-agents/observability/step01_agent_tracing/main.go diff --git a/cmd/verifyexamples/examples.go b/cmd/verifyexamples/examples.go index 6aa19081..2e41611a 100644 --- a/cmd/verifyexamples/examples.go +++ b/cmd/verifyexamples/examples.go @@ -812,6 +812,17 @@ var agentsExamples = []ExampleDefinition{ "The output should not contain error messages or stack traces.", }, }, + { + Name: "02_agents_observability_step01_agent_tracing", + ProjectPath: "examples/02-agents/observability/step01_agent_tracing", + RequiredEnvironmentVariables: []string{"FOUNDRY_PROJECT_ENDPOINT"}, + OptionalEnvironmentVariables: []string{"FOUNDRY_MODEL"}, + ExpectedOutputDescription: []string{ + "The output should contain a joke about a pirate from the agent.", + "The output should also contain an OpenTelemetry span printed to stdout for the agent run (an invoke_agent gen_ai span).", + "The output should not contain error messages or stack traces.", + }, + }, } var workflowExamples = []ExampleDefinition{ diff --git a/examples/02-agents/observability/step01_agent_tracing/main.go b/examples/02-agents/observability/step01_agent_tracing/main.go new file mode 100644 index 00000000..2cca1912 --- /dev/null +++ b/examples/02-agents/observability/step01_agent_tracing/main.go @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft. All rights reserved. + +package main + +import ( + "context" + + "github.com/microsoft/agent-framework-go/agent" + "github.com/microsoft/agent-framework-go/examples/internal/demo" + "github.com/microsoft/agent-framework-go/provider/foundryprovider" + "github.com/microsoft/agent-framework-go/provider/otelprovider" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + sdktrace "go.opentelemetry.io/otel/sdk/trace" +) + +var logger = demo.NewLogger( + "Agent OpenTelemetry", + "This sample shows how to trace an agent run with OpenTelemetry. The otelprovider "+ + "middleware emits a gen_ai invoke_agent span (model, usage, finish reason) that "+ + "is exported here to stdout.", + "Model", demo.FoundryModel, +) + +func main() { + // Set up an OpenTelemetry tracer that prints spans to stdout, and install it + // as the global tracer provider so the otel middleware records to it. + exporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint()) + if err != nil { + demo.Panic(err) + } + tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter)) + otel.SetTracerProvider(tp) + defer func() { _ = tp.Shutdown(context.Background()) }() + + token := demo.FoundryTokenCredential() + + // The otelprovider middleware wraps the agent run in a gen_ai span. + a := foundryprovider.NewAgent( + demo.FoundryProjectEndpoint, + token, + foundryprovider.ModelDeployment(demo.FoundryModel), + foundryprovider.AgentConfig{ + Instructions: "You are good at telling jokes.", + Config: agent.Config{ + Name: "Joker", + Middlewares: []agent.Middleware{ + otelprovider.NewMiddleware(otelprovider.MiddlewareConfig{}), + logger, // for logging agent interactions + }, + }, + }, + ) + + ctx := context.Background() + resp, err := a.RunText(ctx, "Tell me a joke about a pirate.").Collect() + demo.Response(resp, err) +}