chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net10.0</TargetFrameworks>
|
||||
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.Identity" />
|
||||
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
|
||||
<PackageReference Include="OpenTelemetry" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Console" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,231 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Metrics;
|
||||
using Azure.AI.Projects;
|
||||
using Azure.Identity;
|
||||
using Azure.Monitor.OpenTelemetry.Exporter;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OpenTelemetry;
|
||||
using OpenTelemetry.Logs;
|
||||
using OpenTelemetry.Metrics;
|
||||
using OpenTelemetry.Resources;
|
||||
using OpenTelemetry.Trace;
|
||||
|
||||
#region Setup Telemetry
|
||||
|
||||
// Source name for this sample's custom ActivitySource and Meter; other instrumentation uses their own sources/categories.
|
||||
const string SourceName = "OpenTelemetryAspire.ConsoleApp";
|
||||
const string ServiceName = "AgentOpenTelemetry";
|
||||
|
||||
// Configure OpenTelemetry for Aspire dashboard
|
||||
var otlpEndpoint = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4317";
|
||||
|
||||
var applicationInsightsConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING");
|
||||
|
||||
// Create a resource to identify this service
|
||||
var resource = ResourceBuilder.CreateDefault()
|
||||
.AddService(ServiceName, serviceVersion: "1.0.0")
|
||||
.AddAttributes(new Dictionary<string, object>
|
||||
{
|
||||
["service.instance.id"] = Environment.MachineName,
|
||||
["deployment.environment"] = "development"
|
||||
})
|
||||
.Build();
|
||||
|
||||
// Setup tracing with resource
|
||||
var tracerProviderBuilder = Sdk.CreateTracerProviderBuilder()
|
||||
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(ServiceName, serviceVersion: "1.0.0"))
|
||||
.AddSource(SourceName) // Our custom activity source
|
||||
.AddHttpClientInstrumentation() // Capture HTTP calls to OpenAI
|
||||
.AddOtlpExporter(options => options.Endpoint = new Uri(otlpEndpoint));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(applicationInsightsConnectionString))
|
||||
{
|
||||
tracerProviderBuilder.AddAzureMonitorTraceExporter(options => options.ConnectionString = applicationInsightsConnectionString);
|
||||
}
|
||||
|
||||
using var tracerProvider = tracerProviderBuilder.Build();
|
||||
|
||||
// Setup metrics with resource and instrument name filtering
|
||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(ServiceName, serviceVersion: "1.0.0"))
|
||||
.AddMeter(SourceName) // Our custom meter source
|
||||
.AddHttpClientInstrumentation() // HTTP client metrics
|
||||
.AddRuntimeInstrumentation() // .NET runtime metrics
|
||||
.AddOtlpExporter(options => options.Endpoint = new Uri(otlpEndpoint))
|
||||
.Build();
|
||||
|
||||
// Setup structured logging with OpenTelemetry
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddLogging(loggingBuilder => loggingBuilder
|
||||
.SetMinimumLevel(LogLevel.Debug)
|
||||
.AddOpenTelemetry(options =>
|
||||
{
|
||||
options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(ServiceName, serviceVersion: "1.0.0"));
|
||||
options.AddOtlpExporter(otlpOptions => otlpOptions.Endpoint = new Uri(otlpEndpoint));
|
||||
if (!string.IsNullOrWhiteSpace(applicationInsightsConnectionString))
|
||||
{
|
||||
options.AddAzureMonitorLogExporter(options => options.ConnectionString = applicationInsightsConnectionString);
|
||||
}
|
||||
options.IncludeScopes = true;
|
||||
options.IncludeFormattedMessage = true;
|
||||
}));
|
||||
|
||||
using var activitySource = new ActivitySource(SourceName);
|
||||
using var meter = new Meter(SourceName);
|
||||
|
||||
// Create custom metrics
|
||||
var interactionCounter = meter.CreateCounter<int>("agent_interactions_total", description: "Total number of agent interactions");
|
||||
var responseTimeHistogram = meter.CreateHistogram<double>("agent_response_time_seconds", description: "Agent response time in seconds");
|
||||
|
||||
#endregion
|
||||
|
||||
var serviceProvider = serviceCollection.BuildServiceProvider();
|
||||
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
|
||||
var appLogger = loggerFactory.CreateLogger<Program>();
|
||||
|
||||
Console.WriteLine("""
|
||||
=== OpenTelemetry Aspire Demo ===
|
||||
This demo shows OpenTelemetry integration with the Agent Framework.
|
||||
You can view the telemetry data in the Aspire Dashboard.
|
||||
Type your message and press Enter. Type 'exit' or empty message to quit.
|
||||
""");
|
||||
|
||||
var endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT environment variable is not set.");
|
||||
var deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
|
||||
|
||||
// Log application startup
|
||||
appLogger.LogInformation("OpenTelemetry Aspire Demo application started");
|
||||
|
||||
[Description("Get the weather for a given location.")]
|
||||
static async Task<string> GetWeatherAsync([Description("The location to get the weather for.")] string location)
|
||||
{
|
||||
await Task.Delay(2000);
|
||||
return $"The weather in {location} is cloudy with a high of 15°C.";
|
||||
}
|
||||
|
||||
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
|
||||
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
|
||||
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
|
||||
appLogger.LogInformation("Creating Agent with OpenTelemetry instrumentation");
|
||||
// Create the agent with the instrumented chat client
|
||||
var agent = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
|
||||
.AsAIAgent(
|
||||
model: deploymentName,
|
||||
instructions: "You are a helpful assistant that provides concise and informative responses.",
|
||||
name: "OpenTelemetryDemoAgent",
|
||||
tools: [AIFunctionFactory.Create(GetWeatherAsync)],
|
||||
clientFactory: client => client
|
||||
.AsBuilder()
|
||||
.UseFunctionInvocation()
|
||||
.UseOpenTelemetry(sourceName: SourceName, configure: (cfg) => cfg.EnableSensitiveData = true) // enable telemetry at the chat client level
|
||||
.Build())
|
||||
.AsBuilder()
|
||||
.UseOpenTelemetry(sourceName: SourceName, configure: (cfg) => cfg.EnableSensitiveData = true) // enable telemetry at the agent level
|
||||
.Build();
|
||||
|
||||
var session = await agent.CreateSessionAsync();
|
||||
|
||||
appLogger.LogInformation("Agent created successfully with ID: {AgentId}", agent.Id);
|
||||
|
||||
// Create a parent span for the entire agent session
|
||||
using var sessionActivity = activitySource.StartActivity("Agent Session");
|
||||
Console.WriteLine($"Trace ID: {sessionActivity?.TraceId} ");
|
||||
|
||||
var sessionId = Guid.NewGuid().ToString("N");
|
||||
sessionActivity?
|
||||
.SetTag("agent.name", "OpenTelemetryDemoAgent")
|
||||
.SetTag("session.id", sessionId)
|
||||
.SetTag("session.start_time", DateTimeOffset.UtcNow.ToString("O"));
|
||||
|
||||
appLogger.LogInformation("Starting agent session with ID: {SessionId}", sessionId);
|
||||
using (appLogger.BeginScope(new Dictionary<string, object> { ["SessionId"] = sessionId, ["AgentName"] = "OpenTelemetryDemoAgent" }))
|
||||
{
|
||||
var interactionCount = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
Console.Write("You (or 'exit' to quit): ");
|
||||
var userInput = Console.ReadLine();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(userInput) || userInput.Equals("exit", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
appLogger.LogInformation("User requested to exit the session");
|
||||
break;
|
||||
}
|
||||
|
||||
interactionCount++;
|
||||
appLogger.LogInformation("Processing user interaction #{InteractionNumber}: {UserInput}", interactionCount, userInput);
|
||||
|
||||
// Create a child span for each individual interaction
|
||||
using var activity = activitySource.StartActivity("Agent Interaction");
|
||||
activity?
|
||||
.SetTag("user.input", userInput)
|
||||
.SetTag("agent.name", "OpenTelemetryDemoAgent")
|
||||
.SetTag("interaction.number", interactionCount);
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
|
||||
try
|
||||
{
|
||||
appLogger.LogDebug("Starting agent execution for interaction #{InteractionNumber}", interactionCount);
|
||||
Console.Write("Agent: ");
|
||||
|
||||
// Run the agent (this will create its own internal telemetry spans)
|
||||
await foreach (var update in agent.RunStreamingAsync(userInput, session))
|
||||
{
|
||||
Console.Write(update.Text);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
|
||||
stopwatch.Stop();
|
||||
var responseTime = stopwatch.Elapsed.TotalSeconds;
|
||||
|
||||
// Record metrics (similar to Python example)
|
||||
interactionCounter.Add(1, new KeyValuePair<string, object?>("status", "success"));
|
||||
responseTimeHistogram.Record(responseTime,
|
||||
new KeyValuePair<string, object?>("status", "success"));
|
||||
|
||||
activity?.SetTag("response.success", true);
|
||||
|
||||
appLogger.LogInformation("Agent interaction #{InteractionNumber} completed successfully in {ResponseTime:F2} seconds",
|
||||
interactionCount, responseTime);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
Console.WriteLine();
|
||||
|
||||
stopwatch.Stop();
|
||||
var responseTime = stopwatch.Elapsed.TotalSeconds;
|
||||
|
||||
// Record error metrics
|
||||
interactionCounter.Add(1, new KeyValuePair<string, object?>("status", "error"));
|
||||
responseTimeHistogram.Record(responseTime,
|
||||
new KeyValuePair<string, object?>("status", "error"));
|
||||
|
||||
activity?
|
||||
.SetTag("response.success", false)
|
||||
.SetTag("error.message", ex.Message)
|
||||
.SetStatus(ActivityStatusCode.Error, ex.Message);
|
||||
|
||||
appLogger.LogError(ex, "Agent interaction #{InteractionNumber} failed after {ResponseTime:F2} seconds: {ErrorMessage}",
|
||||
interactionCount, responseTime, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// Add session summary to the parent span
|
||||
sessionActivity?
|
||||
.SetTag("session.total_interactions", interactionCount)
|
||||
.SetTag("session.end_time", DateTimeOffset.UtcNow.ToString("O"));
|
||||
|
||||
appLogger.LogInformation("Agent session completed. Total interactions: {TotalInteractions}", interactionCount);
|
||||
} // End of logging scope
|
||||
|
||||
appLogger.LogInformation("OpenTelemetry Aspire Demo application shutting down");
|
||||
@@ -0,0 +1,229 @@
|
||||
# OpenTelemetry Aspire Demo with Microsoft Foundry
|
||||
|
||||
This demo showcases the integration of OpenTelemetry with the Microsoft Agent Framework using Microsoft Foundry and the .NET Aspire Dashboard for telemetry visualization.
|
||||
|
||||
## Overview
|
||||
|
||||
The demo consists of three main components:
|
||||
|
||||
1. **Aspire Dashboard** - Provides a web-based interface to visualize OpenTelemetry data
|
||||
2. **Console Application** - An interactive console application that demonstrates agent interactions with proper OpenTelemetry instrumentation
|
||||
3. **[Optional] Application Insights** - When the agent is deployed to a production environment, Application Insights can be used to monitor the agent performance.
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["Console App<br/>(Interactive)"] --> B["Agent Framework<br/>with OpenTel<br/>Instrumentation"]
|
||||
B --> C["Microsoft Foundry<br/>Project"]
|
||||
A --> D["Aspire Dashboard<br/>(OpenTelemetry Visualization)"]
|
||||
B --> D
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- .NET 10 SDK or later
|
||||
- Microsoft Foundry project endpoint and model configured
|
||||
- Azure CLI installed and authenticated (for Azure credential authentication)
|
||||
- Docker installed (for running Aspire Dashboard)
|
||||
- [Optional] Application Insights and Grafana
|
||||
|
||||
## Configuration
|
||||
|
||||
### Microsoft Foundry Setup
|
||||
Set the following environment variables:
|
||||
```powershell
|
||||
$env:FOUNDRY_PROJECT_ENDPOINT="https://<your-project>.services.ai.azure.com/api/projects/<your-project>"
|
||||
$env:FOUNDRY_MODEL="gpt-5.4-mini" # Optional, defaults to gpt-5.4-mini
|
||||
```
|
||||
|
||||
**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Foundry project.
|
||||
|
||||
### [Optional] Application Insights Setup
|
||||
Set the following environment variables:
|
||||
```powershell
|
||||
$env:APPLICATIONINSIGHTS_CONNECTION_STRING="InstrumentationKey=XXXX;IngestionEndpoint=https://XXXX.applicationinsights.azure.com/;LiveEndpoint=https://XXXXX.livediagnostics.monitor.azure.com/;ApplicationId=XXXXX"
|
||||
```
|
||||
|
||||
## Running the Demo
|
||||
|
||||
### Quick Start (Using Script)
|
||||
|
||||
The easiest way to run the demo is using the provided PowerShell script:
|
||||
|
||||
```powershell
|
||||
.\start-demo.ps1
|
||||
```
|
||||
|
||||
This script will automatically:
|
||||
- ✅ Check prerequisites (Docker, Foundry configuration)
|
||||
- 🔨 Build the console application
|
||||
- 🐳 Start the Aspire Dashboard via Docker (with anonymous access)
|
||||
- ⏳ Wait for dashboard to be ready (polls port until listening)
|
||||
- 🌐 Open your browser with the dashboard
|
||||
- 📊 Configure telemetry endpoints (http://localhost:4317)
|
||||
- 🎯 Start the interactive console application
|
||||
|
||||
### Manual Setup (Step by Step)
|
||||
|
||||
If you prefer to run the components manually:
|
||||
|
||||
#### Step 1: Start the Aspire Dashboard via Docker
|
||||
|
||||
```powershell
|
||||
docker run -d --name aspire-dashboard -p 4318:18888 -p 4317:18889 -e DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=true mcr.microsoft.com/dotnet/aspire-dashboard:latest
|
||||
```
|
||||
|
||||
#### Step 2: Access the Dashboard
|
||||
|
||||
Open your browser to: http://localhost:4318
|
||||
|
||||
#### Step 3: Run the Console Application
|
||||
|
||||
```powershell
|
||||
cd dotnet/demos/AgentOpenTelemetry
|
||||
$env:OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
|
||||
dotnet run
|
||||
```
|
||||
|
||||
#### Interacting with the Console Application
|
||||
|
||||
You should see a welcome message like:
|
||||
|
||||
```
|
||||
=== OpenTelemetry Aspire Demo ===
|
||||
This demo shows OpenTelemetry integration with the Agent Framework.
|
||||
You can view the telemetry data in the Aspire Dashboard.
|
||||
Type your message and press Enter. Type 'exit' or empty message to quit.
|
||||
|
||||
You:
|
||||
```
|
||||
|
||||
1. Type your message and press Enter to interact with the AI agent
|
||||
2. The agent will respond, and you can continue the conversation
|
||||
3. Type `exit` to stop the application
|
||||
|
||||
**Note**: Make sure the Aspire Dashboard is running before starting the console application, as the telemetry data will be sent to the dashboard.
|
||||
|
||||
#### Step 4: Test the Integration
|
||||
|
||||
1. **Start the Aspire Dashboard** (if not already running)
|
||||
2. **Run the Console Application** in a separate terminal
|
||||
3. **Send a test message** like "Hello, how are you?"
|
||||
4. **Check the Aspire Dashboard** - you should see:
|
||||
- New traces appearing in the **Traces** tab
|
||||
- Each trace showing the complete agent interaction flow
|
||||
- Metrics in the **Metrics** tab showing token usage and duration
|
||||
- Logs in the **Structured Logs** tab with detailed information
|
||||
|
||||
## Viewing Telemetry Data in Aspire Dashboard
|
||||
|
||||
### Traces
|
||||
1. In the Aspire Dashboard, navigate to the **Traces** tab
|
||||
2. You'll see traces for each agent interaction
|
||||
3. Each trace contains:
|
||||
- An outer span for the entire agent interaction
|
||||
- Inner spans from the Agent Framework's OpenTelemetry instrumentation
|
||||
- Spans from HTTP calls to Microsoft Foundry
|
||||
|
||||
### Metrics
|
||||
1. Navigate to the **Metrics** tab
|
||||
2. View metrics related to:
|
||||
- Agent execution duration
|
||||
- Token usage (input/output tokens)
|
||||
- Request counts
|
||||
|
||||
### Logs
|
||||
1. Navigate to the **Structured Logs** tab
|
||||
2. Filter by the console application to see detailed logs
|
||||
3. Logs include information about user inputs, agent responses, and any errors
|
||||
|
||||
## [Optional] View Application Insights data in Grafana
|
||||
Besides the Aspire Dashboard and the Application Insights native UI, you can also use Grafana to visualize the telemetry data in Application Insights. There are two tailored dashboards for you to get started quickly:
|
||||
|
||||
### Agent Overview dashboard
|
||||
Open dashboard in Azure portal: <https://aka.ms/amg/dash/af-agent>
|
||||

|
||||
|
||||
### Workflow Overview dashboard
|
||||
Open dashboard in Azure portal: <https://aka.ms/amg/dash/af-workflow>
|
||||

|
||||
|
||||
## Key Features Demonstrated
|
||||
|
||||
### OpenTelemetry Integration
|
||||
- **Automatic instrumentation** of Agent Framework operations
|
||||
- **Custom spans** for user interactions
|
||||
- **Proper span lifecycle management** (create → execute → close)
|
||||
- **Telemetry correlation** across the entire request flow
|
||||
|
||||
### Agent Framework Features
|
||||
- **ChatClientAgent** created from `AIProjectClient`
|
||||
- **OpenTelemetry wrapper** using `.WithOpenTelemetry()`
|
||||
- **Conversation threading** for multi-turn conversations
|
||||
- **Error handling** with telemetry correlation
|
||||
|
||||
### Aspire Dashboard Features
|
||||
- **Real-time telemetry visualization**
|
||||
- **Distributed tracing** across services
|
||||
- **Metrics and logging** integration
|
||||
- **Resource management** and monitoring
|
||||
|
||||
## Available Script
|
||||
|
||||
The demo includes a PowerShell script to make running the demo easy:
|
||||
|
||||
### `start-demo.ps1`
|
||||
Complete demo startup script that handles everything automatically.
|
||||
|
||||
**Usage:**
|
||||
```powershell
|
||||
.\start-demo.ps1 # Start the complete demo
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- **Automatic configuration detection** - Checks for Foundry configuration
|
||||
- **Project building** - Automatically builds projects before running
|
||||
- **Error handling** - Provides clear error messages if something goes wrong
|
||||
- **Multi-window support** - Opens dashboard in separate window for better experience
|
||||
- **Browser auto-launch** - Automatically opens the Aspire Dashboard in your browser
|
||||
- **Docker integration** - Uses Docker to run the Aspire Dashboard
|
||||
|
||||
**Docker Endpoints:**
|
||||
- **Aspire Dashboard**: `http://localhost:4318`
|
||||
- **OTLP Telemetry**: `http://localhost:4317`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port Conflicts
|
||||
If you encounter port binding errors, try:
|
||||
1. Stop any existing Docker containers using the same ports (`docker stop aspire-dashboard`)
|
||||
2. Or kill any processes using the conflicting ports
|
||||
|
||||
### Authentication Issues
|
||||
- Ensure your Foundry project endpoint is correctly configured
|
||||
- Check that the environment variables are set in the correct terminal session
|
||||
- Verify you're logged in with Azure CLI (`az login`) and have access to the Foundry project
|
||||
- Ensure the `FOUNDRY_MODEL` value matches an enabled model in your Foundry project
|
||||
|
||||
### Build Issues
|
||||
- Ensure you're using .NET 10.0 SDK
|
||||
- Run `dotnet restore` if you encounter package restore issues
|
||||
- Check that all project references are correctly resolved
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
AgentOpenTelemetry/
|
||||
├── AgentOpenTelemetry.csproj # Project file with dependencies
|
||||
├── Program.cs # Main application with Foundry AIProjectClient agent integration
|
||||
├── start-demo.ps1 # PowerShell script to start the demo
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Experiment with different prompts to see various telemetry patterns
|
||||
- Explore the Aspire Dashboard's filtering and search capabilities
|
||||
- Try modifying the OpenTelemetry configuration to add custom metrics or spans
|
||||
- Integrate additional services to see distributed tracing in action
|
||||
@@ -0,0 +1,139 @@
|
||||
# OpenTelemetry Console Demo with Aspire Dashboard (Docker)
|
||||
# This script starts the Aspire Dashboard via Docker and the Console Application
|
||||
|
||||
Write-Host "Starting OpenTelemetry Console Demo..." -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Check if we're in the right directory
|
||||
if (!(Test-Path "AgentOpenTelemetry.csproj")) {
|
||||
Write-Host "Error: Please run this script from the AgentOpenTelemetry directory" -ForegroundColor Red
|
||||
Write-Host "Expected to find AgentOpenTelemetry.csproj file" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if Docker is running
|
||||
try {
|
||||
docker version | Out-Null
|
||||
Write-Host "Docker is running" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "Docker is not running or not installed" -ForegroundColor Red
|
||||
Write-Host "Please start Docker Desktop and try again" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check for Azure OpenAI configuration
|
||||
if ($env:AZURE_OPENAI_ENDPOINT) {
|
||||
Write-Host "Found Azure OpenAI endpoint: $($env:AZURE_OPENAI_ENDPOINT)" -ForegroundColor Green
|
||||
if ($env:AZURE_OPENAI_DEPLOYMENT_NAME) {
|
||||
Write-Host "Using deployment: $($env:AZURE_OPENAI_DEPLOYMENT_NAME)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "Using default deployment: gpt-4o-mini" -ForegroundColor Cyan
|
||||
}
|
||||
} else {
|
||||
Write-Host "Warning: AZURE_OPENAI_ENDPOINT not found!" -ForegroundColor Yellow
|
||||
Write-Host "Please set the AZURE_OPENAI_ENDPOINT environment variable" -ForegroundColor Yellow
|
||||
Write-Host "Example: `$env:AZURE_OPENAI_ENDPOINT='https://your-resource.openai.azure.com/'" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Build console application
|
||||
Write-Host ""
|
||||
Write-Host "Building console application..." -ForegroundColor Cyan
|
||||
|
||||
$buildResult = dotnet build --verbosity quiet
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "Failed to build Console App" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "Build completed successfully" -ForegroundColor Green
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Starting Aspire Dashboard via Docker..." -ForegroundColor Cyan
|
||||
|
||||
# Stop any existing Aspire Dashboard container
|
||||
Write-Host "Stopping any existing Aspire Dashboard container..." -ForegroundColor Gray
|
||||
docker stop aspire-dashboard-afdemo 2>$null | Out-Null
|
||||
docker rm aspire-dashboard-afdemo 2>$null | Out-Null
|
||||
|
||||
# Start Aspire Dashboard in Docker daemon mode with fixed token
|
||||
Write-Host "Starting Aspire Dashboard container..." -ForegroundColor Green
|
||||
$fixedToken = "demo-token-12345"
|
||||
$dockerResult = docker run -d `
|
||||
--name aspire-dashboard-afdemo `
|
||||
-p 4318:18888 `
|
||||
-p 4317:18889 `
|
||||
-e DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=true `
|
||||
--restart unless-stopped `
|
||||
mcr.microsoft.com/dotnet/aspire-dashboard:latest
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "Failed to start Aspire Dashboard container" -ForegroundColor Red
|
||||
Write-Host "Make sure Docker is running and try again" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "Aspire Dashboard started successfully!" -ForegroundColor Green
|
||||
Write-Host "OTLP Endpoint: http://localhost:4318" -ForegroundColor Cyan
|
||||
|
||||
# Wait for dashboard to be ready by polling the port
|
||||
Write-Host "Waiting for dashboard to be ready..." -ForegroundColor Gray
|
||||
$maxWaitSeconds = 10
|
||||
$waitCount = 0
|
||||
$dashboardReady = $false
|
||||
|
||||
while ($waitCount -lt $maxWaitSeconds -and !$dashboardReady) {
|
||||
try {
|
||||
$tcpConnection = Test-NetConnection -ComputerName "localhost" -Port 4317 -InformationLevel Quiet -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
|
||||
if ($tcpConnection) {
|
||||
$dashboardReady = $true
|
||||
Write-Host "Dashboard is ready! (took $waitCount seconds)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "." -NoNewline -ForegroundColor Gray
|
||||
Start-Sleep -Seconds 1
|
||||
$waitCount++
|
||||
}
|
||||
} catch {
|
||||
Write-Host "." -NoNewline -ForegroundColor Gray
|
||||
Start-Sleep -Seconds 1
|
||||
$waitCount++
|
||||
}
|
||||
}
|
||||
|
||||
if (!$dashboardReady) {
|
||||
Write-Host ""
|
||||
Write-Host "Dashboard port 4317 not responding after $maxWaitSeconds seconds" -ForegroundColor Yellow
|
||||
Write-Host " Continuing anyway - dashboard might still be starting..." -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Open the dashboard in browser (anonymous access enabled)
|
||||
Write-Host "Opening dashboard in browser..." -ForegroundColor Green
|
||||
Write-Host "Dashboard URL: http://localhost:4318" -ForegroundColor Cyan
|
||||
Start-Process "http://localhost:4318"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Starting Console Application..." -ForegroundColor Cyan
|
||||
Write-Host "You can now interact with the AI agent!" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Set the OTLP endpoint for the console application (Docker Aspire Dashboard)
|
||||
$otlpEndpoint = "http://localhost:4317"
|
||||
Write-Host "Using OTLP endpoint: $otlpEndpoint" -ForegroundColor Cyan
|
||||
|
||||
$env:OTEL_EXPORTER_OTLP_ENDPOINT = $otlpEndpoint
|
||||
|
||||
# Start the console application in the current window
|
||||
Write-Host ""
|
||||
Write-Host "Starting the console application..." -ForegroundColor Green
|
||||
Write-Host "Tip: The dashboard should now be open in your browser!" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
dotnet run --no-build
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Demo completed!" -ForegroundColor Green
|
||||
Write-Host "The Aspire Dashboard is still running in Docker." -ForegroundColor Gray
|
||||
Write-Host "You can view telemetry data in the browser tab that opened." -ForegroundColor Gray
|
||||
Write-Host "To stop the dashboard: docker stop aspire-dashboard-afdemo" -ForegroundColor Gray
|
||||
Reference in New Issue
Block a user