From ac33659d7e851af87607459e4fb68895de0f44f2 Mon Sep 17 00:00:00 2001 From: M-Hietala <78813398+M-Hietala@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:35:06 -0500 Subject: [PATCH] adding sample for tracing custom attributes --- sdk/ai/Azure.AI.Projects/README.md | 44 +++++++ .../tests/Azure.AI.Projects.Tests.csproj | 4 +- .../Sample_Telemetry_CustomAttributes.cs | 124 ++++++++++++++++++ 3 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 sdk/ai/Azure.AI.Projects/tests/Samples/Telemetry/Sample_Telemetry_CustomAttributes.cs diff --git a/sdk/ai/Azure.AI.Projects/README.md b/sdk/ai/Azure.AI.Projects/README.md index 8db7d5b98b83..39aabaff3dde 100644 --- a/sdk/ai/Azure.AI.Projects/README.md +++ b/sdk/ai/Azure.AI.Projects/README.md @@ -33,6 +33,8 @@ See [full set of Agents samples](https://github.com/Azure/azure-sdk-for-net/tree - [Connections operations](#connections-operations) - [Dataset operations](#dataset-operations) - [Indexes operations](#indexes-operations) +- [Tracing](#tracing) + - [Adding custom attributes](#adding-custom-attributes) - [Troubleshooting](#troubleshooting) - [Next steps](#next-steps) - [Contributing](#contributing) @@ -360,6 +362,48 @@ Console.WriteLine("Delete the Index version created above:"); indexesClient.Delete(name: indexName, version: indexVersion); ``` +## Tracing + +### Adding custom attributes + +You can enhance telemetry data by adding custom attributes to activities through implementing a custom processor. This allows you to enrich trace data with application-specific context. + +The following example demonstrates how to create a custom processor that: +- Adds a `custom.session_id` attribute to all activities +- Adds `custom.operation_type` and `custom.priority` attributes specifically to 'GetWeather' activities: +```C# Snippet:AI_Projects_TelemetryCustomAttributeProcessor +// Custom processor that adds attributes to spans +public class CustomAttributeProcessor : BaseProcessor +{ + public override void OnStart(Activity activity) + { + // Add custom attributes to all spans + activity.SetTag("custom.session_id", "session_123"); + + // Add specific attributes based on span name + if (activity.DisplayName == "GetWeather") + { + activity.SetTag("custom.operation_type", "weather_query"); + activity.SetTag("custom.priority", "normal"); + } + + base.OnStart(activity); + } +} +``` + +Configure the processor into use like so: +```C# Snippet:AI_Projects_TelemetryAddCustomAttributeProcessor +// Setup tracing to console with custom processor +var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddSource("SimpleTracingSample") + .SetResourceBuilder(ResourceBuilder.CreateDefault() + .AddService("WeatherApp", "1.0.0")) + .AddProcessor(new CustomAttributeProcessor()) + .AddConsoleExporter() + .Build(); +``` + ## Troubleshooting Any operation that fails will throw a [RequestFailedException][RequestFailedException]. The exception's `code` will hold the HTTP response status code. The exception's `message` contains a detailed message that may be helpful in diagnosing the issue: diff --git a/sdk/ai/Azure.AI.Projects/tests/Azure.AI.Projects.Tests.csproj b/sdk/ai/Azure.AI.Projects/tests/Azure.AI.Projects.Tests.csproj index 55af3f348443..29b9ce0faef2 100644 --- a/sdk/ai/Azure.AI.Projects/tests/Azure.AI.Projects.Tests.csproj +++ b/sdk/ai/Azure.AI.Projects/tests/Azure.AI.Projects.Tests.csproj @@ -13,15 +13,17 @@ - + + + diff --git a/sdk/ai/Azure.AI.Projects/tests/Samples/Telemetry/Sample_Telemetry_CustomAttributes.cs b/sdk/ai/Azure.AI.Projects/tests/Samples/Telemetry/Sample_Telemetry_CustomAttributes.cs new file mode 100644 index 000000000000..118ba40a268c --- /dev/null +++ b/sdk/ai/Azure.AI.Projects/tests/Samples/Telemetry/Sample_Telemetry_CustomAttributes.cs @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using Azure.Monitor.OpenTelemetry.Exporter; +using NUnit.Framework; +using OpenTelemetry; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; + +namespace Azure.AI.Projects.Tests +{ + public partial class Sample_Telemetry_CustomAttributes : SamplesBase + { + #region Snippet:AI_Projects_TelemetryCustomAttributeProcessor + // Custom processor that adds attributes to spans + public class CustomAttributeProcessor : BaseProcessor + { + public override void OnStart(Activity activity) + { + // Add custom attributes to all spans + activity.SetTag("custom.session_id", "session_123"); + + // Add specific attributes based on span name + if (activity.DisplayName == "GetWeather") + { + activity.SetTag("custom.operation_type", "weather_query"); + activity.SetTag("custom.priority", "normal"); + } + + base.OnStart(activity); + } + } + #endregion + + public class WeatherService + { + private static readonly ActivitySource ActivitySource = new("SimpleTracingSample"); + + public async Task GetWeatherAsync(string location) + { + using var activity = ActivitySource.StartActivity("GetWeather"); + activity?.SetTag("weather.location", location); + + // Simulate some work + await Task.Delay(100); + + var result = "It is sunny"; + activity?.SetTag("weather.result", result); + + return result; + } + + public string GetWeather(string location) + { + using var activity = ActivitySource.StartActivity("GetWeather"); + activity?.SetTag("weather.location", location); + + var result = "It is sunny"; + activity?.SetTag("weather.result", result); + + return result; + } + } + + [Test] + [AsyncOnly] + public async Task TracingCustomAttributesExample() + { + #region Snippet:AI_Projects_TelemetryAddCustomAttributeProcessor + // Setup tracing to console with custom processor + var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddSource("SimpleTracingSample") + .SetResourceBuilder(ResourceBuilder.CreateDefault() + .AddService("WeatherApp", "1.0.0")) + .AddProcessor(new CustomAttributeProcessor()) + .AddConsoleExporter() + .Build(); + #endregion + + var weatherService = new WeatherService(); + + Console.WriteLine("Calling async GetWeatherAsync..."); + var asyncResult = await weatherService.GetWeatherAsync("Portland"); + Console.WriteLine($"Result: {asyncResult}\n"); + + // Cleanup + tracerProvider?.Dispose(); + } + + [Test] + [SyncOnly] + public void TracingCustomAttributesExampleSync() + { + // Setup tracing to console with custom processor + var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddSource("SimpleTracingSample") + .SetResourceBuilder(ResourceBuilder.CreateDefault() + .AddService("WeatherApp", "1.0.0")) + .AddProcessor(new CustomAttributeProcessor()) + .AddConsoleExporter() + .Build(); + + var weatherService = new WeatherService(); + + // Test sync version + Console.WriteLine("Calling sync GetWeather..."); + var syncResult = weatherService.GetWeather("Seattle"); + Console.WriteLine($"Result: {syncResult}\n"); + + // Cleanup + tracerProvider?.Dispose(); + Console.WriteLine("Check console output above for spans with custom attributes!"); + } + } +}