Skip to content

Commit 3645ccc

Browse files
authored
Change OpenTelemetryChatClient/EmbeddingGenerator to log raw additional properties (#6776)
For historical reasons (based on older versions of the genai convention), we were mangling the key names. Now just use the key names as sourced from the dictionary, enabling a developer to more easily augment the spans with data of their choice.
1 parent 44fbcce commit 3645ccc

File tree

5 files changed

+25
-55
lines changed

5 files changed

+25
-55
lines changed

src/Libraries/Microsoft.Extensions.AI/ChatCompletion/OpenTelemetryChatClient.cs

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -364,20 +364,13 @@ private static string SerializeChatMessages(IEnumerable<ChatMessage> messages, C
364364
}
365365
}
366366

367-
if (_providerName is not null)
367+
// Log all additional request options as raw values on the span.
368+
// Since AdditionalProperties has undefined meaning, we treat it as potentially sensitive data.
369+
if (EnableSensitiveData && options.AdditionalProperties is { } props)
368370
{
369-
// Since AdditionalProperties has undefined meaning, we treat it as potentially sensitive data
370-
if (EnableSensitiveData && options.AdditionalProperties is { } props)
371+
foreach (KeyValuePair<string, object?> prop in props)
371372
{
372-
// Log all additional request options as per-provider tags. This is non-normative, but it covers cases where
373-
// there's a per-provider specification in a best-effort manner (e.g. gen_ai.openai.request.service_tier),
374-
// and more generally cases where there's additional useful information to be logged.
375-
foreach (KeyValuePair<string, object?> prop in props)
376-
{
377-
_ = activity.AddTag(
378-
OpenTelemetryConsts.GenAI.Request.PerProvider(_providerName, JsonNamingPolicy.SnakeCaseLower.ConvertName(prop.Key)),
379-
prop.Value);
380-
}
373+
_ = activity.AddTag(prop.Key, prop.Value);
381374
}
382375
}
383376
}
@@ -467,20 +460,13 @@ private void TraceResponse(
467460
_ = activity.AddTag(OpenTelemetryConsts.GenAI.Usage.OutputTokens, (int)outputTokens);
468461
}
469462

470-
if (_providerName is not null)
463+
// Log all additional response properties as raw values on the span.
464+
// Since AdditionalProperties has undefined meaning, we treat it as potentially sensitive data.
465+
if (EnableSensitiveData && response.AdditionalProperties is { } props)
471466
{
472-
// Since AdditionalProperties has undefined meaning, we treat it as potentially sensitive data
473-
if (EnableSensitiveData && response.AdditionalProperties is { } props)
467+
foreach (KeyValuePair<string, object?> prop in props)
474468
{
475-
// Log all additional response properties as per-provider tags. This is non-normative, but it covers cases where
476-
// there's a per-provider specification in a best-effort manner (e.g. gen_ai.openai.response.system_fingerprint),
477-
// and more generally cases where there's additional useful information to be logged.
478-
foreach (KeyValuePair<string, object?> prop in props)
479-
{
480-
_ = activity.AddTag(
481-
OpenTelemetryConsts.GenAI.Response.PerProvider(_providerName, JsonNamingPolicy.SnakeCaseLower.ConvertName(prop.Key)),
482-
prop.Value);
483-
}
469+
_ = activity.AddTag(prop.Key, prop.Value);
484470
}
485471
}
486472
}

src/Libraries/Microsoft.Extensions.AI/Embeddings/OpenTelemetryEmbeddingGenerator.cs

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Diagnostics;
77
using System.Diagnostics.Metrics;
88
using System.Linq;
9-
using System.Text.Json;
109
using System.Threading;
1110
using System.Threading.Tasks;
1211
using Microsoft.Extensions.Logging;
@@ -175,19 +174,13 @@ protected override void Dispose(bool disposing)
175174
_ = activity.AddTag(OpenTelemetryConsts.GenAI.Request.EmbeddingDimensions, dimensionsValue);
176175
}
177176

178-
// Log all additional request options as per-provider tags. This is non-normative, but it covers cases where
179-
// there's a per-provider specification in a best-effort manner (e.g. gen_ai.openai.request.service_tier),
180-
// and more generally cases where there's additional useful information to be logged.
177+
// Log all additional request options as raw values on the span.
181178
// Since AdditionalProperties has undefined meaning, we treat it as potentially sensitive data.
182-
if (EnableSensitiveData &&
183-
_providerName is not null &&
184-
options?.AdditionalProperties is { } props)
179+
if (EnableSensitiveData && options?.AdditionalProperties is { } props)
185180
{
186181
foreach (KeyValuePair<string, object?> prop in props)
187182
{
188-
_ = activity.AddTag(
189-
OpenTelemetryConsts.GenAI.Request.PerProvider(_providerName, JsonNamingPolicy.SnakeCaseLower.ConvertName(prop.Key)),
190-
prop.Value);
183+
_ = activity.AddTag(prop.Key, prop.Value);
191184
}
192185
}
193186
}
@@ -255,18 +248,13 @@ private void TraceResponse(
255248
_ = activity.AddTag(OpenTelemetryConsts.GenAI.Response.Model, responseModelId);
256249
}
257250

