From e215b40028fd724904fabc0c056727fdf78a2131 Mon Sep 17 00:00:00 2001 From: Vishwesh Bankwar Date: Tue, 17 Jan 2023 13:46:40 -0800 Subject: [PATCH] Export span event as trace telemetry (#32980) * export span event as trace telemetry * revert demo * mark method private * assert * rename method * refactor * resolve pr comments --- .../Customizations/Models/TelemetryItem.cs | 4 +- .../src/Internals/TraceHelper.cs | 47 +++++++++++++++---- .../SampleRateTests.cs | 2 +- .../TraceHelperTests.cs | 45 +++++++++++++++--- 4 files changed, 81 insertions(+), 17 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 e2a4c108b86dd..9e0c51b217550 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 @@ -48,8 +48,8 @@ public TelemetryItem(Activity activity, ref TagEnumerationState monitorTags, str } } - public TelemetryItem(TelemetryItem telemetryItem, ActivitySpanId activitySpanId, ActivityKind kind, DateTimeOffset activityEventTimeStamp) : - this("Exception", FormatUtcTimestamp(activityEventTimeStamp.DateTime)) + public TelemetryItem(string name, TelemetryItem telemetryItem, ActivitySpanId activitySpanId, ActivityKind kind, DateTimeOffset activityEventTimeStamp) : + this(name, FormatUtcTimestamp(activityEventTimeStamp.DateTime)) { Tags[ContextTagKeys.AiOperationParentId.ToString()] = activitySpanId.ToHexString(); Tags[ContextTagKeys.AiOperationId.ToString()] = telemetryItem.Tags[ContextTagKeys.AiOperationId.ToString()]; diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/TraceHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/TraceHelper.cs index 82e7d03c0b67f..4d857adfb8c38 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/TraceHelper.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/TraceHelper.cs @@ -34,7 +34,7 @@ internal static List OtelToAzureMonitorTrace(Batch batc // Check for Exceptions events if (activity.Events.Any()) { - AddExceptionTelemetryFromActivityExceptionEvents(activity, telemetryItem, telemetryItems); + AddTelemetryFromActivityEvents(activity, telemetryItem, telemetryItems); } switch (activity.GetTelemetryType()) @@ -177,31 +177,62 @@ internal static string GetOperationName(Activity activity, ref AzMonList MappedT return activity.DisplayName; } - private static void AddExceptionTelemetryFromActivityExceptionEvents(Activity activity, TelemetryItem telemetryItem, List telemetryItems) + private static void AddTelemetryFromActivityEvents(Activity activity, TelemetryItem telemetryItem, List telemetryItems) { foreach (var evnt in activity.Events) { - if (evnt.Name == SemanticConventions.AttributeExceptionEventName) + try { - try + if (evnt.Name == SemanticConventions.AttributeExceptionEventName) { var exceptionData = GetExceptionDataDetailsOnTelemetryItem(evnt.Tags); if (exceptionData != null) { - var exceptionTelemetryItem = new TelemetryItem(telemetryItem, activity.SpanId, activity.Kind, evnt.Timestamp); + var exceptionTelemetryItem = new TelemetryItem("Exception", telemetryItem, activity.SpanId, activity.Kind, evnt.Timestamp); exceptionTelemetryItem.Data = exceptionData; telemetryItems.Add(exceptionTelemetryItem); } } - catch (Exception ex) + else { - AzureMonitorExporterEventSource.Log.WriteWarning("FailedToExtractExceptionFromActivityEvent", ex); + var messageData = GetTraceTelemetryData(evnt); + if (messageData != null) + { + var traceTelemetryItem = new TelemetryItem("Message", telemetryItem, activity.SpanId, activity.Kind, evnt.Timestamp); + traceTelemetryItem.Data = messageData; + telemetryItems.Add(traceTelemetryItem); + } } } + catch (Exception ex) + { + AzureMonitorExporterEventSource.Log.WriteError("FailedToExtractActivityEvent", ex); + } + } + } + + private static MonitorBase GetTraceTelemetryData(ActivityEvent activityEvent) + { + if (activityEvent.Name == null) + { + return null; + } + + var messageData = new MessageData(Version, activityEvent.Name); + + foreach (var tag in activityEvent.Tags) + { + messageData.Properties.Add(tag.Key, tag.Value.ToString()); } + + return new MonitorBase + { + BaseType = "MessageData", + BaseData = messageData, + }; } - internal static MonitorBase GetExceptionDataDetailsOnTelemetryItem(IEnumerable> activityEventTags) + private static MonitorBase GetExceptionDataDetailsOnTelemetryItem(IEnumerable> activityEventTags) { string exceptionType = null; string exceptionStackTrace = null; diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/SampleRateTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/SampleRateTests.cs index 6c6a485ea879f..992d94e35a3c4 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/SampleRateTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/SampleRateTests.cs @@ -56,7 +56,7 @@ public void ValidateSampleRateForEventException(object SampleRate) var monitorTags = TraceHelper.EnumerateActivityTags(activity); var telemetryItem = new TelemetryItem(activity, ref monitorTags, "RoleName", "RoleInstance", "00000000-0000-0000-0000-000000000000"); - var expTelemetryItem = new TelemetryItem(telemetryItem, default, default, default); + var expTelemetryItem = new TelemetryItem("Exception", telemetryItem, default, default, default); if (SampleRate is float) { diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TraceHelperTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TraceHelperTests.cs index d54d6f043856e..67c2b380965d8 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TraceHelperTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TraceHelperTests.cs @@ -238,11 +238,44 @@ public void ActivityWithExceptionEventCreatesExceptionTelemetry() var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(batch, "roleName", "roleInstance", "00000000-0000-0000-0000-000000000000"); Assert.Equal(2, telemetryItems.Count()); - Assert.Equal("Exception", (IEnumerable)telemetryItems[0].Name); - Assert.Equal("Request", (IEnumerable)telemetryItems[1].Name); - Assert.Equal(exceptionMessage, (IEnumerable)(telemetryItems[0].Data.BaseData as TelemetryExceptionData).Exceptions.First().Message); - Assert.Equal("System.Exception", (IEnumerable)(telemetryItems[0].Data.BaseData as TelemetryExceptionData).Exceptions.First().TypeName); - Assert.Equal("System.Exception: Exception Message", (IEnumerable)(telemetryItems[0].Data.BaseData as TelemetryExceptionData).Exceptions.First().Stack); + Assert.Equal("Exception", telemetryItems[0].Name); + Assert.Equal("Request", telemetryItems[1].Name); + Assert.Equal(exceptionMessage, (telemetryItems[0].Data.BaseData as TelemetryExceptionData).Exceptions.First().Message); + Assert.Equal("System.Exception", (telemetryItems[0].Data.BaseData as TelemetryExceptionData).Exceptions.First().TypeName); + Assert.Equal("System.Exception: Exception Message", (telemetryItems[0].Data.BaseData as TelemetryExceptionData).Exceptions.First().Stack); + } + + [Fact] + public void ActivityWithEventCreatesTraceTelemetry() + { + var eventName = "Custom Event"; + using ActivitySource activitySource = new ActivitySource(ActivitySourceName); + using var activity = activitySource.StartActivity( + ActivityName, + ActivityKind.Server); + + var tagsCollection = new ActivityTagsCollection + { + { "key1", "value1" }, + }; + + var activityEvent = new ActivityEvent(eventName, default, tagsCollection); + + activity.AddEvent(activityEvent); + + Activity[] activityList = new Activity[1]; + activityList[0] = activity; + Batch batch = new Batch(activityList, 1); + + var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(batch, "roleName", "roleInstance", "00000000-0000-0000-0000-000000000000"); + + Assert.Equal(2, telemetryItems.Count()); + Assert.Equal("Message", telemetryItems[0].Name); + Assert.Equal("Request", telemetryItems[1].Name); + Assert.Equal(eventName, (telemetryItems[0].Data.BaseData as MessageData).Message); + Assert.True((telemetryItems[0].Data.BaseData as MessageData).Properties.TryGetValue("key1", out var value)); + Assert.Equal("value1", value); + Assert.Null((telemetryItems[0].Data.BaseData as MessageData).SeverityLevel); } [Fact] @@ -295,7 +328,7 @@ public void ActivityWithExceptionEventDoesNotCreateExceptionTelemetryWhenTypeNam var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(batch, "roleName", "roleInstance", "00000000 - 0000 - 0000 - 0000 - 000000000000"); Assert.Single(telemetryItems); - Assert.Equal("Request", (IEnumerable)telemetryItems[0].Name); + Assert.Equal("Request", telemetryItems[0].Name); } private string GetExpectedMSlinks(IEnumerable links)