Snippet
Copy only trusted baggage onto spans
A complete OpenTelemetry processor that tags child spans with your own conversation ID and ignores whatever the caller sent.
AI-generated, human-reviewed: the first draft was generated by an AI agent; I fact-checked, tested, and edited it. AI use policy
What it does#
Copies one server-generated baggage entry, gen_ai.conversation.id, onto child spans as a
tag, so every span of a conversation can be found by its ID. It skips the incoming request
span, because any baggage there came from the caller and is untrusted. The API setup clears
caller baggage at the request boundary; any later baggage is generated by the server.
You need#
- .NET 10 and
Azure.Monitor.OpenTelemetry.AspNetCore1.6.0 (orOpenTelemetry1.x) - Your API generates the conversation ID and sets the baggage itself before calling the agent, as shown in OpenTelemetry and Azure Monitor setup for an agent API
Where it goes#
Add the file to your API project and register it with .AddProcessor(new ConversationBaggageProcessor()).
// SPDX-License-Identifier: MIT
// Copyright (c) 2026 Sarang Datye
using System.Diagnostics;
using OpenTelemetry;
/// <summary>
/// Copies only the gen_ai.conversation.id baggage entry onto child spans as a tag.
/// Incoming request (server) spans are skipped, because any baggage they see came from the caller.
/// No other baggage entries, and no prompt or response content, are ever copied.
/// </summary>
public sealed class ConversationBaggageProcessor : BaseProcessor<Activity>
{
public const string BaggageKey = "gen_ai.conversation.id";
public override void OnStart(Activity activity)
{
// An incoming request span starts before the endpoint sets the baggage, so any value seen
// here came from the caller's baggage header: untrusted text that must not become span data.
if (activity.Kind == ActivityKind.Server)
{
return;
}
var conversationId = activity.GetBaggageItem(BaggageKey);
if (!string.IsNullOrEmpty(conversationId))
{
activity.SetTag(BaggageKey, conversationId);
}
}
}
Check that it works#
Send a request with a baggage: gen_ai.conversation.id=anything header. The request span has
no gen_ai.conversation.id tag; the agent’s child spans have the server-generated ID your
API set.