diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 81a2da4a49..400b35d298 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -113,6 +113,7 @@
+
diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step08_Observability/Agent_Step08_Observability.csproj b/dotnet/samples/GettingStarted/Agents/Agent_Step08_Observability/Agent_Step08_Observability.csproj
index 1f8c39c55f..980e282641 100644
--- a/dotnet/samples/GettingStarted/Agents/Agent_Step08_Observability/Agent_Step08_Observability.csproj
+++ b/dotnet/samples/GettingStarted/Agents/Agent_Step08_Observability/Agent_Step08_Observability.csproj
@@ -11,6 +11,7 @@
+
diff --git a/dotnet/samples/GettingStarted/Agents/Agent_Step08_Observability/Program.cs b/dotnet/samples/GettingStarted/Agents/Agent_Step08_Observability/Program.cs
index 2826eb06b0..4990f9716a 100644
--- a/dotnet/samples/GettingStarted/Agents/Agent_Step08_Observability/Program.cs
+++ b/dotnet/samples/GettingStarted/Agents/Agent_Step08_Observability/Program.cs
@@ -4,6 +4,7 @@
using Azure.AI.OpenAI;
using Azure.Identity;
+using Azure.Monitor.OpenTelemetry.Exporter;
using Microsoft.Agents.AI;
using OpenAI;
using OpenTelemetry;
@@ -11,6 +12,7 @@ using OpenTelemetry.Trace;
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
+var applicationInsightsConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING");
const string JokerName = "Joker";
const string JokerInstructions = "You are good at telling jokes.";
@@ -18,10 +20,14 @@ const string JokerInstructions = "You are good at telling jokes.";
// Create TracerProvider with console exporter
// This will output the telemetry data to the console.
string sourceName = Guid.NewGuid().ToString("N");
-using var tracerProvider = Sdk.CreateTracerProviderBuilder()
+var tracerProviderBuilder = Sdk.CreateTracerProviderBuilder()
.AddSource(sourceName)
- .AddConsoleExporter()
- .Build();
+ .AddConsoleExporter();
+if (!string.IsNullOrWhiteSpace(applicationInsightsConnectionString))
+{
+ tracerProviderBuilder.AddAzureMonitorTraceExporter(options => options.ConnectionString = applicationInsightsConnectionString);
+}
+using var tracerProvider = tracerProviderBuilder.Build();
// Create the agent, and enable OpenTelemetry instrumentation.
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
diff --git a/dotnet/samples/GettingStarted/Workflows/Observability/ApplicationInsights/ApplicationInsights.csproj b/dotnet/samples/GettingStarted/Workflows/Observability/ApplicationInsights/ApplicationInsights.csproj
new file mode 100644
index 0000000000..f7a5a4424f
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Workflows/Observability/ApplicationInsights/ApplicationInsights.csproj
@@ -0,0 +1,21 @@
+
+
+
+ Exe
+ net9.0
+
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/samples/GettingStarted/Workflows/Observability/ApplicationInsights/Program.cs b/dotnet/samples/GettingStarted/Workflows/Observability/ApplicationInsights/Program.cs
new file mode 100644
index 0000000000..0ff7a50e8b
--- /dev/null
+++ b/dotnet/samples/GettingStarted/Workflows/Observability/ApplicationInsights/Program.cs
@@ -0,0 +1,96 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Diagnostics;
+using Azure.Monitor.OpenTelemetry.Exporter;
+using Microsoft.Agents.AI.Workflows;
+using Microsoft.Agents.AI.Workflows.Reflection;
+using OpenTelemetry;
+using OpenTelemetry.Resources;
+using OpenTelemetry.Trace;
+
+namespace WorkflowObservabilitySample;
+
+///
+/// This sample shows how to enable observability in a workflow and send the traces
+/// to be visualized in Application Insights.
+///
+/// In this example, we create a simple text processing pipeline that:
+/// 1. Takes input text and converts it to uppercase using an UppercaseExecutor
+/// 2. Takes the uppercase text and reverses it using a ReverseTextExecutor
+///
+/// The executors are connected sequentially, so data flows from one to the next in order.
+/// For input "Hello, World!", the workflow produces "!DLROW ,OLLEH".
+///
+public static class Program
+{
+ private const string SourceName = "Workflow.ApplicationInsightsSample";
+ private static readonly ActivitySource s_activitySource = new(SourceName);
+
+ private static async Task Main()
+ {
+ var applicationInsightsConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING") ?? throw new InvalidOperationException("APPLICATIONINSIGHTS_CONNECTION_STRING is not set.");
+
+ var resourceBuilder = ResourceBuilder
+ .CreateDefault()
+ .AddService("WorkflowSample");
+
+ using var traceProvider = Sdk.CreateTracerProviderBuilder()
+ .SetResourceBuilder(resourceBuilder)
+ .AddSource("Microsoft.Agents.AI.Workflows*")
+ .AddSource(SourceName)
+ .AddAzureMonitorTraceExporter(options => options.ConnectionString = applicationInsightsConnectionString)
+ .Build();
+
+ // Start a root activity for the application
+ using var activity = s_activitySource.StartActivity("main");
+ Console.WriteLine($"Operation/Trace ID: {Activity.Current?.TraceId}");
+
+ // Create the executors
+ UppercaseExecutor uppercase = new();
+ ReverseTextExecutor reverse = new();
+
+ // Build the workflow by connecting executors sequentially
+ var workflow = new WorkflowBuilder(uppercase)
+ .AddEdge(uppercase, reverse)
+ .Build();
+
+ // Execute the workflow with input data
+ Run run = await InProcessExecution.RunAsync(workflow, "Hello, World!");
+ foreach (WorkflowEvent evt in run.NewEvents)
+ {
+ if (evt is ExecutorCompletedEvent executorComplete)
+ {
+ Console.WriteLine($"{executorComplete.ExecutorId}: {executorComplete.Data}");
+ }
+ }
+ }
+}
+
+///
+/// First executor: converts input text to uppercase.
+///
+internal sealed class UppercaseExecutor() : ReflectingExecutor("UppercaseExecutor"), IMessageHandler
+{
+ ///
+ /// Processes the input message by converting it to uppercase.
+ ///
+ /// The input text to convert
+ /// Workflow context for accessing workflow services and adding events
+ /// The input text converted to uppercase
+ public async ValueTask HandleAsync(string message, IWorkflowContext context) =>
+ message.ToUpperInvariant(); // The return value will be sent as a message along an edge to subsequent executors
+}
+
+///
+/// Second executor: reverses the input text and completes the workflow.
+///
+internal sealed class ReverseTextExecutor() : ReflectingExecutor("ReverseTextExecutor"), IMessageHandler
+{
+ ///
+ /// Processes the input message by reversing the text.
+ ///
+ /// The input text to reverse
+ /// Workflow context for accessing workflow services and adding events
+ /// The input text reversed
+ public async ValueTask HandleAsync(string message, IWorkflowContext context) => new string(message.Reverse().ToArray());
+}