258-
// Log all additional response properties as per-provider tags. This is non-normative, but it covers cases where
259-
// there's a per-provider specification in a best-effort manner (e.g. gen_ai.openai.response.system_fingerprint),
260-
// and more generally cases where there's additional useful information to be logged.
261-
if (EnableSensitiveData &&
262-
_providerName is not null &&
263-
embeddings?.AdditionalProperties is { } props)
251+
// Log all additional response properties as raw values on the span.
252+
// Since AdditionalProperties has undefined meaning, we treat it as potentially sensitive data.
253+
if (EnableSensitiveData && embeddings?.AdditionalProperties is { } props)
264254
{
265255
foreach (KeyValuePair<string, object?> prop in props)
266256
{
267-
_ = activity.AddTag(
268-
OpenTelemetryConsts.GenAI.Response.PerProvider(_providerName, JsonNamingPolicy.SnakeCaseLower.ConvertName(prop.Key)),
269-
prop.Value);
257+
_ = activity.AddTag(prop.Key, prop.Value);
270258
}
271259
}
272260
}

src/Libraries/Microsoft.Extensions.AI/OpenTelemetryConsts.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,13 @@ public static class Request
9090
public const string Temperature = "gen_ai.request.temperature";
9191
public const string TopK = "gen_ai.request.top_k";
9292
public const string TopP = "gen_ai.request.top_p";
93-
94-
public static string PerProvider(string providerName, string parameterName) => $"{providerName}.request.{parameterName}";
9593
}
9694

9795
public static class Response
9896
{
9997
public const string FinishReasons = "gen_ai.response.finish_reasons";
10098
public const string Id = "gen_ai.response.id";
10199
public const string Model = "gen_ai.response.model";
102-
103-
public static string PerProvider(string providerName, string parameterName) => $"{providerName}.response.{parameterName}";
104100
}
105101

106102
public static class Token

test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/OpenTelemetryChatClientTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,16 +163,16 @@ async static IAsyncEnumerable<ChatResponseUpdate> CallbackAsync(
163163
Assert.Equal(7, activity.GetTagItem("gen_ai.request.top_k"));
164164
Assert.Equal(123, activity.GetTagItem("gen_ai.request.max_tokens"));
165165
Assert.Equal("""["hello", "world"]""", activity.GetTagItem("gen_ai.request.stop_sequences"));
166-
Assert.Equal(enableSensitiveData ? "value1" : null, activity.GetTagItem("testservice.request.service_tier"));
167-
Assert.Equal(enableSensitiveData ? "value2" : null, activity.GetTagItem("testservice.request.something_else"));
166+
Assert.Equal(enableSensitiveData ? "value1" : null, activity.GetTagItem("service_tier"));
167+
Assert.Equal(enableSensitiveData ? "value2" : null, activity.GetTagItem("SomethingElse"));
168168
Assert.Equal(42L, activity.GetTagItem("gen_ai.request.seed"));
169169

170170
Assert.Equal("id123", activity.GetTagItem("gen_ai.response.id"));
171171
Assert.Equal("""["stop"]""", activity.GetTagItem("gen_ai.response.finish_reasons"));
172172
Assert.Equal(10, activity.GetTagItem("gen_ai.usage.input_tokens"));
173173
Assert.Equal(20, activity.GetTagItem("gen_ai.usage.output_tokens"));
174-
Assert.Equal(enableSensitiveData ? "abcdefgh" : null, activity.GetTagItem("testservice.response.system_fingerprint"));
175-
Assert.Equal(enableSensitiveData ? "value2" : null, activity.GetTagItem("testservice.response.and_something_else"));
174+
Assert.Equal(enableSensitiveData ? "abcdefgh" : null, activity.GetTagItem("system_fingerprint"));
175+
Assert.Equal(enableSensitiveData ? "value2" : null, activity.GetTagItem("AndSomethingElse"));
176176

177177
Assert.True(activity.Duration.TotalMilliseconds > 0);
178178

test/Libraries/Microsoft.Extensions.AI.Tests/Embeddings/OpenTelemetryEmbeddingGeneratorTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,12 @@ public async Task ExpectedInformationLogged_Async(string? perRequestModelId, boo
8686

8787
Assert.Equal(expectedModelName, activity.GetTagItem("gen_ai.request.model"));
8888
Assert.Equal(1234, activity.GetTagItem("gen_ai.request.embedding.dimensions"));
89-
Assert.Equal(enableSensitiveData ? "value1" : null, activity.GetTagItem("testservice.request.service_tier"));
90-
Assert.Equal(enableSensitiveData ? "value2" : null, activity.GetTagItem("testservice.request.something_else"));
89+
Assert.Equal(enableSensitiveData ? "value1" : null, activity.GetTagItem("service_tier"));
90+
Assert.Equal(enableSensitiveData ? "value2" : null, activity.GetTagItem("SomethingElse"));
9191

9292
Assert.Equal(10, activity.GetTagItem("gen_ai.usage.input_tokens"));
93-
Assert.Equal(enableSensitiveData ? "abcdefgh" : null, activity.GetTagItem("testservice.response.system_fingerprint"));
94-
Assert.Equal(enableSensitiveData ? "value3" : null, activity.GetTagItem("testservice.response.and_something_else"));
93+
Assert.Equal(enableSensitiveData ? "abcdefgh" : null, activity.GetTagItem("system_fingerprint"));
94+
Assert.Equal(enableSensitiveData ? "value3" : null, activity.GetTagItem("AndSomethingElse"));
9595

9696
Assert.True(activity.Duration.TotalMilliseconds > 0);
9797
}

0 commit comments

Comments
 (0)