diff --git a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/AzureMonitorConverter.cs b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/AzureMonitorConverter.cs index a3f1f7557cdd..05e422a8ff1e 100644 --- a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/AzureMonitorConverter.cs +++ b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/AzureMonitorConverter.cs @@ -1,17 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; -using System.Runtime.CompilerServices; -using System.Text; -using Microsoft.OpenTelemetry.Exporter.AzureMonitor.Models; - using OpenTelemetry; -using OpenTelemetry.Resources; -using OpenTelemetry.Trace; +using Microsoft.OpenTelemetry.Exporter.AzureMonitor.Models; namespace Microsoft.OpenTelemetry.Exporter.AzureMonitor { @@ -29,65 +22,6 @@ internal static class AzureMonitorConverter [TelemetryType.Event] = "EventData", }; - private static readonly IReadOnlyDictionary PartA_Name_Mapping = new Dictionary - { - [TelemetryType.Request] = "Request", - [TelemetryType.Dependency] = "RemoteDependency", - [TelemetryType.Message] = "Message", - [TelemetryType.Event] = "Event", - }; - - private static readonly IReadOnlyDictionary Part_B_Mapping = new Dictionary() - { - [SemanticConventions.AttributeDbStatement] = PartBType.Db, - [SemanticConventions.AttributeDbSystem] = PartBType.Db, - - [SemanticConventions.AttributeHttpMethod] = PartBType.Http, - [SemanticConventions.AttributeHttpUrl] = PartBType.Http, - [SemanticConventions.AttributeHttpStatusCode] = PartBType.Http, - [SemanticConventions.AttributeHttpScheme] = PartBType.Http, - [SemanticConventions.AttributeHttpHost] = PartBType.Http, - [SemanticConventions.AttributeHttpHostPort] = PartBType.Http, - [SemanticConventions.AttributeHttpTarget] = PartBType.Http, - - [SemanticConventions.AttributeNetPeerName] = PartBType.Common, - [SemanticConventions.AttributeNetPeerIp] = PartBType.Common, - [SemanticConventions.AttributeNetPeerPort] = PartBType.Common, - [SemanticConventions.AttributeNetTransport] = PartBType.Common, - [SemanticConventions.AttributeNetHostIp] = PartBType.Common, - [SemanticConventions.AttributeNetHostPort] = PartBType.Common, - [SemanticConventions.AttributeNetHostName] = PartBType.Common, - [SemanticConventions.AttributeComponent] = PartBType.Common, - - [SemanticConventions.AttributeRpcService] = PartBType.Rpc, - [SemanticConventions.AttributeRpcSystem] = PartBType.Rpc, - [SemanticConventions.AttributeRpcStatus] = PartBType.Rpc, - - [SemanticConventions.AttributeFaasTrigger] = PartBType.FaaS, - [SemanticConventions.AttributeFaasExecution] = PartBType.FaaS, - [SemanticConventions.AttributeFaasColdStart] = PartBType.FaaS, - [SemanticConventions.AttributeFaasDocumentCollection] = PartBType.FaaS, - [SemanticConventions.AttributeFaasDocumentOperation] = PartBType.FaaS, - [SemanticConventions.AttributeFaasDocumentTime] = PartBType.FaaS, - [SemanticConventions.AttributeFaasDocumentName] = PartBType.FaaS, - [SemanticConventions.AttributeFaasCron] = PartBType.FaaS, - [SemanticConventions.AttributeFaasTime] = PartBType.FaaS, - - [SemanticConventions.AttributeAzureNameSpace] = PartBType.Azure, - [SemanticConventions.AttributeMessageBusDestination] = PartBType.Azure, - - [SemanticConventions.AttributeEndpointAddress] = PartBType.Messaging, - [SemanticConventions.AttributeMessagingSystem] = PartBType.Messaging, - [SemanticConventions.AttributeMessagingDestination] = PartBType.Messaging, - [SemanticConventions.AttributeMessagingDestinationKind] = PartBType.Messaging, - [SemanticConventions.AttributeMessagingTempDestination] = PartBType.Messaging, - [SemanticConventions.AttributeMessagingUrl] = PartBType.Messaging - }; - - internal static string RoleName { get; set; } = null; - - internal static string RoleInstance { get; set; } = null; - internal static List Convert(Batch batchActivity, string instrumentationKey) { List telemetryItems = new List(); @@ -95,218 +29,26 @@ internal static List Convert(Batch batchActivity, strin foreach (var activity in batchActivity) { - telemetryItem = GeneratePartAEnvelope(activity); - telemetryItem.InstrumentationKey = instrumentationKey; - telemetryItem.Data = GenerateTelemetryData(activity); - telemetryItems.Add(telemetryItem); - } - - return telemetryItems; - } - - internal static TelemetryItem GeneratePartAEnvelope(Activity activity) - { - TelemetryItem telemetryItem = new TelemetryItem(PartA_Name_Mapping[activity.GetTelemetryType()], activity.StartTimeUtc.ToString(CultureInfo.InvariantCulture)); - InitRoleInfo(activity); - telemetryItem.Tags[ContextTagKeys.AiCloudRole.ToString()] = RoleName; - telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()] = RoleInstance; - telemetryItem.Tags[ContextTagKeys.AiOperationId.ToString()] = activity.TraceId.ToHexString(); - if (activity.Parent != null) - { - telemetryItem.Tags[ContextTagKeys.AiOperationParentId.ToString()] = activity.Parent.SpanId.ToHexString(); - } - // TODO: Handle exception - telemetryItem.Tags[ContextTagKeys.AiInternalSdkVersion.ToString()] = SdkVersionUtils.SdkVersion; - - return telemetryItem; - } - - internal static void InitRoleInfo(Activity activity) - { - if (RoleName != null || RoleInstance != null) - { - return; - } - - var resource = activity.GetResource(); - - if (resource == null) - { - return; - } - - string serviceName = null; - string serviceNamespace = null; - - foreach (var attribute in resource.Attributes) - { - if (attribute.Key == Resource.ServiceNameKey && attribute.Value is string) - { - serviceName = attribute.Value.ToString(); - } - else if (attribute.Key == Resource.ServiceNamespaceKey && attribute.Value is string) - { - serviceNamespace = attribute.Value.ToString(); - } - else if (attribute.Key == Resource.ServiceInstanceIdKey && attribute.Value is string) - { - RoleInstance = attribute.Value.ToString(); - } - } - - if (serviceName != null && serviceNamespace != null) - { - RoleName = string.Concat(serviceNamespace, ".", serviceName); - } - else - { - RoleName = serviceName; - } - } + MonitorBase telemetryData = new MonitorBase(); + telemetryItem = TelemetryPartA.GetTelemetryItem(activity, instrumentationKey); - private static MonitorBase GenerateTelemetryData(Activity activity) - { - var telemetryType = activity.GetTelemetryType(); - var monitorTags = new TagEnumerationState - { - PartBTags = AzMonList.Initialize(), - PartCTags = AzMonList.Initialize() - }; - - activity.EnumerateTags(ref monitorTags); - - MonitorBase telemetry = new MonitorBase - { - BaseType = Telemetry_Base_Type_Mapping[telemetryType] - }; - - if (telemetryType == TelemetryType.Request) - { - monitorTags.PartBTags.GenerateUrlAndAuthority(out var url, out var urlAuthority); - var statusCode = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpStatusCode)?.ToString() ?? "0"; - var success = activity.GetStatus() != Status.Error; - var request = new RequestData(2, activity.Context.SpanId.ToHexString(), activity.Duration.ToString("c", CultureInfo.InvariantCulture), success, statusCode) - { - Name = activity.DisplayName, - Url = url, - Source = urlAuthority - }; - - // TODO: Handle activity.TagObjects, extract well-known tags - AddPropertiesToTelemetry(request.Properties, monitorTags.PartCTags); - telemetry.BaseData = request; - } - else if (telemetryType == TelemetryType.Dependency) - { - var dependency = new RemoteDependencyData(2, activity.DisplayName, activity.Duration.ToString("c", CultureInfo.InvariantCulture)) + switch (activity.GetTelemetryType()) { - Id = activity.Context.SpanId.ToHexString(), - Success = activity.GetStatus() != Status.Error - }; - - switch (monitorTags.activityType) - { - case PartBType.Http: - monitorTags.PartBTags.GenerateUrlAndAuthority(out var url, out var urlAuthority); - dependency.Data = url; - dependency.Target = urlAuthority; - dependency.Type = "Http"; - dependency.ResultCode = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpStatusCode)?.ToString() ?? "0"; - break; - case PartBType.Db: - var depDataAndType = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeDbStatement, SemanticConventions.AttributeDbSystem); - dependency.Data = depDataAndType[0]?.ToString(); - dependency.Type = depDataAndType[1]?.ToString(); + case TelemetryType.Request: + telemetryData.BaseType = Telemetry_Base_Type_Mapping[TelemetryType.Request]; + telemetryData.BaseData = TelemetryPartB.GetRequestData(activity); break; - case PartBType.Rpc: - var depInfo = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeRpcService, SemanticConventions.AttributeRpcSystem, SemanticConventions.AttributeRpcStatus); - dependency.Data = depInfo[0]?.ToString(); - dependency.Type = depInfo[1]?.ToString(); - dependency.ResultCode = depInfo[2]?.ToString(); - break; - case PartBType.Messaging: - depDataAndType = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeMessagingUrl, SemanticConventions.AttributeMessagingSystem); - dependency.Data = depDataAndType[0]?.ToString(); - dependency.Type = depDataAndType[1]?.ToString(); + case TelemetryType.Dependency: + telemetryData.BaseType = Telemetry_Base_Type_Mapping[TelemetryType.Dependency]; + telemetryData.BaseData = TelemetryPartB.GetRemoteDependencyData(activity); break; } - AddPropertiesToTelemetry(dependency.Properties, monitorTags.PartCTags); - telemetry.BaseData = dependency; - } - - return telemetry; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void AddPropertiesToTelemetry(IDictionary destination, AzMonList PartCTags) - { - // TODO: Iterate only interested fields. Ref: https://github.com/Azure/azure-sdk-for-net/pull/14254#discussion_r470907560 - for (int i = 0; i < PartCTags.Length; i++) - { - destination.Add(PartCTags[i].Key, PartCTags[i].Value?.ToString()); + telemetryItem.Data = telemetryData; + telemetryItems.Add(telemetryItem); } - } - internal struct TagEnumerationState : IActivityEnumerator> - { - public AzMonList PartBTags; - public AzMonList PartCTags; - - private PartBType tempActivityType; - public PartBType activityType; - - public bool ForEach(KeyValuePair activityTag) - { - if (activityTag.Value == null) - { - return true; - } - - if (activityTag.Value is Array array) - { - StringBuilder sw = new StringBuilder(); - foreach (var item in array) - { - // TODO: Consider changing it to JSon array. - if (item != null) - { - sw.Append(item); - sw.Append(','); - } - } - - if (sw.Length > 0) - { - sw.Length--; - } - - AzMonList.Add(ref PartCTags, new KeyValuePair(activityTag.Key, sw.ToString())); - return true; - } - - if (!Part_B_Mapping.TryGetValue(activityTag.Key, out tempActivityType)) - { - AzMonList.Add(ref PartCTags, activityTag); - return true; - } - - if (activityType == PartBType.Unknown || activityType == PartBType.Common) - { - activityType = tempActivityType; - } - - if (tempActivityType == activityType || tempActivityType == PartBType.Common) - { - AzMonList.Add(ref PartBTags, activityTag); - } - else - { - AzMonList.Add(ref PartCTags, activityTag); - } - - return true; - } + return telemetryItems; } } } diff --git a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/SdkVersionUtils.cs b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/SdkVersionUtils.cs index 40614e064a26..79e561fdfe3d 100644 --- a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/SdkVersionUtils.cs +++ b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/SdkVersionUtils.cs @@ -5,8 +5,7 @@ using System.Globalization; using System.Linq; using System.Reflection; - -using OpenTelemetrySdk = OpenTelemetry.Sdk; +using OpenTelemetry; namespace Microsoft.OpenTelemetry.Exporter.AzureMonitor { @@ -19,7 +18,7 @@ private static string GetSdkVersion() try { Version dotnetSdkVersion = GetVersion(typeof(object)); - Version otelSdkVersion = GetVersion(typeof(OpenTelemetrySdk)); + Version otelSdkVersion = GetVersion(typeof(Sdk)); Version extensionVersion = GetVersion(typeof(AzureMonitorTraceExporter)); return string.Format(CultureInfo.InvariantCulture, $"dotnet{dotnetSdkVersion.ToString(2)}:otel{otelSdkVersion.ToString(3)}:ext{extensionVersion.ToString(3)}"); diff --git a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/TagEnumerationState.cs b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/TagEnumerationState.cs new file mode 100644 index 000000000000..e920fb572021 --- /dev/null +++ b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/TagEnumerationState.cs @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; +using OpenTelemetry.Trace; + +namespace Microsoft.OpenTelemetry.Exporter.AzureMonitor +{ + internal struct TagEnumerationState : IActivityEnumerator> + { + private static readonly IReadOnlyDictionary Part_B_Mapping = new Dictionary() + { + [SemanticConventions.AttributeDbStatement] = PartBType.Db, + [SemanticConventions.AttributeDbSystem] = PartBType.Db, + + [SemanticConventions.AttributeHttpMethod] = PartBType.Http, + [SemanticConventions.AttributeHttpUrl] = PartBType.Http, + [SemanticConventions.AttributeHttpStatusCode] = PartBType.Http, + [SemanticConventions.AttributeHttpScheme] = PartBType.Http, + [SemanticConventions.AttributeHttpHost] = PartBType.Http, + [SemanticConventions.AttributeHttpHostPort] = PartBType.Http, + [SemanticConventions.AttributeHttpTarget] = PartBType.Http, + + [SemanticConventions.AttributeNetPeerName] = PartBType.Common, + [SemanticConventions.AttributeNetPeerIp] = PartBType.Common, + [SemanticConventions.AttributeNetPeerPort] = PartBType.Common, + [SemanticConventions.AttributeNetTransport] = PartBType.Common, + [SemanticConventions.AttributeNetHostIp] = PartBType.Common, + [SemanticConventions.AttributeNetHostPort] = PartBType.Common, + [SemanticConventions.AttributeNetHostName] = PartBType.Common, + [SemanticConventions.AttributeComponent] = PartBType.Common, + + [SemanticConventions.AttributeRpcService] = PartBType.Rpc, + [SemanticConventions.AttributeRpcSystem] = PartBType.Rpc, + [SemanticConventions.AttributeRpcStatus] = PartBType.Rpc, + + [SemanticConventions.AttributeFaasTrigger] = PartBType.FaaS, + [SemanticConventions.AttributeFaasExecution] = PartBType.FaaS, + [SemanticConventions.AttributeFaasColdStart] = PartBType.FaaS, + [SemanticConventions.AttributeFaasDocumentCollection] = PartBType.FaaS, + [SemanticConventions.AttributeFaasDocumentOperation] = PartBType.FaaS, + [SemanticConventions.AttributeFaasDocumentTime] = PartBType.FaaS, + [SemanticConventions.AttributeFaasDocumentName] = PartBType.FaaS, + [SemanticConventions.AttributeFaasCron] = PartBType.FaaS, + [SemanticConventions.AttributeFaasTime] = PartBType.FaaS, + + [SemanticConventions.AttributeAzureNameSpace] = PartBType.Azure, + [SemanticConventions.AttributeMessageBusDestination] = PartBType.Azure, + + [SemanticConventions.AttributeEndpointAddress] = PartBType.Messaging, + [SemanticConventions.AttributeMessagingSystem] = PartBType.Messaging, + [SemanticConventions.AttributeMessagingDestination] = PartBType.Messaging, + [SemanticConventions.AttributeMessagingDestinationKind] = PartBType.Messaging, + [SemanticConventions.AttributeMessagingTempDestination] = PartBType.Messaging, + [SemanticConventions.AttributeMessagingUrl] = PartBType.Messaging + }; + + public AzMonList PartBTags; + public AzMonList PartCTags; + + private PartBType tempActivityType; + public PartBType activityType; + + public bool ForEach(KeyValuePair activityTag) + { + if (activityTag.Value == null) + { + return true; + } + + if (activityTag.Value is Array array) + { + StringBuilder sw = new StringBuilder(); + foreach (var item in array) + { + // TODO: Consider changing it to JSon array. + if (item != null) + { + sw.Append(item); + sw.Append(','); + } + } + + if (sw.Length > 0) + { + sw.Length--; + } + + AzMonList.Add(ref PartCTags, new KeyValuePair(activityTag.Key, sw.ToString())); + return true; + } + + if (!Part_B_Mapping.TryGetValue(activityTag.Key, out tempActivityType)) + { + AzMonList.Add(ref PartCTags, activityTag); + return true; + } + + if (activityType == PartBType.Unknown || activityType == PartBType.Common) + { + activityType = tempActivityType; + } + + if (tempActivityType == activityType || tempActivityType == PartBType.Common) + { + AzMonList.Add(ref PartBTags, activityTag); + } + else + { + AzMonList.Add(ref PartCTags, activityTag); + } + + return true; + } + } +} diff --git a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/TelemetryPartA.cs b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/TelemetryPartA.cs new file mode 100644 index 000000000000..25b5c60f786d --- /dev/null +++ b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/TelemetryPartA.cs @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; +using Microsoft.OpenTelemetry.Exporter.AzureMonitor.Models; + +namespace Microsoft.OpenTelemetry.Exporter.AzureMonitor +{ + /// + /// Part A are the common data that apply to OTel Trace, OTel Logs and OTel Metrics. + /// + internal class TelemetryPartA + { + private static readonly IReadOnlyDictionary PartA_Name_Mapping = new Dictionary + { + [TelemetryType.Request] = "Request", + [TelemetryType.Dependency] = "RemoteDependency", + [TelemetryType.Message] = "Message", + [TelemetryType.Event] = "Event", + }; + + internal static string RoleName { get; set; } = null; + + internal static string RoleInstance { get; set; } = null; + + internal static TelemetryItem GetTelemetryItem(Activity activity, string instrumentationKey) + { + TelemetryItem telemetryItem = new TelemetryItem(PartA_Name_Mapping[activity.GetTelemetryType()], activity.StartTimeUtc.ToString(CultureInfo.InvariantCulture)) + { + InstrumentationKey = instrumentationKey + }; + + InitRoleInfo(activity); + telemetryItem.Tags[ContextTagKeys.AiCloudRole.ToString()] = RoleName; + telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()] = RoleInstance; + telemetryItem.Tags[ContextTagKeys.AiOperationId.ToString()] = activity.TraceId.ToHexString(); + + if (activity.Parent != null) + { + telemetryItem.Tags[ContextTagKeys.AiOperationParentId.ToString()] = activity.Parent.SpanId.ToHexString(); + } + + telemetryItem.Tags[ContextTagKeys.AiInternalSdkVersion.ToString()] = SdkVersionUtils.SdkVersion; + + return telemetryItem; + } + + internal static void InitRoleInfo(Activity activity) + { + if (RoleName != null || RoleInstance != null) + { + return; + } + + var resource = activity.GetResource(); + + if (resource == null) + { + return; + } + + string serviceName = null; + string serviceNamespace = null; + + foreach (var attribute in resource.Attributes) + { + if (attribute.Key == Resource.ServiceNameKey && attribute.Value is string) + { + serviceName = attribute.Value.ToString(); + } + else if (attribute.Key == Resource.ServiceNamespaceKey && attribute.Value is string) + { + serviceNamespace = attribute.Value.ToString(); + } + else if (attribute.Key == Resource.ServiceInstanceIdKey && attribute.Value is string) + { + RoleInstance = attribute.Value.ToString(); + } + } + + if (serviceName != null && serviceNamespace != null) + { + RoleName = string.Concat(serviceNamespace, ".", serviceName); + } + else + { + RoleName = serviceName; + } + } + } +} diff --git a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/TelemetryPartB.cs b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/TelemetryPartB.cs new file mode 100644 index 000000000000..1b0a73a1b6b5 --- /dev/null +++ b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/TelemetryPartB.cs @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.CompilerServices; +using OpenTelemetry.Trace; +using Microsoft.OpenTelemetry.Exporter.AzureMonitor.Models; + +namespace Microsoft.OpenTelemetry.Exporter.AzureMonitor +{ + /// + /// Part B are the Azure Monitor domain specific schemas. + /// These properties are unique to individual telemetry types. + /// For example, Request telemetry has Url and Message telemetry has Severity Level. + /// + internal class TelemetryPartB + { + internal static RequestData GetRequestData(Activity activity) + { + string url = null; + string urlAuthority = null; + var monitorTags = EnumerateActivityTags(activity); + + switch (monitorTags.activityType) + { + case PartBType.Http: + monitorTags.PartBTags.GenerateUrlAndAuthority(out url, out urlAuthority); + break; + case PartBType.Messaging: + url = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeMessagingUrl)?.ToString(); + break; + } + + var statusCode = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpStatusCode)?.ToString() ?? "0"; + var success = activity.GetStatus() != Status.Error; + var request = new RequestData(2, activity.Context.SpanId.ToHexString(), activity.Duration.ToString("c", CultureInfo.InvariantCulture), success, statusCode) + { + Name = activity.DisplayName, + Url = url, + Source = urlAuthority + }; + + AddPropertiesToTelemetry(request.Properties, ref monitorTags.PartCTags); + + return request; + } + + internal static RemoteDependencyData GetRemoteDependencyData(Activity activity) + { + var monitorTags = EnumerateActivityTags(activity); + + var dependency = new RemoteDependencyData(2, activity.DisplayName, activity.Duration.ToString("c", CultureInfo.InvariantCulture)) + { + Id = activity.Context.SpanId.ToHexString(), + Success = activity.GetStatus() != Status.Error + }; + + switch (monitorTags.activityType) + { + case PartBType.Http: + monitorTags.PartBTags.GenerateUrlAndAuthority(out var url, out var urlAuthority); + dependency.Data = url; + dependency.Target = urlAuthority; + dependency.Type = "Http"; + dependency.ResultCode = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpStatusCode)?.ToString() ?? "0"; + break; + case PartBType.Db: + var depDataAndType = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeDbStatement, SemanticConventions.AttributeDbSystem); + dependency.Data = depDataAndType[0]?.ToString(); + dependency.Type = depDataAndType[1]?.ToString(); + break; + case PartBType.Rpc: + var depInfo = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeRpcService, SemanticConventions.AttributeRpcSystem, SemanticConventions.AttributeRpcStatus); + dependency.Data = depInfo[0]?.ToString(); + dependency.Type = depInfo[1]?.ToString(); + dependency.ResultCode = depInfo[2]?.ToString(); + break; + case PartBType.Messaging: + depDataAndType = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeMessagingUrl, SemanticConventions.AttributeMessagingSystem); + dependency.Data = depDataAndType[0]?.ToString(); + dependency.Type = depDataAndType[1]?.ToString(); + break; + } + + AddPropertiesToTelemetry(dependency.Properties, ref monitorTags.PartCTags); + + return dependency; + } + + private static TagEnumerationState EnumerateActivityTags(Activity activity) + { + var monitorTags = new TagEnumerationState + { + PartBTags = AzMonList.Initialize(), + PartCTags = AzMonList.Initialize() + }; + + activity.EnumerateTags(ref monitorTags); + return monitorTags; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AddPropertiesToTelemetry(IDictionary destination, ref AzMonList PartCTags) + { + // TODO: Iterate only interested fields. Ref: https://github.com/Azure/azure-sdk-for-net/pull/14254#discussion_r470907560 + for (int i = 0; i < PartCTags.Length; i++) + { + destination.Add(PartCTags[i].Key, PartCTags[i].Value?.ToString()); + } + } + } +} diff --git a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Benchmarks/TagObjectsBenchmarks.cs b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Benchmarks/TagObjectsBenchmarks.cs index 4891b1109e42..32b240dcd391 100644 --- a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Benchmarks/TagObjectsBenchmarks.cs +++ b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Benchmarks/TagObjectsBenchmarks.cs @@ -12,7 +12,7 @@ namespace Microsoft.OpenTelemetry.Exporter.AzureMonitor.Benchmarks [MemoryDiagnoser] public class TagObjectsBenchmarks { - private AzureMonitorConverter.TagEnumerationState monitorTags; + private TagEnumerationState monitorTags; private IEnumerable> tagObjects; private IEnumerable> PartB_tagObjects; private IEnumerable> PartC_tagObjects; @@ -39,7 +39,7 @@ static TagObjectsBenchmarks() [GlobalSetup] public void Setup() { - monitorTags = new AzureMonitorConverter.TagEnumerationState + monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() diff --git a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Microsoft.OpenTelemetry.Exporter.AzureMonitor.Tests/TagsTests.cs b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Microsoft.OpenTelemetry.Exporter.AzureMonitor.Tests/TagsTests.cs index eabe2789ee1a..813a5b915fbc 100644 --- a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Microsoft.OpenTelemetry.Exporter.AzureMonitor.Tests/TagsTests.cs +++ b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Microsoft.OpenTelemetry.Exporter.AzureMonitor.Tests/TagsTests.cs @@ -27,7 +27,7 @@ static TagsTests() [Fact] public void TagObjects_NoItem() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -44,7 +44,7 @@ public void TagObjects_NoItem() [Fact] public void TagObjects_Empty() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -61,7 +61,7 @@ public void TagObjects_Empty() [Fact] public void TagObjects_NullItem() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -88,7 +88,7 @@ public void TagObjects_NullItem() [Fact] public void TagObjects_PartC() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -106,7 +106,7 @@ public void TagObjects_PartC() [Fact] public void TagObjects_PartB() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -137,7 +137,7 @@ public void TagObjects_PartB() [Fact] public void TagObjects_PartB_PartC() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -168,7 +168,7 @@ public void TagObjects_PartB_PartC() [Fact] public void TagObjects_IntArray() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -192,7 +192,7 @@ public void TagObjects_IntArray() [Fact] public void TagObjects_DoubleArray() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -216,7 +216,7 @@ public void TagObjects_DoubleArray() [Fact] public void TagObjects_StringArray() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -240,7 +240,7 @@ public void TagObjects_StringArray() [Fact] public void TagObjects_BooleanArray() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -264,7 +264,7 @@ public void TagObjects_BooleanArray() [Fact] public void TagObjects_ObjectArray() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() @@ -288,7 +288,7 @@ public void TagObjects_ObjectArray() [Fact] public void TagObjects_Diff_DataTypes() { - var monitorTags = new AzureMonitorConverter.TagEnumerationState + var monitorTags = new TagEnumerationState { PartBTags = AzMonList.Initialize(), PartCTags = AzMonList.Initialize() diff --git a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Microsoft.OpenTelemetry.Exporter.AzureMonitor.Tests/AzureMonitorConverterTests.cs b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Microsoft.OpenTelemetry.Exporter.AzureMonitor.Tests/TelemetryPartATests.cs similarity index 81% rename from sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Microsoft.OpenTelemetry.Exporter.AzureMonitor.Tests/AzureMonitorConverterTests.cs rename to sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Microsoft.OpenTelemetry.Exporter.AzureMonitor.Tests/TelemetryPartATests.cs index 45da2b368e0c..d5632784a9dc 100644 --- a/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Microsoft.OpenTelemetry.Exporter.AzureMonitor.Tests/AzureMonitorConverterTests.cs +++ b/sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/tests/Microsoft.OpenTelemetry.Exporter.AzureMonitor.Tests/TelemetryPartATests.cs @@ -12,11 +12,11 @@ namespace Microsoft.OpenTelemetry.Exporter.AzureMonitor.Demo.Tracing { - public class AzureMonitorConverterTests + public class TelemetryPartATests { private const string ResourcePropertyName = "OTel.Resource"; - static AzureMonitorConverterTests() + static TelemetryPartATests() { Activity.DefaultIdFormat = ActivityIdFormat.W3C; Activity.ForceDefaultIdFormat = true; @@ -30,19 +30,19 @@ static AzureMonitorConverterTests() ActivitySource.AddActivityListener(listener); } - public AzureMonitorConverterTests() + public TelemetryPartATests() { - AzureMonitorConverter.RoleName = null; - AzureMonitorConverter.RoleInstance = null; + TelemetryPartA.RoleName = null; + TelemetryPartA.RoleInstance = null; } [Fact] public void InitRoleInfo_NullResource() { - AzureMonitorConverter.InitRoleInfo(null); + TelemetryPartA.InitRoleInfo(null); - Assert.Null(AzureMonitorConverter.RoleName); - Assert.Null(AzureMonitorConverter.RoleInstance); + Assert.Null(TelemetryPartA.RoleName); + Assert.Null(TelemetryPartA.RoleInstance); } [Fact] @@ -51,9 +51,9 @@ public void InitRoleInfo_Empty() using var activity = new Activity("InitRoleInfo_Empty"); activity.SetCustomProperty(ResourcePropertyName, Resources.CreateServiceResource(null)); - AzureMonitorConverter.InitRoleInfo(activity); - Assert.Null(AzureMonitorConverter.RoleName); - Assert.Null(AzureMonitorConverter.RoleInstance); + TelemetryPartA.InitRoleInfo(activity); + Assert.Null(TelemetryPartA.RoleName); + Assert.Null(TelemetryPartA.RoleInstance); } [Fact] @@ -61,9 +61,9 @@ public void InitRoleInfo_ServiceName() { using var activity = new Activity("InitRoleInfo_ServiceName"); activity.SetCustomProperty(ResourcePropertyName, Resources.CreateServiceResource("my-service")); - AzureMonitorConverter.InitRoleInfo(activity); - Assert.Equal("my-service", AzureMonitorConverter.RoleName); - Assert.True(Guid.TryParse(AzureMonitorConverter.RoleInstance, out var guid)); + TelemetryPartA.InitRoleInfo(activity); + Assert.Equal("my-service", TelemetryPartA.RoleName); + Assert.True(Guid.TryParse(TelemetryPartA.RoleInstance, out var guid)); } [Fact] @@ -71,10 +71,10 @@ public void InitRoleInfo_ServiceInstance() { using var activity = new Activity("InitRoleInfo_ServiceInstance"); activity.SetCustomProperty(ResourcePropertyName, Resources.CreateServiceResource(null, "roleInstance_1")); - AzureMonitorConverter.InitRoleInfo(activity); + TelemetryPartA.InitRoleInfo(activity); - Assert.Null(AzureMonitorConverter.RoleName); - Assert.Null(AzureMonitorConverter.RoleInstance); + Assert.Null(TelemetryPartA.RoleName); + Assert.Null(TelemetryPartA.RoleInstance); } [Fact] @@ -82,9 +82,9 @@ public void InitRoleInfo_ServiceNamespace() { using var activity = new Activity("InitRoleInfo_ServiceNamespace"); activity.SetCustomProperty(ResourcePropertyName, Resources.CreateServiceResource(null, null, "my-namespace")); - AzureMonitorConverter.InitRoleInfo(activity); - Assert.Null(AzureMonitorConverter.RoleName); - Assert.Null(AzureMonitorConverter.RoleInstance); + TelemetryPartA.InitRoleInfo(activity); + Assert.Null(TelemetryPartA.RoleName); + Assert.Null(TelemetryPartA.RoleInstance); } [Fact] @@ -92,9 +92,9 @@ public void InitRoleInfo_ServiceNameAndInstance() { using var activity = new Activity("InitRoleInfo_ServiceNameAndInstance"); activity.SetCustomProperty(ResourcePropertyName, Resources.CreateServiceResource("my-service", "roleInstance_1")); - AzureMonitorConverter.InitRoleInfo(activity); - Assert.Equal("my-service", AzureMonitorConverter.RoleName); - Assert.Equal("roleInstance_1", AzureMonitorConverter.RoleInstance); + TelemetryPartA.InitRoleInfo(activity); + Assert.Equal("my-service", TelemetryPartA.RoleName); + Assert.Equal("roleInstance_1", TelemetryPartA.RoleInstance); } [Fact] @@ -102,16 +102,16 @@ public void InitRoleInfo_ServiceNameAndInstanceAndNamespace() { using var activity = new Activity("InitRoleInfo_ServiceNameAndInstanceAndNamespace"); activity.SetCustomProperty(ResourcePropertyName, Resources.CreateServiceResource("my-service", "roleInstance_1", "my-namespace")); - AzureMonitorConverter.InitRoleInfo(activity); - Assert.Equal("my-namespace.my-service", AzureMonitorConverter.RoleName); - Assert.Equal("roleInstance_1", AzureMonitorConverter.RoleInstance); + TelemetryPartA.InitRoleInfo(activity); + Assert.Equal("my-namespace.my-service", TelemetryPartA.RoleName); + Assert.Equal("roleInstance_1", TelemetryPartA.RoleInstance); } [Fact] public void GeneratePartAEnvelope_DefaultActivity() { var activity = CreateTestActivity(); - var telemetryItem = AzureMonitorConverter.GeneratePartAEnvelope(activity); + var telemetryItem = TelemetryPartA.GetTelemetryItem(activity, null); Assert.Equal("RemoteDependency", telemetryItem.Name); Assert.Equal(activity.StartTimeUtc.ToString(CultureInfo.InvariantCulture), telemetryItem.Time); Assert.Null(telemetryItem.Tags[ContextTagKeys.AiCloudRole.ToString()]); @@ -127,7 +127,7 @@ public void GeneratePartAEnvelope_ActivityWithRoleInformation() var activity = CreateTestActivity( resource: Resources.CreateServiceResource("BusyWorker", "TEST3650724")); - var telemetryItem = AzureMonitorConverter.GeneratePartAEnvelope(activity); + var telemetryItem = TelemetryPartA.GetTelemetryItem(activity, null); Assert.Equal("RemoteDependency", telemetryItem.Name); Assert.Equal(activity.StartTimeUtc.ToString(CultureInfo.InvariantCulture), telemetryItem.Time); Assert.Equal("BusyWorker", telemetryItem.Tags[ContextTagKeys.AiCloudRole.ToString()]);