From 043c0b9e1baf0c89d11b67ecac1dd0fa9c717842 Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Thu, 5 Mar 2026 13:23:20 -0800 Subject: [PATCH 01/11] initial draft need to test --- .../src/Customizations/Models/MetricsData.cs | 24 +++- .../Customizations/Models/TelemetryItem.cs | 123 +++++++++++++++++- .../src/Internals/ActivityTagsProcessor.cs | 60 ++++++++- .../src/Internals/LogContextInfo.cs | 20 ++- .../src/Internals/LogsHelper.cs | 63 +++++++++ .../src/Internals/MetricHelper.cs | 67 +++++++++- .../Platform/EnvironmentVariableConstants.cs | 7 + .../src/Internals/SchemaConstants.cs | 8 ++ .../src/Internals/SemanticConventions.cs | 12 ++ 9 files changed, 377 insertions(+), 7 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs index 92ce5875d0f5..c3ab048bac55 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs @@ -26,9 +26,10 @@ public MetricsData(int version, Metric metric, MetricPoint metricPoint) : base(v Properties = new ChangeTrackingDictionary(); foreach (var tag in metricPoint.Tags) { - if (tag.Key.Length <= SchemaConstants.MetricsData_Properties_MaxKeyLength && tag.Value != null) + if (tag.Key.Length <= SchemaConstants.MetricsData_Properties_MaxKeyLength && tag.Value != null && !IsContextTagKey(tag.Key)) { // Note: if Key exceeds MaxLength or if Value is null, the entire KVP will be dropped. + // Context tag keys are excluded from Properties as they are mapped to envelope-level tags. if (tag.Value is Array array) { @@ -42,6 +43,27 @@ public MetricsData(int version, Metric metric, MetricPoint metricPoint) : base(v } } + private static bool IsContextTagKey(string key) + { + return key switch + { + SemanticConventions.AttributeEnduserId or + SemanticConventions.AttributeEnduserPseudoId or + SemanticConventions.AttributeClientAddress or + SemanticConventions.AttributeMicrosoftClientIp or + SemanticConventions.AttributeMicrosoftSessionId or + SemanticConventions.AttributeAiSessionIsFirst or + SemanticConventions.AttributeAiDeviceId or + SemanticConventions.AttributeAiDeviceModel or + SemanticConventions.AttributeAiDeviceOemName or + SemanticConventions.AttributeAiDeviceType or + SemanticConventions.AttributeAiDeviceOsVersion or + SemanticConventions.AttributeMicrosoftSyntheticSource or + SemanticConventions.AttributeMicrosoftUserAccountId => true, + _ => false, + }; + } + /// /// This constructor is used only for creating resource metrics with the name "_OTELRESOURCE_". /// diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs index f371a9aaf0f3..43ba3bfcf0dd 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs @@ -17,6 +17,7 @@ internal partial class TelemetryItem { private static volatile string? s_cloudRoleNameOverride; private static volatile string? s_cloudRoleInstanceOverride; + private static volatile string? s_componentVersionOverride; public TelemetryItem(Activity activity, ref ActivityTagsProcessor activityTagsProcessor, AzureMonitorResource? resource, string instrumentationKey, float sampleRate) : this(activity.GetTelemetryType() == TelemetryType.Request ? "Request" : "RemoteDependency", FormatUtcTimestamp(activity.StartTimeUtc)) @@ -28,7 +29,7 @@ public TelemetryItem(Activity activity, ref ActivityTagsProcessor activityTagsPr Tags[ContextTagKeys.AiOperationId.ToString()] = activity.TraceId.ToHexString(); - string? microsoftClientIp = AzMonList.GetTagValue(ref activityTagsProcessor.MappedTags, "microsoft.client.ip")?.ToString(); + string? microsoftClientIp = AzMonList.GetTagValue(ref activityTagsProcessor.MappedTags, SemanticConventions.AttributeMicrosoftClientIp)?.ToString(); // Check for microsoft.operation_name override (applies to both request and dependency) string? overrideOperationName = activityTagsProcessor.HasOverrideAttributes @@ -88,6 +89,7 @@ public TelemetryItem(Activity activity, ref ActivityTagsProcessor activityTagsPr } SetUserIdAndAuthenticatedUserId(ref activityTagsProcessor); + SetOverrideContextTags(ref activityTagsProcessor); SetResourceSdkVersionAndIkey(resource, instrumentationKey); if (sampleRate != 100f) @@ -112,6 +114,15 @@ public TelemetryItem(string name, TelemetryItem telemetryItem, ActivitySpanId ac Tags[ContextTagKeys.AiCloudRoleInstance.ToString()] = telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()].Truncate(SchemaConstants.Tags_AiCloudRoleInstance_MaxLength); Tags[ContextTagKeys.AiInternalSdkVersion.ToString()] = SdkVersionUtils.s_sdkVersion.Truncate(SchemaConstants.Tags_AiInternalSdkVersion_MaxLength); Tags[ContextTagKeys.AiApplicationVer.ToString()] = telemetryItem.Tags[ContextTagKeys.AiApplicationVer.ToString()].Truncate(SchemaConstants.Tags_AiApplicationVer_MaxLength); + CopyTagIfPresent(telemetryItem, ContextTagKeys.AiSessionId.ToString()); + CopyTagIfPresent(telemetryItem, ContextTagKeys.AiSessionIsFirst.ToString()); + CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceId.ToString()); + CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceModel.ToString()); + CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceOemName.ToString()); + CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceType.ToString()); + CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceOsVersion.ToString()); + CopyTagIfPresent(telemetryItem, ContextTagKeys.AiOperationSyntheticSource.ToString()); + CopyTagIfPresent(telemetryItem, ContextTagKeys.AiUserAccountId.ToString()); InstrumentationKey = telemetryItem.InstrumentationKey; if (telemetryItem.SampleRate != 100f) @@ -160,6 +171,51 @@ public TelemetryItem (string name, LogRecord logRecord, AzureMonitorResource? re { Tags[ContextTagKeys.AiOperationName.ToString()] = logContext.OperationName.Truncate(SchemaConstants.Tags_AiOperationName_MaxLength); } + + if (logContext.SessionId != null) + { + Tags[ContextTagKeys.AiSessionId.ToString()] = logContext.SessionId.Truncate(SchemaConstants.Tags_AiSessionId_MaxLength); + } + + if (logContext.SessionIsFirst != null) + { + Tags[ContextTagKeys.AiSessionIsFirst.ToString()] = logContext.SessionIsFirst; + } + + if (logContext.DeviceId != null) + { + Tags[ContextTagKeys.AiDeviceId.ToString()] = logContext.DeviceId.Truncate(SchemaConstants.Tags_AiDeviceId_MaxLength); + } + + if (logContext.DeviceModel != null) + { + Tags[ContextTagKeys.AiDeviceModel.ToString()] = logContext.DeviceModel.Truncate(SchemaConstants.Tags_AiDeviceModel_MaxLength); + } + + if (logContext.DeviceOemName != null) + { + Tags[ContextTagKeys.AiDeviceOemName.ToString()] = logContext.DeviceOemName.Truncate(SchemaConstants.Tags_AiDeviceOemName_MaxLength); + } + + if (logContext.DeviceType != null) + { + Tags[ContextTagKeys.AiDeviceType.ToString()] = logContext.DeviceType.Truncate(SchemaConstants.Tags_AiDeviceType_MaxLength); + } + + if (logContext.DeviceOsVersion != null) + { + Tags[ContextTagKeys.AiDeviceOsVersion.ToString()] = logContext.DeviceOsVersion.Truncate(SchemaConstants.Tags_AiDeviceOsVersion_MaxLength); + } + + if (logContext.SyntheticSource != null) + { + Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()] = logContext.SyntheticSource.Truncate(SchemaConstants.Tags_AiOperationSyntheticSource_MaxLength); + } + + if (logContext.UserAccountId != null) + { + Tags[ContextTagKeys.AiUserAccountId.ToString()] = logContext.UserAccountId.Truncate(SchemaConstants.Tags_AiUserAccountId_MaxLength); + } } InstrumentationKey = instrumentationKey; @@ -196,6 +252,12 @@ private void SetResourceSdkVersionAndIkey(AzureMonitorResource? resource, string { Tags[ContextTagKeys.AiCloudRoleInstance.ToString()] = roleInstance.Truncate(SchemaConstants.Tags_AiCloudRoleInstance_MaxLength); } + + var componentVersion = s_componentVersionOverride ?? (s_componentVersionOverride = Environment.GetEnvironmentVariable(EnvironmentVariableConstants.APPLICATIONINSIGHTS_COMPONENT_VERSION) ?? string.Empty); + if (componentVersion.Length > 0) + { + Tags[ContextTagKeys.AiApplicationVer.ToString()] = componentVersion.Truncate(SchemaConstants.Tags_AiApplicationVer_MaxLength); + } } /// @@ -205,6 +267,7 @@ internal static void ResetEnvironmentVariableOverrides() { s_cloudRoleNameOverride = null; s_cloudRoleInstanceOverride = null; + s_componentVersionOverride = null; } internal static DateTimeOffset FormatUtcTimestamp(System.DateTime utcTimestamp) @@ -212,6 +275,15 @@ internal static DateTimeOffset FormatUtcTimestamp(System.DateTime utcTimestamp) return DateTime.SpecifyKind(utcTimestamp, DateTimeKind.Utc); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CopyTagIfPresent(TelemetryItem source, string key) + { + if (source.Tags.TryGetValue(key, out string? value) && value != null) + { + Tags[key] = value; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void SetUserIdAndAuthenticatedUserId(ref ActivityTagsProcessor activityTagsProcessor) { @@ -225,5 +297,54 @@ private void SetUserIdAndAuthenticatedUserId(ref ActivityTagsProcessor activityT Tags[ContextTagKeys.AiUserId.ToString()] = activityTagsProcessor.EndUserPseudoId.Truncate(SchemaConstants.Tags_AiUserId_MaxLength); } } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetOverrideContextTags(ref ActivityTagsProcessor activityTagsProcessor) + { + if (activityTagsProcessor.SessionId != null) + { + Tags[ContextTagKeys.AiSessionId.ToString()] = activityTagsProcessor.SessionId.Truncate(SchemaConstants.Tags_AiSessionId_MaxLength); + } + + if (activityTagsProcessor.SessionIsFirst != null) + { + Tags[ContextTagKeys.AiSessionIsFirst.ToString()] = activityTagsProcessor.SessionIsFirst; + } + + if (activityTagsProcessor.DeviceId != null) + { + Tags[ContextTagKeys.AiDeviceId.ToString()] = activityTagsProcessor.DeviceId.Truncate(SchemaConstants.Tags_AiDeviceId_MaxLength); + } + + if (activityTagsProcessor.DeviceModel != null) + { + Tags[ContextTagKeys.AiDeviceModel.ToString()] = activityTagsProcessor.DeviceModel.Truncate(SchemaConstants.Tags_AiDeviceModel_MaxLength); + } + + if (activityTagsProcessor.DeviceOemName != null) + { + Tags[ContextTagKeys.AiDeviceOemName.ToString()] = activityTagsProcessor.DeviceOemName.Truncate(SchemaConstants.Tags_AiDeviceOemName_MaxLength); + } + + if (activityTagsProcessor.DeviceType != null) + { + Tags[ContextTagKeys.AiDeviceType.ToString()] = activityTagsProcessor.DeviceType.Truncate(SchemaConstants.Tags_AiDeviceType_MaxLength); + } + + if (activityTagsProcessor.DeviceOsVersion != null) + { + Tags[ContextTagKeys.AiDeviceOsVersion.ToString()] = activityTagsProcessor.DeviceOsVersion.Truncate(SchemaConstants.Tags_AiDeviceOsVersion_MaxLength); + } + + if (activityTagsProcessor.SyntheticSource != null) + { + Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()] = activityTagsProcessor.SyntheticSource.Truncate(SchemaConstants.Tags_AiOperationSyntheticSource_MaxLength); + } + + if (activityTagsProcessor.UserAccountId != null) + { + Tags[ContextTagKeys.AiUserAccountId.ToString()] = activityTagsProcessor.UserAccountId.Truncate(SchemaConstants.Tags_AiUserAccountId_MaxLength); + } + } } } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs index 67b96e13d775..2cad2a53b6cd 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs @@ -59,7 +59,7 @@ internal struct ActivityTagsProcessor // Others SemanticConventions.AttributeEnduserId, SemanticConventions.AttributeEnduserPseudoId, - "microsoft.client.ip", + SemanticConventions.AttributeMicrosoftClientIp, // Microsoft Application Insights Override Attributes SemanticConventions.AttributeMicrosoftDependencyData, @@ -71,7 +71,18 @@ internal struct ActivityTagsProcessor SemanticConventions.AttributeMicrosoftRequestName, SemanticConventions.AttributeMicrosoftRequestUrl, SemanticConventions.AttributeMicrosoftRequestSource, - SemanticConventions.AttributeMicrosoftRequestResultCode + SemanticConventions.AttributeMicrosoftRequestResultCode, + + // Context tag attributes from Application Insights shim + SemanticConventions.AttributeMicrosoftSessionId, + SemanticConventions.AttributeAiSessionIsFirst, + SemanticConventions.AttributeAiDeviceId, + SemanticConventions.AttributeAiDeviceModel, + SemanticConventions.AttributeAiDeviceOemName, + SemanticConventions.AttributeAiDeviceType, + SemanticConventions.AttributeAiDeviceOsVersion, + SemanticConventions.AttributeMicrosoftSyntheticSource, + SemanticConventions.AttributeMicrosoftUserAccountId, }; internal static readonly HashSet s_semanticsSet = new(s_semantics); @@ -87,6 +98,24 @@ internal struct ActivityTagsProcessor public string? EndUserPseudoId { get; private set; } = null; + public string? SessionId { get; private set; } = null; + + public string? SessionIsFirst { get; private set; } = null; + + public string? DeviceId { get; private set; } = null; + + public string? DeviceModel { get; private set; } = null; + + public string? DeviceOemName { get; private set; } = null; + + public string? DeviceType { get; private set; } = null; + + public string? DeviceOsVersion { get; private set; } = null; + + public string? SyntheticSource { get; private set; } = null; + + public string? UserAccountId { get; private set; } = null; + public bool HasOverrideAttributes { get; private set; } = false; public ActivityTagsProcessor() @@ -132,6 +161,33 @@ public void CategorizeTags(Activity activity) case SemanticConventions.AttributeEnduserPseudoId: EndUserPseudoId = tag.Value.ToString(); continue; + case SemanticConventions.AttributeMicrosoftSessionId: + SessionId = tag.Value.ToString(); + continue; + case SemanticConventions.AttributeAiSessionIsFirst: + SessionIsFirst = tag.Value.ToString(); + continue; + case SemanticConventions.AttributeAiDeviceId: + DeviceId = tag.Value.ToString(); + continue; + case SemanticConventions.AttributeAiDeviceModel: + DeviceModel = tag.Value.ToString(); + continue; + case SemanticConventions.AttributeAiDeviceOemName: + DeviceOemName = tag.Value.ToString(); + continue; + case SemanticConventions.AttributeAiDeviceType: + DeviceType = tag.Value.ToString(); + continue; + case SemanticConventions.AttributeAiDeviceOsVersion: + DeviceOsVersion = tag.Value.ToString(); + continue; + case SemanticConventions.AttributeMicrosoftSyntheticSource: + SyntheticSource = tag.Value.ToString(); + continue; + case SemanticConventions.AttributeMicrosoftUserAccountId: + UserAccountId = tag.Value.ToString(); + continue; case SemanticConventions.AttributeMicrosoftDependencyData: case SemanticConventions.AttributeMicrosoftDependencyName: case SemanticConventions.AttributeMicrosoftDependencyTarget: diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs index 6393432acf13..34b6dc441a95 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs @@ -14,6 +14,15 @@ internal struct LogContextInfo public string? EndUserId; public string? UserAgent; public string? OperationName; + public string? SessionId; + public string? SessionIsFirst; + public string? DeviceId; + public string? DeviceModel; + public string? DeviceOemName; + public string? DeviceType; + public string? DeviceOsVersion; + public string? SyntheticSource; + public string? UserAccountId; /// /// Returns true if any context field has been set. @@ -23,6 +32,15 @@ internal struct LogContextInfo EndUserPseudoId != null || EndUserId != null || UserAgent != null || - OperationName != null; + OperationName != null || + SessionId != null || + SessionIsFirst != null || + DeviceId != null || + DeviceModel != null || + DeviceOemName != null || + DeviceType != null || + DeviceOsVersion != null || + SyntheticSource != null || + UserAccountId != null; } } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs index f439d7f912f3..b1637ad1bf9c 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs @@ -26,6 +26,15 @@ internal static class LogsHelper private const string EndUserIdAttributeName = "enduser.id"; private const string UserAgentOriginalAttributeName = "user_agent.original"; private const string OperationNameAttributeName = "microsoft.operation_name"; + private const string SessionIdAttributeName = "microsoft.session.id"; + private const string SessionIsFirstAttributeName = "ai.session.isFirst"; + private const string DeviceIdAttributeName = "ai.device.id"; + private const string DeviceModelAttributeName = "ai.device.model"; + private const string DeviceOemNameAttributeName = "ai.device.oemName"; + private const string DeviceTypeAttributeName = "ai.device.type"; + private const string DeviceOsVersionAttributeName = "ai.device.osVersion"; + private const string SyntheticSourceAttributeName = "microsoft.synthetic_source"; + private const string UserAccountIdAttributeName = "microsoft.user.account_id"; private const string AvailabilityIdAttributeName = "microsoft.availability.id"; private const string AvailabilityNameAttributeName = "microsoft.availability.name"; private const string AvailabilityDurationAttributeName = "microsoft.availability.duration"; @@ -166,6 +175,33 @@ internal static void ProcessLogRecordProperties(LogRecord logRecord, IDictionary case OperationNameAttributeName: logContext.OperationName = item.Value?.ToString(); break; + case SessionIdAttributeName: + logContext.SessionId = item.Value?.ToString(); + break; + case SessionIsFirstAttributeName: + logContext.SessionIsFirst = item.Value?.ToString(); + break; + case DeviceIdAttributeName: + logContext.DeviceId = item.Value?.ToString(); + break; + case DeviceModelAttributeName: + logContext.DeviceModel = item.Value?.ToString(); + break; + case DeviceOemNameAttributeName: + logContext.DeviceOemName = item.Value?.ToString(); + break; + case DeviceTypeAttributeName: + logContext.DeviceType = item.Value?.ToString(); + break; + case DeviceOsVersionAttributeName: + logContext.DeviceOsVersion = item.Value?.ToString(); + break; + case SyntheticSourceAttributeName: + logContext.SyntheticSource = item.Value?.ToString(); + break; + case UserAccountIdAttributeName: + logContext.UserAccountId = item.Value?.ToString(); + break; default: // Note: if Key exceeds MaxLength, the entire KVP will be dropped. if (item.Key.Length <= SchemaConstants.MessageData_Properties_MaxKeyLength && item.Value != null) @@ -281,6 +317,33 @@ internal static void ProcessLogRecordProperties(LogRecord logRecord, IDictionary case OperationNameAttributeName: logContext.OperationName = item.Value?.ToString(); break; + case SessionIdAttributeName: + logContext.SessionId = item.Value?.ToString(); + break; + case SessionIsFirstAttributeName: + logContext.SessionIsFirst = item.Value?.ToString(); + break; + case DeviceIdAttributeName: + logContext.DeviceId = item.Value?.ToString(); + break; + case DeviceModelAttributeName: + logContext.DeviceModel = item.Value?.ToString(); + break; + case DeviceOemNameAttributeName: + logContext.DeviceOemName = item.Value?.ToString(); + break; + case DeviceTypeAttributeName: + logContext.DeviceType = item.Value?.ToString(); + break; + case DeviceOsVersionAttributeName: + logContext.DeviceOsVersion = item.Value?.ToString(); + break; + case SyntheticSourceAttributeName: + logContext.SyntheticSource = item.Value?.ToString(); + break; + case UserAccountIdAttributeName: + logContext.UserAccountId = item.Value?.ToString(); + break; default: if (item.Key.Length <= SchemaConstants.AvailabilityData_Properties_MaxValueLength && item.Value != null && !properties.ContainsKey(item.Key)) { diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs index d1477054746e..b4e0bb3a32be 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Azure.Monitor.OpenTelemetry.Exporter.Internals.CustomerSdkStats; using Azure.Monitor.OpenTelemetry.Exporter.Internals.Diagnostics; using Azure.Monitor.OpenTelemetry.Exporter.Models; @@ -26,14 +27,17 @@ internal static (List TelemetryItems, TelemetrySchemaTypeCounter { try { - telemetryItems.Add(new TelemetryItem(metricPoint.EndTime.UtcDateTime, resource, instrumentationKey) + var telemetryItem = new TelemetryItem(metricPoint.EndTime.UtcDateTime, resource, instrumentationKey) { Data = new MonitorBase { BaseType = "MetricData", BaseData = new MetricsData(Version, metric, metricPoint) } - }); + }; + + SetContextTagsFromMetricTags(telemetryItem, metricPoint); + telemetryItems.Add(telemetryItem); } catch (Exception ex) { @@ -44,5 +48,64 @@ internal static (List TelemetryItems, TelemetrySchemaTypeCounter return (telemetryItems, new TelemetrySchemaTypeCounter() { _metricCount = telemetryItems.Count }); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void SetContextTagsFromMetricTags(TelemetryItem telemetryItem, in MetricPoint metricPoint) + { + string? clientAddress = null; + string? microsoftClientIp = null; + + foreach (var tag in metricPoint.Tags) + { + switch (tag.Key) + { + case SemanticConventions.AttributeEnduserId: + telemetryItem.Tags[ContextTagKeys.AiUserAuthUserId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiUserAuthUserId_MaxLength); + break; + case SemanticConventions.AttributeEnduserPseudoId: + telemetryItem.Tags[ContextTagKeys.AiUserId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiUserId_MaxLength); + break; + case SemanticConventions.AttributeClientAddress: + clientAddress = tag.Value?.ToString(); + break; + case SemanticConventions.AttributeMicrosoftClientIp: + microsoftClientIp = tag.Value?.ToString(); + break; + case SemanticConventions.AttributeMicrosoftSessionId: + telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiSessionId_MaxLength); + break; + case SemanticConventions.AttributeAiSessionIsFirst: + telemetryItem.Tags[ContextTagKeys.AiSessionIsFirst.ToString()] = tag.Value?.ToString(); + break; + case SemanticConventions.AttributeAiDeviceId: + telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceId_MaxLength); + break; + case SemanticConventions.AttributeAiDeviceModel: + telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceModel_MaxLength); + break; + case SemanticConventions.AttributeAiDeviceOemName: + telemetryItem.Tags[ContextTagKeys.AiDeviceOemName.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceOemName_MaxLength); + break; + case SemanticConventions.AttributeAiDeviceType: + telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceType_MaxLength); + break; + case SemanticConventions.AttributeAiDeviceOsVersion: + telemetryItem.Tags[ContextTagKeys.AiDeviceOsVersion.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceOsVersion_MaxLength); + break; + case SemanticConventions.AttributeMicrosoftSyntheticSource: + telemetryItem.Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiOperationSyntheticSource_MaxLength); + break; + case SemanticConventions.AttributeMicrosoftUserAccountId: + telemetryItem.Tags[ContextTagKeys.AiUserAccountId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiUserAccountId_MaxLength); + break; + } + } + + var locationIp = microsoftClientIp ?? clientAddress; + if (locationIp != null) + { + telemetryItem.Tags[ContextTagKeys.AiLocationIp.ToString()] = locationIp; + } + } } } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/Platform/EnvironmentVariableConstants.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/Platform/EnvironmentVariableConstants.cs index 48ccc9656815..c1243fc7228e 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/Platform/EnvironmentVariableConstants.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/Platform/EnvironmentVariableConstants.cs @@ -19,6 +19,7 @@ internal static class EnvironmentVariableConstants APPLICATIONINSIGHTS_SDKSTATS_EXPORT_INTERVAL, APPLICATIONINSIGHTS_CLOUD_ROLE_NAME, APPLICATIONINSIGHTS_CLOUD_ROLE_INSTANCE, + APPLICATIONINSIGHTS_COMPONENT_VERSION, FUNCTIONS_WORKER_RUNTIME, LOCALAPPDATA, TEMP, @@ -154,5 +155,11 @@ internal static class EnvironmentVariableConstants /// the cloud role instance after the OTel Resource has been built and is immutable. /// public const string APPLICATIONINSIGHTS_CLOUD_ROLE_INSTANCE = "APPLICATIONINSIGHTS_CLOUD_ROLE_INSTANCE"; + + /// + /// Set by the Application Insights shim (TelemetryClient.Context.Component.Version) to override + /// the application version after the OTel Resource has been built and is immutable. + /// + public const string APPLICATIONINSIGHTS_COMPONENT_VERSION = "APPLICATIONINSIGHTS_COMPONENT_VERSION"; } } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SchemaConstants.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SchemaConstants.cs index 7aba060084eb..b720004df354 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SchemaConstants.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SchemaConstants.cs @@ -126,5 +126,13 @@ internal static class SchemaConstants public const int Tags_AiCloudRole_MaxLength = 256; public const int Tags_AiCloudRoleInstance_MaxLength = 256; public const int Tags_AiInternalSdkVersion_MaxLength = 64; + public const int Tags_AiSessionId_MaxLength = 64; + public const int Tags_AiDeviceId_MaxLength = 1024; + public const int Tags_AiDeviceModel_MaxLength = 256; + public const int Tags_AiDeviceOemName_MaxLength = 256; + public const int Tags_AiDeviceType_MaxLength = 64; + public const int Tags_AiDeviceOsVersion_MaxLength = 256; + public const int Tags_AiOperationSyntheticSource_MaxLength = 1024; + public const int Tags_AiUserAccountId_MaxLength = 1024; } } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SemanticConventions.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SemanticConventions.cs index 09a776e6a9d9..59da476a30ee 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SemanticConventions.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SemanticConventions.cs @@ -239,5 +239,17 @@ internal static class SemanticConventions /// When present, takes precedence over computed result code from semantic conventions. /// public const string AttributeMicrosoftRequestResultCode = "microsoft.request.resultCode"; + + // Context tag attributes set by the Application Insights shim (TelemetryClient.Context) + public const string AttributeMicrosoftClientIp = "microsoft.client.ip"; + public const string AttributeMicrosoftSessionId = "microsoft.session.id"; + public const string AttributeAiSessionIsFirst = "ai.session.isFirst"; + public const string AttributeAiDeviceId = "ai.device.id"; + public const string AttributeAiDeviceModel = "ai.device.model"; + public const string AttributeAiDeviceOemName = "ai.device.oemName"; + public const string AttributeAiDeviceType = "ai.device.type"; + public const string AttributeAiDeviceOsVersion = "ai.device.osVersion"; + public const string AttributeMicrosoftSyntheticSource = "microsoft.synthetic_source"; + public const string AttributeMicrosoftUserAccountId = "microsoft.user.account_id"; } } From 43dc4b048ab0cb6c38cfce7d72d424180472d737 Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Thu, 5 Mar 2026 13:47:58 -0800 Subject: [PATCH 02/11] tests --- .../E2ETelemetryItemValidation/LogsTests.cs | 57 ++++++++++++++ .../MetricsTests.cs | 53 +++++++++++++ .../E2ETelemetryItemValidation/TracesTests.cs | 77 +++++++++++++++++++ 3 files changed, 187 insertions(+) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs index 65a479dca5d7..82a99d7d0d8f 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Azure.Monitor.OpenTelemetry.Exporter.Models; +using Azure.Monitor.OpenTelemetry.Exporter.Internals; using Azure.Monitor.OpenTelemetry.Exporter.Tests.CommonTestFramework; using Microsoft.Extensions.Logging; using OpenTelemetry.Logs; @@ -204,5 +205,61 @@ public void VerifyLogWithClientIPMapsToAiLocationIp() expectedTraceId: null, expectedClientIp: "1.2.3.4"); } + + [Fact] + public void VerifyContextTagAttributes_MappedToEnvelopeTags() + { + // SETUP + var uniqueTestId = Guid.NewGuid(); + var logCategoryName = $"logCategoryName{uniqueTestId}"; + List? telemetryItems = null; + + var loggerFactory = LoggerFactory.Create(builder => + { + builder + .AddOpenTelemetry(options => + { + options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddAttributes(testResourceAttributes)); + options.AddAzureMonitorLogExporterForTest(out telemetryItems); + }); + }); + + // ACT + var logger = loggerFactory.CreateLogger(logCategoryName); + logger.LogInformation( + "{microsoft.session.id} {ai.session.isFirst} {ai.device.id} {ai.device.model} {ai.device.oemName} {ai.device.type} {ai.device.osVersion} {microsoft.synthetic_source} {microsoft.user.account_id}", + "session-123", "True", "device-456", "Surface Pro", "Microsoft", "PC", "Microsoft Windows NT 10.0.22621.0", "test-bot", "account-789"); + + // CLEANUP + loggerFactory.Dispose(); + + // ASSERT + Assert.True(telemetryItems?.Any(), "Unit test failed to collect telemetry."); + this.telemetryOutput.Write(telemetryItems); + var telemetryItem = telemetryItems!.First(x => x.Name == "Message"); + + // Verify context tags are mapped to envelope tags + Assert.Equal("session-123", telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()]); + Assert.Equal("True", telemetryItem.Tags[ContextTagKeys.AiSessionIsFirst.ToString()]); + Assert.Equal("device-456", telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()]); + Assert.Equal("Surface Pro", telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()]); + Assert.Equal("Microsoft", telemetryItem.Tags[ContextTagKeys.AiDeviceOemName.ToString()]); + Assert.Equal("PC", telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()]); + Assert.Equal("Microsoft Windows NT 10.0.22621.0", telemetryItem.Tags[ContextTagKeys.AiDeviceOsVersion.ToString()]); + Assert.Equal("test-bot", telemetryItem.Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()]); + Assert.Equal("account-789", telemetryItem.Tags[ContextTagKeys.AiUserAccountId.ToString()]); + + // Verify context tags are NOT in customDimensions + var messageData = (MessageData)telemetryItem.Data.BaseData; + Assert.False(messageData.Properties.ContainsKey("microsoft.session.id")); + Assert.False(messageData.Properties.ContainsKey("ai.session.isFirst")); + Assert.False(messageData.Properties.ContainsKey("ai.device.id")); + Assert.False(messageData.Properties.ContainsKey("ai.device.model")); + Assert.False(messageData.Properties.ContainsKey("ai.device.oemName")); + Assert.False(messageData.Properties.ContainsKey("ai.device.type")); + Assert.False(messageData.Properties.ContainsKey("ai.device.osVersion")); + Assert.False(messageData.Properties.ContainsKey("microsoft.synthetic_source")); + Assert.False(messageData.Properties.ContainsKey("microsoft.user.account_id")); + } } } \ No newline at end of file diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs index 8a8c3f1515af..7643764e8b2c 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs @@ -6,6 +6,7 @@ using System.Diagnostics.Metrics; using System.Linq; using Azure.Monitor.OpenTelemetry.Exporter.Models; +using Azure.Monitor.OpenTelemetry.Exporter.Internals; using Azure.Monitor.OpenTelemetry.Exporter.Tests.CommonTestFramework; using OpenTelemetry; using OpenTelemetry.Metrics; @@ -289,5 +290,57 @@ public void VerifyObservableUpDownCounter(bool asView) expectedMetricDataPointValue: 4, expectedMetricsProperties: new Dictionary { { "tag1", "value1" }, { "tag2", "value2" } }); } + + [Fact] + public void VerifyContextTagAttributes_MappedToEnvelopeTags() + { + // SETUP + var uniqueTestId = Guid.NewGuid(); + + var meterName = $"meterName{uniqueTestId}"; + using var meter = new Meter(meterName, "1.0"); + + var meterProvider = Sdk.CreateMeterProviderBuilder() + .ConfigureResource(x => x.AddAttributes(testResourceAttributes)) + .AddMeter(meterName) + .AddAzureMonitorMetricExporterForTest(out List telemetryItems) + .Build(); + + // ACT - emit a metric with all context tag attributes as dimensions + var counter = meter.CreateCounter("TestCounter"); + counter.Add(1, + new(SemanticConventions.AttributeMicrosoftSessionId, "session-123"), + new(SemanticConventions.AttributeAiSessionIsFirst, "True"), + new(SemanticConventions.AttributeAiDeviceId, "device-456"), + new(SemanticConventions.AttributeAiDeviceModel, "Surface Pro"), + new(SemanticConventions.AttributeAiDeviceOemName, "Microsoft"), + new(SemanticConventions.AttributeAiDeviceType, "PC"), + new(SemanticConventions.AttributeAiDeviceOsVersion, "Microsoft Windows NT 10.0.22621.0"), + new(SemanticConventions.AttributeMicrosoftSyntheticSource, "test-bot"), + new(SemanticConventions.AttributeMicrosoftUserAccountId, "account-789")); + + // CLEANUP + meterProvider?.Dispose(); + + // ASSERT + Assert.True(telemetryItems.Any(), "Unit test failed to collect telemetry."); + this.telemetryOutput.Write(telemetryItems); + var telemetryItem = telemetryItems.Last()!; + + // Verify context tags are mapped to envelope tags + Assert.Equal("session-123", telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()]); + Assert.Equal("True", telemetryItem.Tags[ContextTagKeys.AiSessionIsFirst.ToString()]); + Assert.Equal("device-456", telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()]); + Assert.Equal("Surface Pro", telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()]); + Assert.Equal("Microsoft", telemetryItem.Tags[ContextTagKeys.AiDeviceOemName.ToString()]); + Assert.Equal("PC", telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()]); + Assert.Equal("Microsoft Windows NT 10.0.22621.0", telemetryItem.Tags[ContextTagKeys.AiDeviceOsVersion.ToString()]); + Assert.Equal("test-bot", telemetryItem.Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()]); + Assert.Equal("account-789", telemetryItem.Tags[ContextTagKeys.AiUserAccountId.ToString()]); + + // Verify context tags are NOT in customDimensions (Properties) + var metricsData = (MetricsData)telemetryItem.Data.BaseData; + Assert.Empty(metricsData.Properties); + } } } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs index 3e1f0152f637..c143cd2549cd 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; using Azure.Monitor.OpenTelemetry.Exporter.Models; +using Azure.Monitor.OpenTelemetry.Exporter.Internals; using Azure.Monitor.OpenTelemetry.Exporter.Tests.CommonTestFramework; using Microsoft.Extensions.Logging; using OpenTelemetry; @@ -361,5 +362,81 @@ public void TestActivityEvents() expectedSpanId: spanId, expectedTraceId: traceId); } + + [Theory] + [InlineData(ActivityKind.Client, "RemoteDependency")] + [InlineData(ActivityKind.Server, "Request")] + public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activityKind, string expectedTelemetryName) + { + // SETUP + var uniqueTestId = Guid.NewGuid(); + + var activitySourceName = $"activitySourceName{uniqueTestId}"; + using var activitySource = new ActivitySource(activitySourceName); + + var tracerProvider = Sdk.CreateTracerProviderBuilder() + .ConfigureResource(x => x.AddAttributes(testResourceAttributes)) + .AddSource(activitySourceName) + .AddAzureMonitorTraceExporterForTest(out List telemetryItems) + .Build(); + + // ACT + using (var activity = activitySource.StartActivity(name: "TestOperation", kind: activityKind)) + { + Assert.NotNull(activity); + + // Set all context tag attributes from the shim + activity.SetTag(SemanticConventions.AttributeMicrosoftSessionId, "session-123"); + activity.SetTag(SemanticConventions.AttributeAiSessionIsFirst, "True"); + activity.SetTag(SemanticConventions.AttributeAiDeviceId, "device-456"); + activity.SetTag(SemanticConventions.AttributeAiDeviceModel, "Surface Pro"); + activity.SetTag(SemanticConventions.AttributeAiDeviceOemName, "Microsoft"); + activity.SetTag(SemanticConventions.AttributeAiDeviceType, "PC"); + activity.SetTag(SemanticConventions.AttributeAiDeviceOsVersion, "Microsoft Windows NT 10.0.22621.0"); + activity.SetTag(SemanticConventions.AttributeMicrosoftSyntheticSource, "test-bot"); + activity.SetTag(SemanticConventions.AttributeMicrosoftUserAccountId, "account-789"); + } + + // CLEANUP + tracerProvider?.Dispose(); + + // ASSERT + Assert.True(telemetryItems.Any(), "Unit test failed to collect telemetry."); + this.telemetryOutput.Write(telemetryItems); + var telemetryItem = telemetryItems.First(x => x.Name == expectedTelemetryName); + + // Verify context tags are mapped to envelope tags + Assert.Equal("session-123", telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()]); + Assert.Equal("True", telemetryItem.Tags[ContextTagKeys.AiSessionIsFirst.ToString()]); + Assert.Equal("device-456", telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()]); + Assert.Equal("Surface Pro", telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()]); + Assert.Equal("Microsoft", telemetryItem.Tags[ContextTagKeys.AiDeviceOemName.ToString()]); + Assert.Equal("PC", telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()]); + Assert.Equal("Microsoft Windows NT 10.0.22621.0", telemetryItem.Tags[ContextTagKeys.AiDeviceOsVersion.ToString()]); + Assert.Equal("test-bot", telemetryItem.Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()]); + Assert.Equal("account-789", telemetryItem.Tags[ContextTagKeys.AiUserAccountId.ToString()]); + + // Verify context tags are NOT in customDimensions + var baseData = telemetryItem.Data.BaseData; + IDictionary properties; + if (baseData is RemoteDependencyData depData) + { + properties = depData.Properties; + } + else + { + properties = ((RequestData)baseData).Properties; + } + + Assert.False(properties.ContainsKey(SemanticConventions.AttributeMicrosoftSessionId)); + Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiSessionIsFirst)); + Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceId)); + Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceModel)); + Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceOemName)); + Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceType)); + Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceOsVersion)); + Assert.False(properties.ContainsKey(SemanticConventions.AttributeMicrosoftSyntheticSource)); + Assert.False(properties.ContainsKey(SemanticConventions.AttributeMicrosoftUserAccountId)); + } } } From 63245941e509e2a3c2f2e72a0d1c12d10e4b5537 Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Tue, 10 Mar 2026 09:45:26 -0700 Subject: [PATCH 03/11] remove some tags and other changes --- .../src/Customizations/Models/MetricsData.cs | 23 +--------- .../Customizations/Models/TelemetryItem.cs | 28 ------------ .../src/Internals/ActivityTagsProcessor.cs | 12 ----- .../src/Internals/LogContextInfo.cs | 6 --- .../src/Internals/LogsHelper.cs | 21 --------- .../src/Internals/MetricHelper.cs | 6 --- .../src/Internals/SchemaConstants.cs | 1 - .../src/Internals/SemanticConventions.cs | 2 - .../LogsHelperTests.cs | 45 ++++--------------- .../TelemetryItemTests.cs | 31 +++++++++++++ 10 files changed, 40 insertions(+), 135 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs index c3ab048bac55..28244e1c3925 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs @@ -26,7 +26,7 @@ public MetricsData(int version, Metric metric, MetricPoint metricPoint) : base(v Properties = new ChangeTrackingDictionary(); foreach (var tag in metricPoint.Tags) { - if (tag.Key.Length <= SchemaConstants.MetricsData_Properties_MaxKeyLength && tag.Value != null && !IsContextTagKey(tag.Key)) + if (tag.Key.Length <= SchemaConstants.MetricsData_Properties_MaxKeyLength && tag.Value != null) { // Note: if Key exceeds MaxLength or if Value is null, the entire KVP will be dropped. // Context tag keys are excluded from Properties as they are mapped to envelope-level tags. @@ -43,27 +43,6 @@ public MetricsData(int version, Metric metric, MetricPoint metricPoint) : base(v } } - private static bool IsContextTagKey(string key) - { - return key switch - { - SemanticConventions.AttributeEnduserId or - SemanticConventions.AttributeEnduserPseudoId or - SemanticConventions.AttributeClientAddress or - SemanticConventions.AttributeMicrosoftClientIp or - SemanticConventions.AttributeMicrosoftSessionId or - SemanticConventions.AttributeAiSessionIsFirst or - SemanticConventions.AttributeAiDeviceId or - SemanticConventions.AttributeAiDeviceModel or - SemanticConventions.AttributeAiDeviceOemName or - SemanticConventions.AttributeAiDeviceType or - SemanticConventions.AttributeAiDeviceOsVersion or - SemanticConventions.AttributeMicrosoftSyntheticSource or - SemanticConventions.AttributeMicrosoftUserAccountId => true, - _ => false, - }; - } - /// /// This constructor is used only for creating resource metrics with the name "_OTELRESOURCE_". /// diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs index 43ba3bfcf0dd..da957fe6e99d 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs @@ -115,10 +115,8 @@ public TelemetryItem(string name, TelemetryItem telemetryItem, ActivitySpanId ac Tags[ContextTagKeys.AiInternalSdkVersion.ToString()] = SdkVersionUtils.s_sdkVersion.Truncate(SchemaConstants.Tags_AiInternalSdkVersion_MaxLength); Tags[ContextTagKeys.AiApplicationVer.ToString()] = telemetryItem.Tags[ContextTagKeys.AiApplicationVer.ToString()].Truncate(SchemaConstants.Tags_AiApplicationVer_MaxLength); CopyTagIfPresent(telemetryItem, ContextTagKeys.AiSessionId.ToString()); - CopyTagIfPresent(telemetryItem, ContextTagKeys.AiSessionIsFirst.ToString()); CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceId.ToString()); CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceModel.ToString()); - CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceOemName.ToString()); CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceType.ToString()); CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceOsVersion.ToString()); CopyTagIfPresent(telemetryItem, ContextTagKeys.AiOperationSyntheticSource.ToString()); @@ -161,12 +159,6 @@ public TelemetryItem (string name, LogRecord logRecord, AzureMonitorResource? re Tags[ContextTagKeys.AiUserAuthUserId.ToString()] = logContext.EndUserId.Truncate(SchemaConstants.Tags_AiUserAuthUserId_MaxLength); } - if (logContext.UserAgent != null) - { - // todo: update swagger to include this key. - Tags["ai.user.userAgent"] = logContext.UserAgent; - } - if (logContext.OperationName != null) { Tags[ContextTagKeys.AiOperationName.ToString()] = logContext.OperationName.Truncate(SchemaConstants.Tags_AiOperationName_MaxLength); @@ -177,11 +169,6 @@ public TelemetryItem (string name, LogRecord logRecord, AzureMonitorResource? re Tags[ContextTagKeys.AiSessionId.ToString()] = logContext.SessionId.Truncate(SchemaConstants.Tags_AiSessionId_MaxLength); } - if (logContext.SessionIsFirst != null) - { - Tags[ContextTagKeys.AiSessionIsFirst.ToString()] = logContext.SessionIsFirst; - } - if (logContext.DeviceId != null) { Tags[ContextTagKeys.AiDeviceId.ToString()] = logContext.DeviceId.Truncate(SchemaConstants.Tags_AiDeviceId_MaxLength); @@ -192,11 +179,6 @@ public TelemetryItem (string name, LogRecord logRecord, AzureMonitorResource? re Tags[ContextTagKeys.AiDeviceModel.ToString()] = logContext.DeviceModel.Truncate(SchemaConstants.Tags_AiDeviceModel_MaxLength); } - if (logContext.DeviceOemName != null) - { - Tags[ContextTagKeys.AiDeviceOemName.ToString()] = logContext.DeviceOemName.Truncate(SchemaConstants.Tags_AiDeviceOemName_MaxLength); - } - if (logContext.DeviceType != null) { Tags[ContextTagKeys.AiDeviceType.ToString()] = logContext.DeviceType.Truncate(SchemaConstants.Tags_AiDeviceType_MaxLength); @@ -306,11 +288,6 @@ private void SetOverrideContextTags(ref ActivityTagsProcessor activityTagsProces Tags[ContextTagKeys.AiSessionId.ToString()] = activityTagsProcessor.SessionId.Truncate(SchemaConstants.Tags_AiSessionId_MaxLength); } - if (activityTagsProcessor.SessionIsFirst != null) - { - Tags[ContextTagKeys.AiSessionIsFirst.ToString()] = activityTagsProcessor.SessionIsFirst; - } - if (activityTagsProcessor.DeviceId != null) { Tags[ContextTagKeys.AiDeviceId.ToString()] = activityTagsProcessor.DeviceId.Truncate(SchemaConstants.Tags_AiDeviceId_MaxLength); @@ -321,11 +298,6 @@ private void SetOverrideContextTags(ref ActivityTagsProcessor activityTagsProces Tags[ContextTagKeys.AiDeviceModel.ToString()] = activityTagsProcessor.DeviceModel.Truncate(SchemaConstants.Tags_AiDeviceModel_MaxLength); } - if (activityTagsProcessor.DeviceOemName != null) - { - Tags[ContextTagKeys.AiDeviceOemName.ToString()] = activityTagsProcessor.DeviceOemName.Truncate(SchemaConstants.Tags_AiDeviceOemName_MaxLength); - } - if (activityTagsProcessor.DeviceType != null) { Tags[ContextTagKeys.AiDeviceType.ToString()] = activityTagsProcessor.DeviceType.Truncate(SchemaConstants.Tags_AiDeviceType_MaxLength); diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs index 2cad2a53b6cd..669a503d11fa 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs @@ -75,10 +75,8 @@ internal struct ActivityTagsProcessor // Context tag attributes from Application Insights shim SemanticConventions.AttributeMicrosoftSessionId, - SemanticConventions.AttributeAiSessionIsFirst, SemanticConventions.AttributeAiDeviceId, SemanticConventions.AttributeAiDeviceModel, - SemanticConventions.AttributeAiDeviceOemName, SemanticConventions.AttributeAiDeviceType, SemanticConventions.AttributeAiDeviceOsVersion, SemanticConventions.AttributeMicrosoftSyntheticSource, @@ -100,14 +98,10 @@ internal struct ActivityTagsProcessor public string? SessionId { get; private set; } = null; - public string? SessionIsFirst { get; private set; } = null; - public string? DeviceId { get; private set; } = null; public string? DeviceModel { get; private set; } = null; - public string? DeviceOemName { get; private set; } = null; - public string? DeviceType { get; private set; } = null; public string? DeviceOsVersion { get; private set; } = null; @@ -164,18 +158,12 @@ public void CategorizeTags(Activity activity) case SemanticConventions.AttributeMicrosoftSessionId: SessionId = tag.Value.ToString(); continue; - case SemanticConventions.AttributeAiSessionIsFirst: - SessionIsFirst = tag.Value.ToString(); - continue; case SemanticConventions.AttributeAiDeviceId: DeviceId = tag.Value.ToString(); continue; case SemanticConventions.AttributeAiDeviceModel: DeviceModel = tag.Value.ToString(); continue; - case SemanticConventions.AttributeAiDeviceOemName: - DeviceOemName = tag.Value.ToString(); - continue; case SemanticConventions.AttributeAiDeviceType: DeviceType = tag.Value.ToString(); continue; diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs index 34b6dc441a95..2f9270039c55 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs @@ -12,13 +12,10 @@ internal struct LogContextInfo public string? MicrosoftClientIp; public string? EndUserPseudoId; public string? EndUserId; - public string? UserAgent; public string? OperationName; public string? SessionId; - public string? SessionIsFirst; public string? DeviceId; public string? DeviceModel; - public string? DeviceOemName; public string? DeviceType; public string? DeviceOsVersion; public string? SyntheticSource; @@ -31,13 +28,10 @@ internal struct LogContextInfo MicrosoftClientIp != null || EndUserPseudoId != null || EndUserId != null || - UserAgent != null || OperationName != null || SessionId != null || - SessionIsFirst != null || DeviceId != null || DeviceModel != null || - DeviceOemName != null || DeviceType != null || DeviceOsVersion != null || SyntheticSource != null || diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs index b1637ad1bf9c..e079a52eedc9 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs @@ -24,13 +24,10 @@ internal static class LogsHelper private const string ClientIpAttributeName = "microsoft.client.ip"; private const string EndUserPseudoIdAttributeName = "enduser.pseudo.id"; private const string EndUserIdAttributeName = "enduser.id"; - private const string UserAgentOriginalAttributeName = "user_agent.original"; private const string OperationNameAttributeName = "microsoft.operation_name"; private const string SessionIdAttributeName = "microsoft.session.id"; - private const string SessionIsFirstAttributeName = "ai.session.isFirst"; private const string DeviceIdAttributeName = "ai.device.id"; private const string DeviceModelAttributeName = "ai.device.model"; - private const string DeviceOemNameAttributeName = "ai.device.oemName"; private const string DeviceTypeAttributeName = "ai.device.type"; private const string DeviceOsVersionAttributeName = "ai.device.osVersion"; private const string SyntheticSourceAttributeName = "microsoft.synthetic_source"; @@ -169,27 +166,18 @@ internal static void ProcessLogRecordProperties(LogRecord logRecord, IDictionary case EndUserIdAttributeName: logContext.EndUserId = item.Value?.ToString(); break; - case UserAgentOriginalAttributeName: - logContext.UserAgent = item.Value?.ToString(); - break; case OperationNameAttributeName: logContext.OperationName = item.Value?.ToString(); break; case SessionIdAttributeName: logContext.SessionId = item.Value?.ToString(); break; - case SessionIsFirstAttributeName: - logContext.SessionIsFirst = item.Value?.ToString(); - break; case DeviceIdAttributeName: logContext.DeviceId = item.Value?.ToString(); break; case DeviceModelAttributeName: logContext.DeviceModel = item.Value?.ToString(); break; - case DeviceOemNameAttributeName: - logContext.DeviceOemName = item.Value?.ToString(); - break; case DeviceTypeAttributeName: logContext.DeviceType = item.Value?.ToString(); break; @@ -311,27 +299,18 @@ internal static void ProcessLogRecordProperties(LogRecord logRecord, IDictionary case EndUserIdAttributeName: logContext.EndUserId = item.Value?.ToString(); break; - case UserAgentOriginalAttributeName: - logContext.UserAgent = item.Value?.ToString(); - break; case OperationNameAttributeName: logContext.OperationName = item.Value?.ToString(); break; case SessionIdAttributeName: logContext.SessionId = item.Value?.ToString(); break; - case SessionIsFirstAttributeName: - logContext.SessionIsFirst = item.Value?.ToString(); - break; case DeviceIdAttributeName: logContext.DeviceId = item.Value?.ToString(); break; case DeviceModelAttributeName: logContext.DeviceModel = item.Value?.ToString(); break; - case DeviceOemNameAttributeName: - logContext.DeviceOemName = item.Value?.ToString(); - break; case DeviceTypeAttributeName: logContext.DeviceType = item.Value?.ToString(); break; diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs index b4e0bb3a32be..765e845195f1 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs @@ -74,18 +74,12 @@ private static void SetContextTagsFromMetricTags(TelemetryItem telemetryItem, in case SemanticConventions.AttributeMicrosoftSessionId: telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiSessionId_MaxLength); break; - case SemanticConventions.AttributeAiSessionIsFirst: - telemetryItem.Tags[ContextTagKeys.AiSessionIsFirst.ToString()] = tag.Value?.ToString(); - break; case SemanticConventions.AttributeAiDeviceId: telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceId_MaxLength); break; case SemanticConventions.AttributeAiDeviceModel: telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceModel_MaxLength); break; - case SemanticConventions.AttributeAiDeviceOemName: - telemetryItem.Tags[ContextTagKeys.AiDeviceOemName.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceOemName_MaxLength); - break; case SemanticConventions.AttributeAiDeviceType: telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceType_MaxLength); break; diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SchemaConstants.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SchemaConstants.cs index b720004df354..44698a15a8ba 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SchemaConstants.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SchemaConstants.cs @@ -129,7 +129,6 @@ internal static class SchemaConstants public const int Tags_AiSessionId_MaxLength = 64; public const int Tags_AiDeviceId_MaxLength = 1024; public const int Tags_AiDeviceModel_MaxLength = 256; - public const int Tags_AiDeviceOemName_MaxLength = 256; public const int Tags_AiDeviceType_MaxLength = 64; public const int Tags_AiDeviceOsVersion_MaxLength = 256; public const int Tags_AiOperationSyntheticSource_MaxLength = 1024; diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SemanticConventions.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SemanticConventions.cs index 59da476a30ee..1f227aabe2f8 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SemanticConventions.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SemanticConventions.cs @@ -243,10 +243,8 @@ internal static class SemanticConventions // Context tag attributes set by the Application Insights shim (TelemetryClient.Context) public const string AttributeMicrosoftClientIp = "microsoft.client.ip"; public const string AttributeMicrosoftSessionId = "microsoft.session.id"; - public const string AttributeAiSessionIsFirst = "ai.session.isFirst"; public const string AttributeAiDeviceId = "ai.device.id"; public const string AttributeAiDeviceModel = "ai.device.model"; - public const string AttributeAiDeviceOemName = "ai.device.oemName"; public const string AttributeAiDeviceType = "ai.device.type"; public const string AttributeAiDeviceOsVersion = "ai.device.osVersion"; public const string AttributeMicrosoftSyntheticSource = "microsoft.synthetic_source"; diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs index db83aaf046db..73e092588311 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs @@ -793,30 +793,6 @@ public void VerifyEndUserId_ExtractedIntoLogContext() Assert.False(properties.ContainsKey("enduser.id"), "enduser.id should not appear in customDimensions"); } - [Fact] - public void VerifyUserAgentOriginal_ExtractedIntoLogContext() - { - // Arrange. - var logRecords = new List(1); - using var loggerFactory = LoggerFactory.Create(builder => - { - builder.AddOpenTelemetry(options => - { - options.AddInMemoryExporter(logRecords); - }); - }); - - var logger = loggerFactory.CreateLogger("Some category"); - logger.LogInformation("{user_agent.original}", "Mozilla/5.0"); - - // Assert. - var properties = new ChangeTrackingDictionary(); - LogsHelper.ProcessLogRecordProperties(logRecords[0], properties, out var message, out var eventName, out LogContextInfo logContext, out var availabilityInfo); - - Assert.Equal("Mozilla/5.0", logContext.UserAgent); - Assert.False(properties.ContainsKey("user_agent.original"), "user_agent.original should not appear in customDimensions"); - } - [Fact] public void VerifyOperationName_ExtractedIntoLogContext() { @@ -856,8 +832,8 @@ public void VerifyAllContextAttributes_ExtractedTogether() var logger = loggerFactory.CreateLogger("Some category"); logger.LogInformation( - "{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {user_agent.original} {microsoft.operation_name}", - "1.2.3.4", "User123", "AuthUser123", "Mozilla/5.0", "SampleOp"); + "{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {microsoft.operation_name}", + "1.2.3.4", "User123", "AuthUser123", "SampleOp"); // Assert. var properties = new ChangeTrackingDictionary(); @@ -866,14 +842,12 @@ public void VerifyAllContextAttributes_ExtractedTogether() Assert.Equal("1.2.3.4", logContext.MicrosoftClientIp); Assert.Equal("User123", logContext.EndUserPseudoId); Assert.Equal("AuthUser123", logContext.EndUserId); - Assert.Equal("Mozilla/5.0", logContext.UserAgent); Assert.Equal("SampleOp", logContext.OperationName); // None of these should leak into customDimensions Assert.False(properties.ContainsKey("microsoft.client.ip")); Assert.False(properties.ContainsKey("enduser.pseudo.id")); Assert.False(properties.ContainsKey("enduser.id")); - Assert.False(properties.ContainsKey("user_agent.original")); Assert.False(properties.ContainsKey("microsoft.operation_name")); } @@ -900,7 +874,6 @@ public void VerifyLogContextDefaults_WhenNoContextAttributesPresent() Assert.Null(logContext.MicrosoftClientIp); Assert.Null(logContext.EndUserPseudoId); Assert.Null(logContext.EndUserId); - Assert.Null(logContext.UserAgent); Assert.Null(logContext.OperationName); } @@ -930,19 +903,19 @@ public void VerifyContextAttributes_MappedToEnvelopeTags(string baseType) } catch (Exception ex) { - logger.LogError(ex, "{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {user_agent.original} {microsoft.operation_name}", - "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestAgent/1.0", "TestOperation"); + logger.LogError(ex, "{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {microsoft.operation_name}", + "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestOperation"); } } else if (baseType == "EventData") { - logger.LogInformation("{microsoft.custom_event.name} {microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {user_agent.original} {microsoft.operation_name}", - "TestEvent", "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestAgent/1.0", "TestOperation"); + logger.LogInformation("{microsoft.custom_event.name} {microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {microsoft.operation_name}", + "TestEvent", "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestOperation"); } else { - logger.LogInformation("{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {user_agent.original} {microsoft.operation_name}", - "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestAgent/1.0", "TestOperation"); + logger.LogInformation("{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {microsoft.operation_name}", + "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestOperation"); } var logResource = new AzureMonitorResource( @@ -958,7 +931,6 @@ public void VerifyContextAttributes_MappedToEnvelopeTags(string baseType) Assert.Equal("10.0.0.1", item.Tags[ContextTagKeys.AiLocationIp.ToString()]); Assert.Equal("PseudoUser", item.Tags[ContextTagKeys.AiUserId.ToString()]); Assert.Equal("AuthenticatedUser", item.Tags[ContextTagKeys.AiUserAuthUserId.ToString()]); - Assert.Equal("TestAgent/1.0", item.Tags["ai.user.userAgent"]); Assert.Equal("TestOperation", item.Tags[ContextTagKeys.AiOperationName.ToString()]); // Verify base type @@ -994,7 +966,6 @@ public void VerifyContextAttributes_NotInEnvelopeTags_WhenAbsent() Assert.False(item.Tags.ContainsKey(ContextTagKeys.AiLocationIp.ToString())); Assert.False(item.Tags.ContainsKey(ContextTagKeys.AiUserId.ToString())); Assert.False(item.Tags.ContainsKey(ContextTagKeys.AiUserAuthUserId.ToString())); - Assert.False(item.Tags.ContainsKey("ai.user.userAgent")); Assert.False(item.Tags.ContainsKey(ContextTagKeys.AiOperationName.ToString())); } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TelemetryItemTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TelemetryItemTests.cs index 9629bbbdd00e..34d123f178ef 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TelemetryItemTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TelemetryItemTests.cs @@ -691,6 +691,37 @@ public void CloudRoleNameOverriddenByEnvironmentVariable() } } + [Fact] + public void ComponentVersionOverriddenByEnvironmentVariable() + { + var priorComponentVersion = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_COMPONENT_VERSION"); + TelemetryItem.ResetEnvironmentVariableOverrides(); + try + { + Environment.SetEnvironmentVariable("APPLICATIONINSIGHTS_COMPONENT_VERSION", "2.0.0-beta1"); + + using ActivitySource activitySource = new ActivitySource(ActivitySourceName); + using var activity = activitySource.StartActivity( + ActivityName, + ActivityKind.Client, + parentContext: default, + startTime: DateTime.UtcNow) + ?? throw new Exception("Failed to create Activity"); + + var resource = CreateTestResource(serviceName: "my-service", serviceInstance: "my-instance"); + var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity); + var traceResource = resource.CreateAzureMonitorResource(instrumentationKey: null, platform: GetMockPlatform()); + var telemetryItem = new TelemetryItem(activity, ref activityTagsProcessor, traceResource, "00000000-0000-0000-0000-000000000000", 1.0f); + + Assert.Equal("2.0.0-beta1", telemetryItem.Tags[ContextTagKeys.AiApplicationVer.ToString()]); + } + finally + { + Environment.SetEnvironmentVariable("APPLICATIONINSIGHTS_COMPONENT_VERSION", priorComponentVersion); + TelemetryItem.ResetEnvironmentVariableOverrides(); + } + } + /// /// If SERVICE.NAME is not defined, it will fall-back to "unknown_service". /// (https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/resource/semantic_conventions#semantic-attributes-with-sdk-provided-default-value). From 8704b9786b0fd088c537ebc5c38e3c7b9a8dc28c Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Mon, 16 Mar 2026 17:03:18 -0700 Subject: [PATCH 04/11] cleanup metrics --- .../src/Customizations/Models/MetricsData.cs | 1 - .../MetricsTests.cs | 52 ------------------- 2 files changed, 53 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs index 28244e1c3925..92ce5875d0f5 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/MetricsData.cs @@ -29,7 +29,6 @@ public MetricsData(int version, Metric metric, MetricPoint metricPoint) : base(v if (tag.Key.Length <= SchemaConstants.MetricsData_Properties_MaxKeyLength && tag.Value != null) { // Note: if Key exceeds MaxLength or if Value is null, the entire KVP will be dropped. - // Context tag keys are excluded from Properties as they are mapped to envelope-level tags. if (tag.Value is Array array) { diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs index 7643764e8b2c..ffe23aa017ac 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs @@ -290,57 +290,5 @@ public void VerifyObservableUpDownCounter(bool asView) expectedMetricDataPointValue: 4, expectedMetricsProperties: new Dictionary { { "tag1", "value1" }, { "tag2", "value2" } }); } - - [Fact] - public void VerifyContextTagAttributes_MappedToEnvelopeTags() - { - // SETUP - var uniqueTestId = Guid.NewGuid(); - - var meterName = $"meterName{uniqueTestId}"; - using var meter = new Meter(meterName, "1.0"); - - var meterProvider = Sdk.CreateMeterProviderBuilder() - .ConfigureResource(x => x.AddAttributes(testResourceAttributes)) - .AddMeter(meterName) - .AddAzureMonitorMetricExporterForTest(out List telemetryItems) - .Build(); - - // ACT - emit a metric with all context tag attributes as dimensions - var counter = meter.CreateCounter("TestCounter"); - counter.Add(1, - new(SemanticConventions.AttributeMicrosoftSessionId, "session-123"), - new(SemanticConventions.AttributeAiSessionIsFirst, "True"), - new(SemanticConventions.AttributeAiDeviceId, "device-456"), - new(SemanticConventions.AttributeAiDeviceModel, "Surface Pro"), - new(SemanticConventions.AttributeAiDeviceOemName, "Microsoft"), - new(SemanticConventions.AttributeAiDeviceType, "PC"), - new(SemanticConventions.AttributeAiDeviceOsVersion, "Microsoft Windows NT 10.0.22621.0"), - new(SemanticConventions.AttributeMicrosoftSyntheticSource, "test-bot"), - new(SemanticConventions.AttributeMicrosoftUserAccountId, "account-789")); - - // CLEANUP - meterProvider?.Dispose(); - - // ASSERT - Assert.True(telemetryItems.Any(), "Unit test failed to collect telemetry."); - this.telemetryOutput.Write(telemetryItems); - var telemetryItem = telemetryItems.Last()!; - - // Verify context tags are mapped to envelope tags - Assert.Equal("session-123", telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()]); - Assert.Equal("True", telemetryItem.Tags[ContextTagKeys.AiSessionIsFirst.ToString()]); - Assert.Equal("device-456", telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()]); - Assert.Equal("Surface Pro", telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()]); - Assert.Equal("Microsoft", telemetryItem.Tags[ContextTagKeys.AiDeviceOemName.ToString()]); - Assert.Equal("PC", telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()]); - Assert.Equal("Microsoft Windows NT 10.0.22621.0", telemetryItem.Tags[ContextTagKeys.AiDeviceOsVersion.ToString()]); - Assert.Equal("test-bot", telemetryItem.Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()]); - Assert.Equal("account-789", telemetryItem.Tags[ContextTagKeys.AiUserAccountId.ToString()]); - - // Verify context tags are NOT in customDimensions (Properties) - var metricsData = (MetricsData)telemetryItem.Data.BaseData; - Assert.Empty(metricsData.Properties); - } } } From 9beb16ab7ce7f91e8810f6c63c6401612c8c32dc Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Thu, 19 Mar 2026 14:41:53 -0700 Subject: [PATCH 05/11] remove isFirst and oemName from tests --- .../E2ETelemetryItemValidation/LogsTests.cs | 8 ++------ .../E2ETelemetryItemValidation/MetricsTests.cs | 1 - .../E2ETelemetryItemValidation/TracesTests.cs | 6 ------ 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs index 82a99d7d0d8f..fe9e6226ba8c 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs @@ -227,8 +227,8 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags() // ACT var logger = loggerFactory.CreateLogger(logCategoryName); logger.LogInformation( - "{microsoft.session.id} {ai.session.isFirst} {ai.device.id} {ai.device.model} {ai.device.oemName} {ai.device.type} {ai.device.osVersion} {microsoft.synthetic_source} {microsoft.user.account_id}", - "session-123", "True", "device-456", "Surface Pro", "Microsoft", "PC", "Microsoft Windows NT 10.0.22621.0", "test-bot", "account-789"); + "{microsoft.session.id} {ai.device.id} {ai.device.model} {ai.device.type} {ai.device.osVersion} {microsoft.synthetic_source} {microsoft.user.account_id}", + "session-123", "device-456", "Surface Pro", "PC", "Microsoft Windows NT 10.0.22621.0", "test-bot", "account-789"); // CLEANUP loggerFactory.Dispose(); @@ -240,10 +240,8 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags() // Verify context tags are mapped to envelope tags Assert.Equal("session-123", telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()]); - Assert.Equal("True", telemetryItem.Tags[ContextTagKeys.AiSessionIsFirst.ToString()]); Assert.Equal("device-456", telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()]); Assert.Equal("Surface Pro", telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()]); - Assert.Equal("Microsoft", telemetryItem.Tags[ContextTagKeys.AiDeviceOemName.ToString()]); Assert.Equal("PC", telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()]); Assert.Equal("Microsoft Windows NT 10.0.22621.0", telemetryItem.Tags[ContextTagKeys.AiDeviceOsVersion.ToString()]); Assert.Equal("test-bot", telemetryItem.Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()]); @@ -252,10 +250,8 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags() // Verify context tags are NOT in customDimensions var messageData = (MessageData)telemetryItem.Data.BaseData; Assert.False(messageData.Properties.ContainsKey("microsoft.session.id")); - Assert.False(messageData.Properties.ContainsKey("ai.session.isFirst")); Assert.False(messageData.Properties.ContainsKey("ai.device.id")); Assert.False(messageData.Properties.ContainsKey("ai.device.model")); - Assert.False(messageData.Properties.ContainsKey("ai.device.oemName")); Assert.False(messageData.Properties.ContainsKey("ai.device.type")); Assert.False(messageData.Properties.ContainsKey("ai.device.osVersion")); Assert.False(messageData.Properties.ContainsKey("microsoft.synthetic_source")); diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs index ffe23aa017ac..8a8c3f1515af 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/MetricsTests.cs @@ -6,7 +6,6 @@ using System.Diagnostics.Metrics; using System.Linq; using Azure.Monitor.OpenTelemetry.Exporter.Models; -using Azure.Monitor.OpenTelemetry.Exporter.Internals; using Azure.Monitor.OpenTelemetry.Exporter.Tests.CommonTestFramework; using OpenTelemetry; using OpenTelemetry.Metrics; diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs index c143cd2549cd..fd6749cbca94 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs @@ -387,10 +387,8 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit // Set all context tag attributes from the shim activity.SetTag(SemanticConventions.AttributeMicrosoftSessionId, "session-123"); - activity.SetTag(SemanticConventions.AttributeAiSessionIsFirst, "True"); activity.SetTag(SemanticConventions.AttributeAiDeviceId, "device-456"); activity.SetTag(SemanticConventions.AttributeAiDeviceModel, "Surface Pro"); - activity.SetTag(SemanticConventions.AttributeAiDeviceOemName, "Microsoft"); activity.SetTag(SemanticConventions.AttributeAiDeviceType, "PC"); activity.SetTag(SemanticConventions.AttributeAiDeviceOsVersion, "Microsoft Windows NT 10.0.22621.0"); activity.SetTag(SemanticConventions.AttributeMicrosoftSyntheticSource, "test-bot"); @@ -407,10 +405,8 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit // Verify context tags are mapped to envelope tags Assert.Equal("session-123", telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()]); - Assert.Equal("True", telemetryItem.Tags[ContextTagKeys.AiSessionIsFirst.ToString()]); Assert.Equal("device-456", telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()]); Assert.Equal("Surface Pro", telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()]); - Assert.Equal("Microsoft", telemetryItem.Tags[ContextTagKeys.AiDeviceOemName.ToString()]); Assert.Equal("PC", telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()]); Assert.Equal("Microsoft Windows NT 10.0.22621.0", telemetryItem.Tags[ContextTagKeys.AiDeviceOsVersion.ToString()]); Assert.Equal("test-bot", telemetryItem.Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()]); @@ -429,10 +425,8 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit } Assert.False(properties.ContainsKey(SemanticConventions.AttributeMicrosoftSessionId)); - Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiSessionIsFirst)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceId)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceModel)); - Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceOemName)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceType)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceOsVersion)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeMicrosoftSyntheticSource)); From e13e324dcf01fa1179e4526373bfad438e3822b6 Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Fri, 20 Mar 2026 14:29:28 -0700 Subject: [PATCH 06/11] adding user agent back --- .../Customizations/Models/TelemetryItem.cs | 6 +++ .../src/Internals/LogContextInfo.cs | 2 + .../src/Internals/LogsHelper.cs | 7 +++ .../E2ETelemetryItemValidation/LogsTests.cs | 6 ++- .../E2ETelemetryItemValidation/TracesTests.cs | 3 ++ .../LogsHelperTests.cs | 45 +++++++++++++++---- 6 files changed, 59 insertions(+), 10 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs index da957fe6e99d..eb13bb3ec536 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs @@ -159,6 +159,12 @@ public TelemetryItem (string name, LogRecord logRecord, AzureMonitorResource? re Tags[ContextTagKeys.AiUserAuthUserId.ToString()] = logContext.EndUserId.Truncate(SchemaConstants.Tags_AiUserAuthUserId_MaxLength); } + if (logContext.UserAgent != null) + { + // todo: update swagger to include this key. + Tags["ai.user.userAgent"] = logContext.UserAgent; + } + if (logContext.OperationName != null) { Tags[ContextTagKeys.AiOperationName.ToString()] = logContext.OperationName.Truncate(SchemaConstants.Tags_AiOperationName_MaxLength); diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs index 2f9270039c55..b4e0394ca099 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogContextInfo.cs @@ -12,6 +12,7 @@ internal struct LogContextInfo public string? MicrosoftClientIp; public string? EndUserPseudoId; public string? EndUserId; + public string? UserAgent; public string? OperationName; public string? SessionId; public string? DeviceId; @@ -28,6 +29,7 @@ internal struct LogContextInfo MicrosoftClientIp != null || EndUserPseudoId != null || EndUserId != null || + UserAgent != null || OperationName != null || SessionId != null || DeviceId != null || diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs index 1e3e2e2cd68e..d0c6cf609f7e 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/LogsHelper.cs @@ -24,6 +24,7 @@ internal static class LogsHelper private const string ClientIpAttributeName = "microsoft.client.ip"; private const string EndUserPseudoIdAttributeName = "enduser.pseudo.id"; private const string EndUserIdAttributeName = "enduser.id"; + private const string UserAgentOriginalAttributeName = "user_agent.original"; private const string OperationNameAttributeName = "microsoft.operation_name"; private const string SessionIdAttributeName = "microsoft.session.id"; private const string DeviceIdAttributeName = "ai.device.id"; @@ -169,6 +170,9 @@ internal static void ProcessLogRecordProperties(LogRecord logRecord, IDictionary case EndUserIdAttributeName: logContext.EndUserId = item.Value?.ToString(); break; + case UserAgentOriginalAttributeName: + logContext.UserAgent = item.Value?.ToString(); + break; case OperationNameAttributeName: logContext.OperationName = item.Value?.ToString(); break; @@ -305,6 +309,9 @@ internal static void ProcessLogRecordProperties(LogRecord logRecord, IDictionary case EndUserIdAttributeName: logContext.EndUserId = item.Value?.ToString(); break; + case UserAgentOriginalAttributeName: + logContext.UserAgent = item.Value?.ToString(); + break; case OperationNameAttributeName: logContext.OperationName = item.Value?.ToString(); break; diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs index fe9e6226ba8c..758214dfb38d 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs @@ -227,8 +227,8 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags() // ACT var logger = loggerFactory.CreateLogger(logCategoryName); logger.LogInformation( - "{microsoft.session.id} {ai.device.id} {ai.device.model} {ai.device.type} {ai.device.osVersion} {microsoft.synthetic_source} {microsoft.user.account_id}", - "session-123", "device-456", "Surface Pro", "PC", "Microsoft Windows NT 10.0.22621.0", "test-bot", "account-789"); + "{user_agent.original} {microsoft.session.id} {ai.device.id} {ai.device.model} {ai.device.type} {ai.device.osVersion} {microsoft.synthetic_source} {microsoft.user.account_id}", + "TestAgent/1.0", "session-123", "device-456", "Surface Pro", "PC", "Microsoft Windows NT 10.0.22621.0", "test-bot", "account-789"); // CLEANUP loggerFactory.Dispose(); @@ -239,6 +239,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags() var telemetryItem = telemetryItems!.First(x => x.Name == "Message"); // Verify context tags are mapped to envelope tags + Assert.Equal("TestAgent/1.0", telemetryItem.Tags["ai.user.userAgent"]); Assert.Equal("session-123", telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()]); Assert.Equal("device-456", telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()]); Assert.Equal("Surface Pro", telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()]); @@ -249,6 +250,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags() // Verify context tags are NOT in customDimensions var messageData = (MessageData)telemetryItem.Data.BaseData; + Assert.False(messageData.Properties.ContainsKey("user_agent.original")); Assert.False(messageData.Properties.ContainsKey("microsoft.session.id")); Assert.False(messageData.Properties.ContainsKey("ai.device.id")); Assert.False(messageData.Properties.ContainsKey("ai.device.model")); diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs index fd6749cbca94..7cc43ca50afb 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs @@ -386,6 +386,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit Assert.NotNull(activity); // Set all context tag attributes from the shim + activity.SetTag(SemanticConventions.AttributeUserAgentOriginal, "TestAgent/1.0"); activity.SetTag(SemanticConventions.AttributeMicrosoftSessionId, "session-123"); activity.SetTag(SemanticConventions.AttributeAiDeviceId, "device-456"); activity.SetTag(SemanticConventions.AttributeAiDeviceModel, "Surface Pro"); @@ -404,6 +405,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit var telemetryItem = telemetryItems.First(x => x.Name == expectedTelemetryName); // Verify context tags are mapped to envelope tags + Assert.Equal("TestAgent/1.0", telemetryItem.Tags["ai.user.userAgent"]); Assert.Equal("session-123", telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()]); Assert.Equal("device-456", telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()]); Assert.Equal("Surface Pro", telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()]); @@ -424,6 +426,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit properties = ((RequestData)baseData).Properties; } + Assert.False(properties.ContainsKey(SemanticConventions.AttributeUserAgentOriginal)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeMicrosoftSessionId)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceId)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceModel)); diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs index 73e092588311..db83aaf046db 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/LogsHelperTests.cs @@ -793,6 +793,30 @@ public void VerifyEndUserId_ExtractedIntoLogContext() Assert.False(properties.ContainsKey("enduser.id"), "enduser.id should not appear in customDimensions"); } + [Fact] + public void VerifyUserAgentOriginal_ExtractedIntoLogContext() + { + // Arrange. + var logRecords = new List(1); + using var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddOpenTelemetry(options => + { + options.AddInMemoryExporter(logRecords); + }); + }); + + var logger = loggerFactory.CreateLogger("Some category"); + logger.LogInformation("{user_agent.original}", "Mozilla/5.0"); + + // Assert. + var properties = new ChangeTrackingDictionary(); + LogsHelper.ProcessLogRecordProperties(logRecords[0], properties, out var message, out var eventName, out LogContextInfo logContext, out var availabilityInfo); + + Assert.Equal("Mozilla/5.0", logContext.UserAgent); + Assert.False(properties.ContainsKey("user_agent.original"), "user_agent.original should not appear in customDimensions"); + } + [Fact] public void VerifyOperationName_ExtractedIntoLogContext() { @@ -832,8 +856,8 @@ public void VerifyAllContextAttributes_ExtractedTogether() var logger = loggerFactory.CreateLogger("Some category"); logger.LogInformation( - "{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {microsoft.operation_name}", - "1.2.3.4", "User123", "AuthUser123", "SampleOp"); + "{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {user_agent.original} {microsoft.operation_name}", + "1.2.3.4", "User123", "AuthUser123", "Mozilla/5.0", "SampleOp"); // Assert. var properties = new ChangeTrackingDictionary(); @@ -842,12 +866,14 @@ public void VerifyAllContextAttributes_ExtractedTogether() Assert.Equal("1.2.3.4", logContext.MicrosoftClientIp); Assert.Equal("User123", logContext.EndUserPseudoId); Assert.Equal("AuthUser123", logContext.EndUserId); + Assert.Equal("Mozilla/5.0", logContext.UserAgent); Assert.Equal("SampleOp", logContext.OperationName); // None of these should leak into customDimensions Assert.False(properties.ContainsKey("microsoft.client.ip")); Assert.False(properties.ContainsKey("enduser.pseudo.id")); Assert.False(properties.ContainsKey("enduser.id")); + Assert.False(properties.ContainsKey("user_agent.original")); Assert.False(properties.ContainsKey("microsoft.operation_name")); } @@ -874,6 +900,7 @@ public void VerifyLogContextDefaults_WhenNoContextAttributesPresent() Assert.Null(logContext.MicrosoftClientIp); Assert.Null(logContext.EndUserPseudoId); Assert.Null(logContext.EndUserId); + Assert.Null(logContext.UserAgent); Assert.Null(logContext.OperationName); } @@ -903,19 +930,19 @@ public void VerifyContextAttributes_MappedToEnvelopeTags(string baseType) } catch (Exception ex) { - logger.LogError(ex, "{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {microsoft.operation_name}", - "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestOperation"); + logger.LogError(ex, "{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {user_agent.original} {microsoft.operation_name}", + "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestAgent/1.0", "TestOperation"); } } else if (baseType == "EventData") { - logger.LogInformation("{microsoft.custom_event.name} {microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {microsoft.operation_name}", - "TestEvent", "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestOperation"); + logger.LogInformation("{microsoft.custom_event.name} {microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {user_agent.original} {microsoft.operation_name}", + "TestEvent", "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestAgent/1.0", "TestOperation"); } else { - logger.LogInformation("{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {microsoft.operation_name}", - "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestOperation"); + logger.LogInformation("{microsoft.client.ip} {enduser.pseudo.id} {enduser.id} {user_agent.original} {microsoft.operation_name}", + "10.0.0.1", "PseudoUser", "AuthenticatedUser", "TestAgent/1.0", "TestOperation"); } var logResource = new AzureMonitorResource( @@ -931,6 +958,7 @@ public void VerifyContextAttributes_MappedToEnvelopeTags(string baseType) Assert.Equal("10.0.0.1", item.Tags[ContextTagKeys.AiLocationIp.ToString()]); Assert.Equal("PseudoUser", item.Tags[ContextTagKeys.AiUserId.ToString()]); Assert.Equal("AuthenticatedUser", item.Tags[ContextTagKeys.AiUserAuthUserId.ToString()]); + Assert.Equal("TestAgent/1.0", item.Tags["ai.user.userAgent"]); Assert.Equal("TestOperation", item.Tags[ContextTagKeys.AiOperationName.ToString()]); // Verify base type @@ -966,6 +994,7 @@ public void VerifyContextAttributes_NotInEnvelopeTags_WhenAbsent() Assert.False(item.Tags.ContainsKey(ContextTagKeys.AiLocationIp.ToString())); Assert.False(item.Tags.ContainsKey(ContextTagKeys.AiUserId.ToString())); Assert.False(item.Tags.ContainsKey(ContextTagKeys.AiUserAuthUserId.ToString())); + Assert.False(item.Tags.ContainsKey("ai.user.userAgent")); Assert.False(item.Tags.ContainsKey(ContextTagKeys.AiOperationName.ToString())); } From bba5c22a2944cbd40f2295b861b3e7aa2f6ec96c Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Fri, 20 Mar 2026 16:20:58 -0700 Subject: [PATCH 07/11] remove method i thought i already removed --- .../Customizations/Models/TelemetryItem.cs | 6 +- .../src/Internals/MetricHelper.cs | 55 ------------------- 2 files changed, 3 insertions(+), 58 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs index eb13bb3ec536..ccfd218c002c 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs @@ -118,7 +118,7 @@ public TelemetryItem(string name, TelemetryItem telemetryItem, ActivitySpanId ac CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceId.ToString()); CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceModel.ToString()); CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceType.ToString()); - CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceOsVersion.ToString()); + CopyTagIfPresent(telemetryItem, ContextTagKeys.AiDeviceOSVersion.ToString()); CopyTagIfPresent(telemetryItem, ContextTagKeys.AiOperationSyntheticSource.ToString()); CopyTagIfPresent(telemetryItem, ContextTagKeys.AiUserAccountId.ToString()); InstrumentationKey = telemetryItem.InstrumentationKey; @@ -192,7 +192,7 @@ public TelemetryItem (string name, LogRecord logRecord, AzureMonitorResource? re if (logContext.DeviceOsVersion != null) { - Tags[ContextTagKeys.AiDeviceOsVersion.ToString()] = logContext.DeviceOsVersion.Truncate(SchemaConstants.Tags_AiDeviceOsVersion_MaxLength); + Tags[ContextTagKeys.AiDeviceOSVersion.ToString()] = logContext.DeviceOsVersion.Truncate(SchemaConstants.Tags_AiDeviceOsVersion_MaxLength); } if (logContext.SyntheticSource != null) @@ -311,7 +311,7 @@ private void SetOverrideContextTags(ref ActivityTagsProcessor activityTagsProces if (activityTagsProcessor.DeviceOsVersion != null) { - Tags[ContextTagKeys.AiDeviceOsVersion.ToString()] = activityTagsProcessor.DeviceOsVersion.Truncate(SchemaConstants.Tags_AiDeviceOsVersion_MaxLength); + Tags[ContextTagKeys.AiDeviceOSVersion.ToString()] = activityTagsProcessor.DeviceOsVersion.Truncate(SchemaConstants.Tags_AiDeviceOsVersion_MaxLength); } if (activityTagsProcessor.SyntheticSource != null) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs index 765e845195f1..f52a37fc285a 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs @@ -35,8 +35,6 @@ internal static (List TelemetryItems, TelemetrySchemaTypeCounter BaseData = new MetricsData(Version, metric, metricPoint) } }; - - SetContextTagsFromMetricTags(telemetryItem, metricPoint); telemetryItems.Add(telemetryItem); } catch (Exception ex) @@ -48,58 +46,5 @@ internal static (List TelemetryItems, TelemetrySchemaTypeCounter return (telemetryItems, new TelemetrySchemaTypeCounter() { _metricCount = telemetryItems.Count }); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void SetContextTagsFromMetricTags(TelemetryItem telemetryItem, in MetricPoint metricPoint) - { - string? clientAddress = null; - string? microsoftClientIp = null; - - foreach (var tag in metricPoint.Tags) - { - switch (tag.Key) - { - case SemanticConventions.AttributeEnduserId: - telemetryItem.Tags[ContextTagKeys.AiUserAuthUserId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiUserAuthUserId_MaxLength); - break; - case SemanticConventions.AttributeEnduserPseudoId: - telemetryItem.Tags[ContextTagKeys.AiUserId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiUserId_MaxLength); - break; - case SemanticConventions.AttributeClientAddress: - clientAddress = tag.Value?.ToString(); - break; - case SemanticConventions.AttributeMicrosoftClientIp: - microsoftClientIp = tag.Value?.ToString(); - break; - case SemanticConventions.AttributeMicrosoftSessionId: - telemetryItem.Tags[ContextTagKeys.AiSessionId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiSessionId_MaxLength); - break; - case SemanticConventions.AttributeAiDeviceId: - telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceId_MaxLength); - break; - case SemanticConventions.AttributeAiDeviceModel: - telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceModel_MaxLength); - break; - case SemanticConventions.AttributeAiDeviceType: - telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceType_MaxLength); - break; - case SemanticConventions.AttributeAiDeviceOsVersion: - telemetryItem.Tags[ContextTagKeys.AiDeviceOsVersion.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiDeviceOsVersion_MaxLength); - break; - case SemanticConventions.AttributeMicrosoftSyntheticSource: - telemetryItem.Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiOperationSyntheticSource_MaxLength); - break; - case SemanticConventions.AttributeMicrosoftUserAccountId: - telemetryItem.Tags[ContextTagKeys.AiUserAccountId.ToString()] = tag.Value?.ToString().Truncate(SchemaConstants.Tags_AiUserAccountId_MaxLength); - break; - } - } - - var locationIp = microsoftClientIp ?? clientAddress; - if (locationIp != null) - { - telemetryItem.Tags[ContextTagKeys.AiLocationIp.ToString()] = locationIp; - } - } } } From 868da484b44b62f7682733f553bce56680107044 Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Fri, 20 Mar 2026 21:30:58 -0700 Subject: [PATCH 08/11] fix build issue --- .../E2ETelemetryItemValidation/LogsTests.cs | 2 +- .../E2ETelemetryItemValidation/TracesTests.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs index 758214dfb38d..962b412313e0 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/LogsTests.cs @@ -244,7 +244,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags() Assert.Equal("device-456", telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()]); Assert.Equal("Surface Pro", telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()]); Assert.Equal("PC", telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()]); - Assert.Equal("Microsoft Windows NT 10.0.22621.0", telemetryItem.Tags[ContextTagKeys.AiDeviceOsVersion.ToString()]); + Assert.Equal("Microsoft Windows NT 10.0.22621.0", telemetryItem.Tags[ContextTagKeys.AiDeviceOSVersion.ToString()]); Assert.Equal("test-bot", telemetryItem.Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()]); Assert.Equal("account-789", telemetryItem.Tags[ContextTagKeys.AiUserAccountId.ToString()]); diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs index 7cc43ca50afb..2671c3ccec6b 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs @@ -391,7 +391,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit activity.SetTag(SemanticConventions.AttributeAiDeviceId, "device-456"); activity.SetTag(SemanticConventions.AttributeAiDeviceModel, "Surface Pro"); activity.SetTag(SemanticConventions.AttributeAiDeviceType, "PC"); - activity.SetTag(SemanticConventions.AttributeAiDeviceOsVersion, "Microsoft Windows NT 10.0.22621.0"); + activity.SetTag(SemanticConventions.AttributeAiDeviceOSVersion, "Microsoft Windows NT 10.0.22621.0"); activity.SetTag(SemanticConventions.AttributeMicrosoftSyntheticSource, "test-bot"); activity.SetTag(SemanticConventions.AttributeMicrosoftUserAccountId, "account-789"); } @@ -410,7 +410,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit Assert.Equal("device-456", telemetryItem.Tags[ContextTagKeys.AiDeviceId.ToString()]); Assert.Equal("Surface Pro", telemetryItem.Tags[ContextTagKeys.AiDeviceModel.ToString()]); Assert.Equal("PC", telemetryItem.Tags[ContextTagKeys.AiDeviceType.ToString()]); - Assert.Equal("Microsoft Windows NT 10.0.22621.0", telemetryItem.Tags[ContextTagKeys.AiDeviceOsVersion.ToString()]); + Assert.Equal("Microsoft Windows NT 10.0.22621.0", telemetryItem.Tags[ContextTagKeys.AiDeviceOSVersion.ToString()]); Assert.Equal("test-bot", telemetryItem.Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()]); Assert.Equal("account-789", telemetryItem.Tags[ContextTagKeys.AiUserAccountId.ToString()]); @@ -431,7 +431,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceId)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceModel)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceType)); - Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceOsVersion)); + Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceOSVersion)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeMicrosoftSyntheticSource)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeMicrosoftUserAccountId)); } From 0a18a53533df4c51d335b09399dc1c0d34bd5909 Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Mon, 23 Mar 2026 10:12:52 -0700 Subject: [PATCH 09/11] fix constant casing --- .../E2ETelemetryItemValidation/TracesTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs index 2671c3ccec6b..690ca1e8e133 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/E2ETelemetryItemValidation/TracesTests.cs @@ -391,7 +391,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit activity.SetTag(SemanticConventions.AttributeAiDeviceId, "device-456"); activity.SetTag(SemanticConventions.AttributeAiDeviceModel, "Surface Pro"); activity.SetTag(SemanticConventions.AttributeAiDeviceType, "PC"); - activity.SetTag(SemanticConventions.AttributeAiDeviceOSVersion, "Microsoft Windows NT 10.0.22621.0"); + activity.SetTag(SemanticConventions.AttributeAiDeviceOsVersion, "Microsoft Windows NT 10.0.22621.0"); activity.SetTag(SemanticConventions.AttributeMicrosoftSyntheticSource, "test-bot"); activity.SetTag(SemanticConventions.AttributeMicrosoftUserAccountId, "account-789"); } @@ -431,7 +431,7 @@ public void VerifyContextTagAttributes_MappedToEnvelopeTags(ActivityKind activit Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceId)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceModel)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceType)); - Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceOSVersion)); + Assert.False(properties.ContainsKey(SemanticConventions.AttributeAiDeviceOsVersion)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeMicrosoftSyntheticSource)); Assert.False(properties.ContainsKey(SemanticConventions.AttributeMicrosoftUserAccountId)); } From a6565a96dfc09cd99dcd32f770122f0a5f960f31 Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Mon, 23 Mar 2026 12:15:29 -0700 Subject: [PATCH 10/11] remove the using --- .../src/Internals/MetricHelper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs index f52a37fc285a..56c753c161bd 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/MetricHelper.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; using Azure.Monitor.OpenTelemetry.Exporter.Internals.CustomerSdkStats; using Azure.Monitor.OpenTelemetry.Exporter.Internals.Diagnostics; using Azure.Monitor.OpenTelemetry.Exporter.Models; From 9316a26848afb8294198cec3f1daa2d09f9d5c80 Mon Sep 17 00:00:00 2001 From: Harsimar Kaur Date: Mon, 23 Mar 2026 15:30:46 -0700 Subject: [PATCH 11/11] pr comments --- .../Customizations/Models/TelemetryItem.cs | 54 ++++++++----------- .../src/Internals/ActivityTagsProcessor.cs | 28 ---------- 2 files changed, 22 insertions(+), 60 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs index ccfd218c002c..17d367bf5cb1 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs @@ -89,7 +89,12 @@ public TelemetryItem(Activity activity, ref ActivityTagsProcessor activityTagsPr } SetUserIdAndAuthenticatedUserId(ref activityTagsProcessor); - SetOverrideContextTags(ref activityTagsProcessor); + + if (activityTagsProcessor.HasOverrideAttributes) + { + SetOverrideContextTags(ref activityTagsProcessor); + } + SetResourceSdkVersionAndIkey(resource, instrumentationKey); if (sampleRate != 100f) @@ -104,6 +109,8 @@ public TelemetryItem(string name, TelemetryItem telemetryItem, ActivitySpanId ac Tags[ContextTagKeys.AiOperationParentId.ToString()] = activitySpanId.ToHexString(); Tags[ContextTagKeys.AiOperationId.ToString()] = telemetryItem.Tags[ContextTagKeys.AiOperationId.ToString()]; + // Copy user agent from the parent TelemetryItem created by the Activity constructor, + // where it was set from ActivityTagsProcessor.MappedTags. if (telemetryItem.Tags.TryGetValue("ai.user.userAgent", out string? userAgent)) { // todo: update swagger to include this key. @@ -289,39 +296,22 @@ private void SetUserIdAndAuthenticatedUserId(ref ActivityTagsProcessor activityT [MethodImpl(MethodImplOptions.AggressiveInlining)] private void SetOverrideContextTags(ref ActivityTagsProcessor activityTagsProcessor) { - if (activityTagsProcessor.SessionId != null) - { - Tags[ContextTagKeys.AiSessionId.ToString()] = activityTagsProcessor.SessionId.Truncate(SchemaConstants.Tags_AiSessionId_MaxLength); - } - - if (activityTagsProcessor.DeviceId != null) - { - Tags[ContextTagKeys.AiDeviceId.ToString()] = activityTagsProcessor.DeviceId.Truncate(SchemaConstants.Tags_AiDeviceId_MaxLength); - } - - if (activityTagsProcessor.DeviceModel != null) - { - Tags[ContextTagKeys.AiDeviceModel.ToString()] = activityTagsProcessor.DeviceModel.Truncate(SchemaConstants.Tags_AiDeviceModel_MaxLength); - } - - if (activityTagsProcessor.DeviceType != null) - { - Tags[ContextTagKeys.AiDeviceType.ToString()] = activityTagsProcessor.DeviceType.Truncate(SchemaConstants.Tags_AiDeviceType_MaxLength); - } - - if (activityTagsProcessor.DeviceOsVersion != null) - { - Tags[ContextTagKeys.AiDeviceOSVersion.ToString()] = activityTagsProcessor.DeviceOsVersion.Truncate(SchemaConstants.Tags_AiDeviceOsVersion_MaxLength); - } - - if (activityTagsProcessor.SyntheticSource != null) - { - Tags[ContextTagKeys.AiOperationSyntheticSource.ToString()] = activityTagsProcessor.SyntheticSource.Truncate(SchemaConstants.Tags_AiOperationSyntheticSource_MaxLength); - } + SetTagFromMappedTags(ref activityTagsProcessor, SemanticConventions.AttributeMicrosoftSessionId, ContextTagKeys.AiSessionId, SchemaConstants.Tags_AiSessionId_MaxLength); + SetTagFromMappedTags(ref activityTagsProcessor, SemanticConventions.AttributeAiDeviceId, ContextTagKeys.AiDeviceId, SchemaConstants.Tags_AiDeviceId_MaxLength); + SetTagFromMappedTags(ref activityTagsProcessor, SemanticConventions.AttributeAiDeviceModel, ContextTagKeys.AiDeviceModel, SchemaConstants.Tags_AiDeviceModel_MaxLength); + SetTagFromMappedTags(ref activityTagsProcessor, SemanticConventions.AttributeAiDeviceType, ContextTagKeys.AiDeviceType, SchemaConstants.Tags_AiDeviceType_MaxLength); + SetTagFromMappedTags(ref activityTagsProcessor, SemanticConventions.AttributeAiDeviceOsVersion, ContextTagKeys.AiDeviceOSVersion, SchemaConstants.Tags_AiDeviceOsVersion_MaxLength); + SetTagFromMappedTags(ref activityTagsProcessor, SemanticConventions.AttributeMicrosoftSyntheticSource, ContextTagKeys.AiOperationSyntheticSource, SchemaConstants.Tags_AiOperationSyntheticSource_MaxLength); + SetTagFromMappedTags(ref activityTagsProcessor, SemanticConventions.AttributeMicrosoftUserAccountId, ContextTagKeys.AiUserAccountId, SchemaConstants.Tags_AiUserAccountId_MaxLength); + } - if (activityTagsProcessor.UserAccountId != null) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetTagFromMappedTags(ref ActivityTagsProcessor activityTagsProcessor, string attributeKey, ContextTagKeys contextTagKey, int maxLength) + { + var value = AzMonList.GetTagValue(ref activityTagsProcessor.MappedTags, attributeKey)?.ToString(); + if (value != null) { - Tags[ContextTagKeys.AiUserAccountId.ToString()] = activityTagsProcessor.UserAccountId.Truncate(SchemaConstants.Tags_AiUserAccountId_MaxLength); + Tags[contextTagKey.ToString()] = value.Truncate(maxLength); } } } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs index 669a503d11fa..e04f42bf5779 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs @@ -96,20 +96,6 @@ internal struct ActivityTagsProcessor public string? EndUserPseudoId { get; private set; } = null; - public string? SessionId { get; private set; } = null; - - public string? DeviceId { get; private set; } = null; - - public string? DeviceModel { get; private set; } = null; - - public string? DeviceType { get; private set; } = null; - - public string? DeviceOsVersion { get; private set; } = null; - - public string? SyntheticSource { get; private set; } = null; - - public string? UserAccountId { get; private set; } = null; - public bool HasOverrideAttributes { get; private set; } = false; public ActivityTagsProcessor() @@ -156,26 +142,12 @@ public void CategorizeTags(Activity activity) EndUserPseudoId = tag.Value.ToString(); continue; case SemanticConventions.AttributeMicrosoftSessionId: - SessionId = tag.Value.ToString(); - continue; case SemanticConventions.AttributeAiDeviceId: - DeviceId = tag.Value.ToString(); - continue; case SemanticConventions.AttributeAiDeviceModel: - DeviceModel = tag.Value.ToString(); - continue; case SemanticConventions.AttributeAiDeviceType: - DeviceType = tag.Value.ToString(); - continue; case SemanticConventions.AttributeAiDeviceOsVersion: - DeviceOsVersion = tag.Value.ToString(); - continue; case SemanticConventions.AttributeMicrosoftSyntheticSource: - SyntheticSource = tag.Value.ToString(); - continue; case SemanticConventions.AttributeMicrosoftUserAccountId: - UserAccountId = tag.Value.ToString(); - continue; case SemanticConventions.AttributeMicrosoftDependencyData: case SemanticConventions.AttributeMicrosoftDependencyName: case SemanticConventions.AttributeMicrosoftDependencyTarget: