diff --git a/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/OpenTelemetryChatClient.cs b/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/OpenTelemetryChatClient.cs index 4157e644a23..df1717b4faa 100644 --- a/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/OpenTelemetryChatClient.cs +++ b/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/OpenTelemetryChatClient.cs @@ -302,7 +302,8 @@ public override async IAsyncEnumerable GetStreamingResponseA if (_system is not null) { - if (options.AdditionalProperties is { } props) + // Since AdditionalProperties has undefined meaning, we treat it as potentially sensitive data + if (EnableSensitiveData && options.AdditionalProperties is { } props) { // Log all additional request options as per-provider tags. This is non-normative, but it covers cases where // there's a per-provider specification in a best-effort manner (e.g. gen_ai.openai.request.service_tier), @@ -404,11 +405,12 @@ private void TraceResponse( if (_system is not null) { - // Log all additional response properties as per-provider tags. This is non-normative, but it covers cases where - // there's a per-provider specification in a best-effort manner (e.g. gen_ai.openai.response.system_fingerprint), - // and more generally cases where there's additional useful information to be logged. - if (response.AdditionalProperties is { } props) + // Since AdditionalProperties has undefined meaning, we treat it as potentially sensitive data + if (EnableSensitiveData && response.AdditionalProperties is { } props) { + // Log all additional response properties as per-provider tags. This is non-normative, but it covers cases where + // there's a per-provider specification in a best-effort manner (e.g. gen_ai.openai.response.system_fingerprint), + // and more generally cases where there's additional useful information to be logged. foreach (KeyValuePair prop in props) { _ = activity.AddTag( diff --git a/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/OpenTelemetryChatClientTests.cs b/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/OpenTelemetryChatClientTests.cs index 37ae545c04c..4d0122c7c92 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/OpenTelemetryChatClientTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/OpenTelemetryChatClientTests.cs @@ -165,16 +165,16 @@ async static IAsyncEnumerable CallbackAsync( Assert.Equal(7, activity.GetTagItem("gen_ai.request.top_k")); Assert.Equal(123, activity.GetTagItem("gen_ai.request.max_tokens")); Assert.Equal("""["hello", "world"]""", activity.GetTagItem("gen_ai.request.stop_sequences")); - Assert.Equal("value1", activity.GetTagItem("gen_ai.testservice.request.service_tier")); - Assert.Equal("value2", activity.GetTagItem("gen_ai.testservice.request.something_else")); + Assert.Equal(enableSensitiveData ? "value1" : null, activity.GetTagItem("gen_ai.testservice.request.service_tier")); + Assert.Equal(enableSensitiveData ? "value2" : null, activity.GetTagItem("gen_ai.testservice.request.something_else")); Assert.Equal(42L, activity.GetTagItem("gen_ai.request.seed")); Assert.Equal("id123", activity.GetTagItem("gen_ai.response.id")); Assert.Equal("""["stop"]""", activity.GetTagItem("gen_ai.response.finish_reasons")); Assert.Equal(10, activity.GetTagItem("gen_ai.response.input_tokens")); Assert.Equal(20, activity.GetTagItem("gen_ai.response.output_tokens")); - Assert.Equal("abcdefgh", activity.GetTagItem("gen_ai.testservice.response.system_fingerprint")); - Assert.Equal("value2", activity.GetTagItem("gen_ai.testservice.response.and_something_else")); + Assert.Equal(enableSensitiveData ? "abcdefgh" : null, activity.GetTagItem("gen_ai.testservice.response.system_fingerprint")); + Assert.Equal(enableSensitiveData ? "value2" : null, activity.GetTagItem("gen_ai.testservice.response.and_something_else")); Assert.True(activity.Duration.TotalMilliseconds > 0);