diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/RemoteDependencyData.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/RemoteDependencyData.cs
index b94ec3dab154..5d08c465e60e 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/RemoteDependencyData.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/RemoteDependencyData.cs
@@ -46,7 +46,7 @@ public RemoteDependencyData(int version, Activity activity, ref ActivityTagsProc
}
dependencyName ??= activity.DisplayName;
- Name = dependencyName.Truncate(SchemaConstants.RemoteDependencyData_Name_MaxLength);
+ Name = dependencyName?.Truncate(SchemaConstants.RemoteDependencyData_Name_MaxLength);
Id = activity.Context.SpanId.ToHexString();
Duration = activity.Duration < SchemaConstants.RemoteDependencyData_Duration_LessThanDays
? activity.Duration.ToString("c", CultureInfo.InvariantCulture)
@@ -101,8 +101,8 @@ private void SetHttpDependencyPropertiesAndDependencyName(Activity activity, ref
}
Type = "Http";
- Data = httpUrl.Truncate(SchemaConstants.RemoteDependencyData_Data_MaxLength);
- Target = target.Truncate(SchemaConstants.RemoteDependencyData_Target_MaxLength);
+ Data = httpUrl?.Truncate(SchemaConstants.RemoteDependencyData_Data_MaxLength);
+ Target = target?.Truncate(SchemaConstants.RemoteDependencyData_Target_MaxLength);
ResultCode = resultCode?.Truncate(SchemaConstants.RemoteDependencyData_ResultCode_MaxLength) ?? "0";
}
@@ -111,11 +111,11 @@ private void SetDbDependencyProperties(ref AzMonList dbTagObjects)
var dbAttributeTagObjects = AzMonList.GetTagValues(ref dbTagObjects, SemanticConventions.AttributeDbStatement, SemanticConventions.AttributeDbSystem);
Data = dbAttributeTagObjects[0]?.ToString().Truncate(SchemaConstants.RemoteDependencyData_Data_MaxLength);
var (DbName, DbTarget) = dbTagObjects.GetDbDependencyTargetAndName();
- Target = DbTarget.Truncate(SchemaConstants.RemoteDependencyData_Target_MaxLength);
+ Target = DbTarget?.Truncate(SchemaConstants.RemoteDependencyData_Target_MaxLength);
Type = s_sqlDbs.Contains(dbAttributeTagObjects[1]?.ToString()) ? "SQL" : dbAttributeTagObjects[1]?.ToString().Truncate(SchemaConstants.RemoteDependencyData_Type_MaxLength);
// special case for db.name
- var sanitizedDbName = DbName.Truncate(SchemaConstants.KVP_MaxValueLength);
+ var sanitizedDbName = DbName?.Truncate(SchemaConstants.KVP_MaxValueLength);
if (sanitizedDbName != null)
{
Properties.Add(SemanticConventions.AttributeDbName, sanitizedDbName);
@@ -132,10 +132,10 @@ private void SetRpcDependencyProperties(ref AzMonList rpcTagObjects)
private void SetMessagingDependencyProperties(Activity activity, ref AzMonList messagingTagObjects)
{
- var messagingAttributeTagObjects = AzMonList.GetTagValues(ref messagingTagObjects, SemanticConventions.AttributeMessagingUrl, SemanticConventions.AttributeMessagingSystem);
- var messagingUrl = messagingAttributeTagObjects[0]?.ToString();
+ var (messagingUrl, target) = messagingTagObjects.GetMessagingUrlAndSourceOrTarget(activity.Kind);
Data = messagingUrl?.Truncate(SchemaConstants.RemoteDependencyData_Data_MaxLength);
- Type = messagingAttributeTagObjects[1]?.ToString().Truncate(SchemaConstants.RemoteDependencyData_Type_MaxLength);
+ Target = target?.Truncate(SchemaConstants.RemoteDependencyData_Target_MaxLength);
+ Type = AzMonList.GetTagValue(ref messagingTagObjects, SemanticConventions.AttributeMessagingSystem)?.ToString().Truncate(SchemaConstants.RemoteDependencyData_Type_MaxLength);
}
}
}
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/RequestData.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/RequestData.cs
index 80b4bca4e4e8..a6b58387eab9 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/RequestData.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/RequestData.cs
@@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Globalization;
+using System.Runtime.CompilerServices;
using Azure.Core;
using Azure.Monitor.OpenTelemetry.Exporter.Internals;
@@ -10,6 +11,12 @@ namespace Azure.Monitor.OpenTelemetry.Exporter.Models
{
internal partial class RequestData
{
+ public RequestData(int version, string? operationName, string? requestUrl, Activity activity, ref ActivityTagsProcessor activityTagsProcessor) : this(version, activity, ref activityTagsProcessor)
+ {
+ Name = operationName?.Truncate(SchemaConstants.RequestData_Name_MaxLength);
+ Url = requestUrl?.Truncate(SchemaConstants.RequestData_Url_MaxLength);
+ }
+
public RequestData(int version, Activity activity, ref ActivityTagsProcessor activityTagsProcessor) : base(version)
{
string? responseCode = null;
@@ -50,6 +57,7 @@ public RequestData(int version, Activity activity, ref ActivityTagsProcessor act
TraceHelper.AddPropertiesToTelemetry(Properties, ref activityTagsProcessor.UnMappedTags);
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool IsSuccess(Activity activity, string? responseCode, OperationType operationType)
{
if (operationType.HasFlag(OperationType.Http)
@@ -67,8 +75,8 @@ internal static bool IsSuccess(Activity activity, string? responseCode, Operatio
private void SetHttpRequestPropertiesAndResponseCode(Activity activity, ref AzMonList httpTagObjects, out string responseCode)
{
- Url = httpTagObjects.GetRequestUrl().Truncate(SchemaConstants.RequestData_Url_MaxLength);
- Name = TraceHelper.GetOperationName(activity, ref httpTagObjects).Truncate(SchemaConstants.RequestData_Name_MaxLength);
+ Url ??= httpTagObjects.GetRequestUrl()?.Truncate(SchemaConstants.RequestData_Url_MaxLength);
+ Name ??= TraceHelper.GetOperationName(activity, ref httpTagObjects)?.Truncate(SchemaConstants.RequestData_Name_MaxLength);
responseCode = AzMonList.GetTagValue(ref httpTagObjects, SemanticConventions.AttributeHttpStatusCode)
?.ToString().Truncate(SchemaConstants.RequestData_ResponseCode_MaxLength)
?? "0";
@@ -76,8 +84,8 @@ private void SetHttpRequestPropertiesAndResponseCode(Activity activity, ref AzMo
private void SetHttpV2RequestPropertiesAndResponseCode(Activity activity, ref AzMonList httpTagObjects, out string responseCode)
{
- Url = httpTagObjects.GetNewSchemaRequestUrl().Truncate(SchemaConstants.RequestData_Url_MaxLength);
- Name = TraceHelper.GetNewSchemaOperationName(activity, Url, ref httpTagObjects).Truncate(SchemaConstants.RequestData_Name_MaxLength);
+ Url ??= httpTagObjects.GetNewSchemaRequestUrl()?.Truncate(SchemaConstants.RequestData_Url_MaxLength);
+ Name ??= TraceHelper.GetNewSchemaOperationName(activity, Url, ref httpTagObjects)?.Truncate(SchemaConstants.RequestData_Name_MaxLength);
responseCode = AzMonList.GetTagValue(ref httpTagObjects, SemanticConventions.AttributeHttpResponseStatusCode)
?.ToString().Truncate(SchemaConstants.RequestData_ResponseCode_MaxLength)
?? "0";
@@ -85,7 +93,9 @@ private void SetHttpV2RequestPropertiesAndResponseCode(Activity activity, ref Az
private void SetMessagingRequestProperties(Activity activity, ref AzMonList messagingTagObjects)
{
- Url = AzMonList.GetTagValue(ref messagingTagObjects, SemanticConventions.AttributeMessagingUrl)?.ToString().Truncate(SchemaConstants.RequestData_Url_MaxLength);
+ var (messagingUrl, source) = messagingTagObjects.GetMessagingUrlAndSourceOrTarget(activity.Kind);
+ Url = messagingUrl?.Truncate(SchemaConstants.RequestData_Url_MaxLength);
+ Source = source?.Truncate(SchemaConstants.RequestData_Source_MaxLength);
Name = activity.DisplayName;
}
}
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 3664fcb6e387..9df309479a29 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
@@ -32,17 +32,6 @@ public TelemetryItem(Activity activity, ref ActivityTagsProcessor activityTagsPr
}
SetAuthenticatedUserId(ref activityTagsProcessor);
-
- // we only have mapping for server spans
- // todo: non-server spans
- if (activity.Kind == ActivityKind.Server)
- {
- Tags[ContextTagKeys.AiOperationName.ToString()] = activityTagsProcessor.activityType.HasFlag(OperationType.V2)
- ? TraceHelper.GetNewSchemaOperationName(activity, null, ref activityTagsProcessor.MappedTags)
- : TraceHelper.GetOperationName(activity, ref activityTagsProcessor.MappedTags);
- Tags[ContextTagKeys.AiLocationIp.ToString()] = TraceHelper.GetLocationIp(ref activityTagsProcessor.MappedTags);
- }
-
SetResourceSdkVersionAndIkey(resource, instrumentationKey);
if (AzMonList.GetTagValue(ref activityTagsProcessor.MappedTags, "sampleRate") is float sampleRate)
{
@@ -62,14 +51,6 @@ public TelemetryItem(string name, TelemetryItem telemetryItem, ActivitySpanId ac
Tags["ai.user.userAgent"] = userAgent;
}
- // we only have mapping for server spans
- // todo: non-server spans
- if (kind == ActivityKind.Server)
- {
- Tags[ContextTagKeys.AiOperationName.ToString()] = telemetryItem.Tags[ContextTagKeys.AiOperationName.ToString()];
- Tags[ContextTagKeys.AiLocationIp.ToString()] = telemetryItem.Tags[ContextTagKeys.AiLocationIp.ToString()];
- }
-
Tags[ContextTagKeys.AiCloudRole.ToString()] = telemetryItem.Tags[ContextTagKeys.AiCloudRole.ToString()];
Tags[ContextTagKeys.AiCloudRoleInstance.ToString()] = telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()];
Tags[ContextTagKeys.AiInternalSdkVersion.ToString()] = SdkVersionUtils.s_sdkVersion;
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 20e7e18ad028..8771638e95bd 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/ActivityTagsProcessor.cs
@@ -61,10 +61,8 @@ internal struct ActivityTagsProcessor
SemanticConventions.AttributeEndpointAddress,
// required - Messaging
SemanticConventions.AttributeMessagingSystem,
- SemanticConventions.AttributeMessagingDestination,
- SemanticConventions.AttributeMessagingDestinationKind,
- SemanticConventions.AttributeMessagingTempDestination,
- SemanticConventions.AttributeMessagingUrl,
+ SemanticConventions.AttributeMessagingDestinationName,
+ SemanticConventions.AttributeNetworkProtocolName,
// Others
SemanticConventions.AttributeEnduserId
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/AzMonNewListExtensions.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/AzMonNewListExtensions.cs
index 03215897fb39..feb3f3a96add 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/AzMonNewListExtensions.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/AzMonNewListExtensions.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System;
+using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Azure.Monitor.OpenTelemetry.Exporter.Internals;
@@ -15,31 +16,79 @@ internal static class AzMonNewListExtensions
{
try
{
- var serverAddress = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeServerAddress)?.ToString();
- if (serverAddress != null)
+ var requestUrlTagObjects = AzMonList.GetTagValues(ref tagObjects, SemanticConventions.AttributeUrlScheme, SemanticConventions.AttributeServerAddress, SemanticConventions.AttributeServerPort, SemanticConventions.AttributeUrlPath, SemanticConventions.AttributeUrlQuery);
+
+ var scheme = requestUrlTagObjects[0]?.ToString() ?? string.Empty; // requestUrlTagObjects[0] => SemanticConventions.AttributeUrlScheme.
+ var host = requestUrlTagObjects[1]?.ToString() ?? string.Empty; // requestUrlTagObjects[1] => SemanticConventions.AttributeServerAddress.
+ var port = requestUrlTagObjects[2]?.ToString(); // requestUrlTagObjects[2] => SemanticConventions.AttributeServerPort.
+ port = port != null ? port = $":{port}" : string.Empty;
+ var path = requestUrlTagObjects[3]?.ToString() ?? string.Empty; // requestUrlTagObjects[3] => SemanticConventions.AttributeUrlPath.
+ var queryString = requestUrlTagObjects[4]?.ToString() ?? string.Empty; // requestUrlTagObjects[4] => SemanticConventions.AttributeUrlQuery.
+
+ var length = scheme.Length + Uri.SchemeDelimiter.Length + host.Length + port.Length + path.Length + queryString.Length;
+
+ var urlStringBuilder = new System.Text.StringBuilder(length)
+ .Append(scheme)
+ .Append(Uri.SchemeDelimiter)
+ .Append(host)
+ .Append(port)
+ .Append(path)
+ .Append(queryString);
+
+ return urlStringBuilder.ToString();
+ }
+ catch
+ {
+ // If URI building fails, there is no need to throw an exception. Instead, we can simply return null.
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets messaging url from activity tag objects.
+ ///
+ internal static (string? MessagingUrl, string? SourceOrTarget) GetMessagingUrlAndSourceOrTarget(this AzMonList tagObjects, ActivityKind activityKind)
+ {
+ string? messagingUrl = null;
+ string? sourceOrTarget = null;
+
+ try
+ {
+ var host = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeServerAddress)?.ToString()
+ ?? AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeNetPeerName)?.ToString();
+ if (!string.IsNullOrEmpty(host))
{
- UriBuilder uriBuilder = new()
- {
- Scheme = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeUrlScheme)?.ToString(),
- Host = serverAddress,
- Path = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeUrlPath)?.ToString(),
- Query = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeUrlQuery)?.ToString()
- };
+ object?[] messagingTagObjects;
- if (int.TryParse(AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeServerPort)?.ToString(), out int port))
+ messagingTagObjects = AzMonList.GetTagValues(ref tagObjects, SemanticConventions.AttributeNetworkProtocolName, SemanticConventions.AttributeMessagingDestinationName);
+ var protocolName = messagingTagObjects[0]?.ToString() ?? string.Empty; // messagingTagObjects[0] => SemanticConventions.AttributeNetworkProtocolName.
+ var destinationName = messagingTagObjects[1]?.ToString() ?? string.Empty; // messagingTagObjects[1] => SemanticConventions.AttributeMessagingDestinationName.
+
+ if (destinationName.Length > 0)
{
- uriBuilder.Port = port;
+ destinationName = $"/{destinationName}";
}
- return uriBuilder.Uri.AbsoluteUri;
+ sourceOrTarget = $"{host}{destinationName}";
+
+ var length = protocolName.Length + (protocolName?.Length > 0 ? Uri.SchemeDelimiter.Length : 0) + host!.Length + destinationName.Length;
+
+ var messagingStringBuilder = new System.Text.StringBuilder(length)
+ .Append(protocolName)
+ .Append(string.IsNullOrEmpty(protocolName) ? null : Uri.SchemeDelimiter)
+ .Append(host)
+ .Append(destinationName);
+
+ messagingUrl = messagingStringBuilder.ToString();
}
}
catch
{
- // If URI building fails, there is no need to throw an exception. Instead, we can simply return null.
+ // If Messaging Url building fails, there is no need to throw an exception. Instead, we can simply return null.
}
- return null;
+ return (MessagingUrl: messagingUrl, SourceOrTarget: sourceOrTarget);
}
///
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 0e87aee27fed..f544ff0e1a26 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SemanticConventions.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SemanticConventions.cs
@@ -163,5 +163,9 @@ internal static class SemanticConventions
public const string AttributeUrlQuery = "url.query";
public const string AttributeUserAgentOriginal = "user_agent.original"; // replaces: "http.user_agent" (AttributeHttpUserAgent)
public const string AttributeServerSocketAddress = "server.socket.address"; // replaces: "net.peer.ip" (AttributeNetPeerIp)
+
+ // Messaging v1.21.0 https://github.com/open-telemetry/opentelemetry-specification/blob/v1.21.0/specification/trace/semantic_conventions/messaging.md
+ public const string AttributeMessagingDestinationName = "messaging.destination.name";
+ public const string AttributeNetworkProtocolName = "network.protocol.name";
}
}
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 c5b44d06390d..16dad352340f 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/TraceHelper.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/TraceHelper.cs
@@ -45,11 +45,26 @@ internal static List OtelToAzureMonitorTrace(Batch batc
switch (activity.GetTelemetryType())
{
case TelemetryType.Request:
- telemetryItem.Data = new MonitorBase
+ if (activity.Kind == ActivityKind.Server && activityTagsProcessor.activityType.HasFlag(OperationType.Http))
{
- BaseType = "RequestData",
- BaseData = new RequestData(Version, activity, ref activityTagsProcessor)
- };
+ var (requestUrl, operationName) = GetHttpOperationNameAndUrl(activity.DisplayName, activityTagsProcessor.activityType, ref activityTagsProcessor.MappedTags);
+ telemetryItem.Tags[ContextTagKeys.AiOperationName.ToString()] = operationName;
+ telemetryItem.Tags[ContextTagKeys.AiLocationIp.ToString()] = TraceHelper.GetLocationIp(ref activityTagsProcessor.MappedTags);
+
+ telemetryItem.Data = new MonitorBase
+ {
+ BaseType = "RequestData",
+ BaseData = new RequestData(Version, operationName, requestUrl, activity, ref activityTagsProcessor)
+ };
+ }
+ else
+ {
+ telemetryItem.Data = new MonitorBase
+ {
+ BaseType = "RequestData",
+ BaseData = new RequestData(Version, activity, ref activityTagsProcessor)
+ };
+ }
break;
case TelemetryType.Dependency:
telemetryItem.Data = new MonitorBase
@@ -171,7 +186,7 @@ internal static string GetOperationName(Activity activity, ref AzMonList MappedT
return activity.DisplayName;
}
- internal static string GetNewSchemaOperationName(Activity activity, string? url, ref AzMonList MappedTags)
+ internal static string GetNewSchemaOperationName(Activity activity, string? url, ref AzMonList MappedTags)
{
var httpMethod = AzMonList.GetTagValue(ref MappedTags, SemanticConventions.AttributeHttpRequestMethod)?.ToString();
if (!string.IsNullOrWhiteSpace(httpMethod))
@@ -195,6 +210,42 @@ internal static string GetNewSchemaOperationName(Activity activity, string? url,
return activity.DisplayName;
}
+ internal static (string? RequestUrl, string? OperationName) GetHttpOperationNameAndUrl(string activityDisplayName, OperationType operationType, ref AzMonList httpMappedTags)
+ {
+ string? httpMethod;
+ string? httpUrl;
+
+ if (operationType.HasFlag(OperationType.V2))
+ {
+ httpUrl = httpMappedTags.GetNewSchemaRequestUrl();
+ httpMethod = AzMonList.GetTagValue(ref httpMappedTags, SemanticConventions.AttributeHttpRequestMethod)?.ToString();
+ }
+ else
+ {
+ httpUrl = AzMonList.GetTagValue(ref httpMappedTags, SemanticConventions.AttributeHttpUrl)?.ToString();
+ httpMethod = AzMonList.GetTagValue(ref httpMappedTags, SemanticConventions.AttributeHttpMethod)?.ToString();
+ }
+
+ if (!string.IsNullOrWhiteSpace(httpMethod))
+ {
+ var httpRoute = AzMonList.GetTagValue(ref httpMappedTags, SemanticConventions.AttributeHttpRoute)?.ToString();
+
+ // ASP.NET instrumentation assigns route as {controller}/{action}/{id} which would result in the same name for different operations.
+ // To work around that we will use path from httpUrl.
+ if (httpRoute?.Contains("{controller}") == false)
+ {
+ return (RequestUrl: httpUrl, OperationName: $"{httpMethod} {httpRoute}");
+ }
+
+ if (!string.IsNullOrWhiteSpace(httpUrl) && Uri.TryCreate(httpUrl!.ToString(), UriKind.RelativeOrAbsolute, out var uri) && uri.IsAbsoluteUri)
+ {
+ return (RequestUrl: httpUrl, OperationName: $"{httpMethod} {uri.AbsolutePath}");
+ }
+ }
+
+ return (RequestUrl: httpUrl, OperationName: activityDisplayName);
+ }
+
private static void AddTelemetryFromActivityEvents(Activity activity, TelemetryItem telemetryItem, List telemetryItems)
{
foreach (ref readonly var @event in activity.EnumerateEvents())
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/AzMonNewListExtensionsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/AzMonNewListExtensionsTests.cs
index 7fe3a125e7d4..e2ad49609996 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/AzMonNewListExtensionsTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/AzMonNewListExtensionsTests.cs
@@ -1,8 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
+using System;
using System.Collections.Generic;
-
+using System.Diagnostics;
using Azure.Monitor.OpenTelemetry.Exporter.Internals;
using Xunit;
@@ -11,13 +12,11 @@ namespace Azure.Monitor.OpenTelemetry.Exporter.Tests
public class AzMonNewListExtensionsTests
{
[Theory]
- [InlineData("http", "example.com", "8080", "/search", "q=OpenTelemetry", "http://example.com:8080/search?q=OpenTelemetry")]
- [InlineData(null, "example.com", "8080", "/search", "q=OpenTelemetry", "example.com:8080/search?q=OpenTelemetry")]
- [InlineData("http", null, "8080", "/search", "q=OpenTelemetry", null)]
- [InlineData("http", "example.com", null, "/search", "q=OpenTelemetry", "http://example.com/search?q=OpenTelemetry")]
- [InlineData("http", "example.com", "8080", null, "q=OpenTelemetry", "http://example.com:8080/?q=OpenTelemetry")]
+ [InlineData("http", "example.com", "8080", "/search", "?q=OpenTelemetry", "http://example.com:8080/search?q=OpenTelemetry")]
+ [InlineData("http", "example.com", null, "/search", "?q=OpenTelemetry", "http://example.com/search?q=OpenTelemetry")]
+ [InlineData("http", "example.com", "8080", "/", "?q=OpenTelemetry", "http://example.com:8080/?q=OpenTelemetry")]
[InlineData("http", "example.com", "8080", "/search", null, "http://example.com:8080/search")]
- public void GetNewRequestUrl_ReturnsCorrectUrl(string urlScheme, string serverAddress, string serverPort, string urlPath, string urlQuery, string expectedUrl)
+ public void GetNewRequestUrl_ReturnsCorrectUrl(string urlScheme, string serverAddress, string? serverPort, string urlPath, string? urlQuery, string expectedUrl)
{
// Arrange
AzMonList tagObjects = AzMonList.Initialize();
@@ -27,11 +26,56 @@ public void GetNewRequestUrl_ReturnsCorrectUrl(string urlScheme, string serverAd
AzMonList.Add(ref tagObjects, new KeyValuePair(SemanticConventions.AttributeUrlPath, urlPath));
AzMonList.Add(ref tagObjects, new KeyValuePair(SemanticConventions.AttributeUrlQuery, urlQuery));
+ // Validate the length with the same logic from code.
+ int colonLength = serverPort == null ? 0 : 1;
+ serverPort ??= string.Empty;
+ urlQuery ??= string.Empty;
+ var length = urlScheme.Length + Uri.SchemeDelimiter.Length + serverAddress.Length + serverPort.Length + colonLength + urlPath.Length + urlQuery.Length;
+
// Act
string? url = tagObjects.GetNewSchemaRequestUrl();
// Assert
Assert.Equal(expectedUrl, url);
+ Assert.Equal(length, url?.Length);
+ }
+
+ [Theory]
+ [InlineData("my.servicebus.windows.net", "amqp", "queueName", "amqp://my.servicebus.windows.net/queueName", "my.servicebus.windows.net/queueName")]
+ [InlineData("my.servicebus.windows.net", "amqp", "", "amqp://my.servicebus.windows.net", "my.servicebus.windows.net")]
+ [InlineData("", "amqp", "queueName", null, null)]
+ [InlineData("my.servicebus.windows.net", "", "queueName", "my.servicebus.windows.net/queueName", "my.servicebus.windows.net/queueName")]
+ [InlineData("my.servicebus.windows.net", null, null, "my.servicebus.windows.net", "my.servicebus.windows.net")]
+ [InlineData(null, "amqp", "queueName", null, null)]
+ public void GetMessagingUrlAndSourceOrTarget_ReturnsCorrectResult(string serverAddress, string protocolName, string destinationName, string expectedUrl, string expectedSourceOrTarget)
+ {
+ // Arrange
+ AzMonList tagObjects = AzMonList.Initialize();
+ AzMonList.Add(ref tagObjects, new KeyValuePair(SemanticConventions.AttributeServerAddress, serverAddress));
+ AzMonList.Add(ref tagObjects, new KeyValuePair(SemanticConventions.AttributeNetworkProtocolName, protocolName));
+ AzMonList.Add(ref tagObjects, new KeyValuePair(SemanticConventions.AttributeMessagingDestinationName, destinationName));
+
+ // Act
+ var (messagingUrl, sourceOrTarget) = tagObjects.GetMessagingUrlAndSourceOrTarget(ActivityKind.Producer);
+
+ // Assert
+ Assert.Equal(expectedUrl, messagingUrl);
+ Assert.Equal(expectedSourceOrTarget, sourceOrTarget);
+ }
+
+ [Fact]
+ public void GetMessagingUrlAndSourceOrTarget_NullTagObjects_ReturnsNull()
+ {
+ // Arrange
+ AzMonList tagObjects = AzMonList.Initialize();
+ var activityKind = ActivityKind.Consumer;
+
+ // Act
+ var (messagingUrl, sourceOrTarget) = tagObjects.GetMessagingUrlAndSourceOrTarget(activityKind);
+
+ // Assert
+ Assert.Null(messagingUrl);
+ Assert.Null(sourceOrTarget);
}
[Theory]
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/CommonTestFramework/TelemetryItemValidationHelper.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/CommonTestFramework/TelemetryItemValidationHelper.cs
index 9a6fade55062..d5f93d246c46 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/CommonTestFramework/TelemetryItemValidationHelper.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/CommonTestFramework/TelemetryItemValidationHelper.cs
@@ -143,14 +143,6 @@ public static void AssertActivity_As_RequestTelemetry(
var expectedTagsCount = 5;
- if (activityKind == ActivityKind.Server)
- {
- expectedTagsCount = 7;
-
- Assert.Contains("ai.operation.name", telemetryItem.Tags.Keys);
- Assert.Contains("ai.location.ip", telemetryItem.Tags.Keys);
- }
-
Assert.Equal(expectedTagsCount, telemetryItem.Tags.Count);
Assert.Equal(expectedTraceId, telemetryItem.Tags["ai.operation.id"]);
Assert.Equal(expectedAuthUserId, telemetryItem.Tags["ai.user.authUserId"]);
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RemoteDependencyDataNewTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RemoteDependencyDataNewTests.cs
index 74c517e696ec..c0e6d570948d 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RemoteDependencyDataNewTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RemoteDependencyDataNewTests.cs
@@ -121,5 +121,38 @@ public void HttpDependencyNameIsActivityDisplayNameByDefault()
Assert.Equal(activity.DisplayName, remoteDependencyDataName);
}
+
+ [Fact]
+ public void ValidateMessagingRemoteDependencyData()
+ {
+ using var tracerProvider = Sdk.CreateTracerProviderBuilder().AddSource(nameof(ValidateMessagingRemoteDependencyData)).Build();
+ using var activitySource = new ActivitySource(nameof(ValidateMessagingRemoteDependencyData));
+ using var activity = activitySource.StartActivity(
+ ActivityName,
+ ActivityKind.Producer,
+ parentContext: new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded),
+ startTime: DateTime.UtcNow);
+ Assert.NotNull(activity);
+ activity.Stop();
+
+ activity.SetStatus(Status.Ok);
+ activity.SetTag(SemanticConventions.AttributeMessagingSystem, "servicebus");
+ activity.SetTag(SemanticConventions.AttributeServerAddress, "my.servicebus.windows.net");
+ activity.SetTag(SemanticConventions.AttributeMessagingDestinationName, "queueName");
+
+ var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
+
+ var remoteDependencyData = new RemoteDependencyData(2, activity, ref activityTagsProcessor);
+
+ Assert.Equal("RemoteDependencyDataNewActivity", remoteDependencyData.Name);
+ Assert.Equal(activity.Context.SpanId.ToHexString(), remoteDependencyData.Id);
+ Assert.Equal("my.servicebus.windows.net/queueName", remoteDependencyData.Data);
+ Assert.Null(remoteDependencyData.ResultCode);
+ Assert.Equal(activity.Duration.ToString("c", CultureInfo.InvariantCulture), remoteDependencyData.Duration);
+ Assert.Equal("my.servicebus.windows.net/queueName", remoteDependencyData.Target);
+ Assert.Equal(activity.GetStatus() != Status.Error, remoteDependencyData.Success);
+ Assert.True(remoteDependencyData.Properties.Count == 0);
+ Assert.True(remoteDependencyData.Measurements.Count == 0);
+ }
}
}
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RequestDataNewTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RequestDataNewTests.cs
index c3f351a793e0..b971bbf10900 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RequestDataNewTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RequestDataNewTests.cs
@@ -39,6 +39,7 @@ public void ValidateHttpRequestData()
activity.SetTag(SemanticConventions.AttributeServerAddress, "www.foo.bar");
activity.SetTag(SemanticConventions.AttributeUrlPath, "/search");
activity.SetTag(SemanticConventions.AttributeHttpResponseStatusCode, null);
+ activity.SetTag("foo", "bar");
var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
@@ -51,7 +52,8 @@ public void ValidateHttpRequestData()
Assert.Equal(activity.Duration.ToString("c", CultureInfo.InvariantCulture), requestData.Duration);
Assert.False(requestData.Success);
Assert.Null(requestData.Source);
- Assert.True(requestData.Properties.Count == 0);
+ Assert.True(requestData.Properties.Count == 1);
+ Assert.Equal("bar", requestData.Properties["foo"]);
Assert.True(requestData.Measurements.Count == 0);
}
@@ -82,11 +84,15 @@ public void ValidateHttpRequestDataResponseCode(string httpStatusCode)
}
[Theory]
- [InlineData("200", true)]
- [InlineData("400", false)]
- [InlineData("500", false)]
- [InlineData("0", false)]
- public void ValidateHttpRequestSuccess(string httpStatusCode, bool isSuccess)
+ [InlineData("200", OperationType.Http, true)]
+ [InlineData("400", OperationType.Http, false)]
+ [InlineData("500", OperationType.Http, false)]
+ [InlineData("0", OperationType.Http, false)]
+ [InlineData(null, OperationType.Http, true)]
+ [InlineData("", OperationType.Http, true)]
+ [InlineData("someStatusCode", OperationType.Unknown, false)] // Activity status is set to error in the test code for validation.
+ [InlineData("someStatusCode", OperationType.Messaging, true)]
+ internal void ValidateHttpRequestSuccess(string httpStatusCode, OperationType operationType, bool isSuccess)
{
using var tracerProvider = Sdk.CreateTracerProviderBuilder().AddSource(nameof(ValidateHttpRequestSuccess)).Build();
using var activitySource = new ActivitySource(nameof(ValidateHttpRequestSuccess));
@@ -98,16 +104,12 @@ public void ValidateHttpRequestSuccess(string httpStatusCode, bool isSuccess)
Assert.NotNull(activity);
activity.Stop();
- var httpResponseCode = httpStatusCode ?? "0";
- activity.SetTag(SemanticConventions.AttributeHttpRequestMethod, "GET");
- activity.SetTag(SemanticConventions.AttributeHttpResponseStatusCode, httpStatusCode);
-
- var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
-
- var requestData = new RequestData(2, activity, ref activityTagsProcessor);
+ if (operationType == OperationType.Unknown)
+ {
+ activity.SetStatus(ActivityStatusCode.Error);
+ }
- Assert.Equal(httpResponseCode, requestData.ResponseCode);
- Assert.Equal(isSuccess, requestData.Success);
+ Assert.Equal(isSuccess, RequestData.IsSuccess(activity, httpStatusCode, operationType));
}
[Fact]
@@ -220,6 +222,41 @@ public void RequestDataTimeSinceEnqueuedInvalidEmqueuedTime()
Assert.False(requestData.Measurements.TryGetValue("timeSinceEnqueued", out var timeInQueue));
}
+ [Fact]
+ public void ValidateMessagingRequestData()
+ {
+ using var tracerProvider = Sdk.CreateTracerProviderBuilder().AddSource(nameof(ValidateMessagingRequestData)).Build();
+ using var activitySource = new ActivitySource(nameof(ValidateMessagingRequestData));
+ using var activity = activitySource.StartActivity(
+ ActivityName,
+ ActivityKind.Consumer,
+ parentContext: new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded),
+ startTime: DateTime.UtcNow);
+ Assert.NotNull(activity);
+ activity.Stop();
+
+ activity.SetStatus(Status.Ok);
+ activity.SetTag(SemanticConventions.AttributeMessagingSystem, "servicebus");
+ activity.SetTag(SemanticConventions.AttributeServerAddress, "my.servicebus.windows.net");
+ activity.SetTag(SemanticConventions.AttributeMessagingDestinationName, "queueName");
+ activity.SetTag("foo", "bar");
+
+ var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
+
+ var requestData = new RequestData(2, activity, ref activityTagsProcessor);
+
+ Assert.Equal("RequestDataNewActivity", requestData.Name);
+ Assert.Equal(activity.Context.SpanId.ToHexString(), requestData.Id);
+ Assert.Equal("my.servicebus.windows.net/queueName", requestData.Url);
+ Assert.Equal("0", requestData.ResponseCode);
+ Assert.Equal(activity.Duration.ToString("c", CultureInfo.InvariantCulture), requestData.Duration);
+ Assert.True(requestData.Success);
+ Assert.Equal("my.servicebus.windows.net/queueName", requestData.Source);
+ Assert.True(requestData.Properties.Count == 1);
+ Assert.Equal("bar", requestData.Properties["foo"]);
+ Assert.True(requestData.Measurements.Count == 0);
+ }
+
private ActivityLink AddActivityLink(long enqueuedTime)
{
ActivityTagsCollection tags = new ActivityTagsCollection
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RequestDataTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RequestDataTests.cs
index 01206f960608..b600e21b1d2b 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RequestDataTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/RequestDataTests.cs
@@ -50,7 +50,8 @@ public void ValidateHttpRequestData()
activity.SetTag(SemanticConventions.AttributeHttpMethod, "GET");
activity.SetTag(SemanticConventions.AttributeHttpRoute, "/search");
activity.SetTag(SemanticConventions.AttributeHttpUrl, httpUrl); // only adding test via http.url. all possible combinations are covered in AzMonListExtensionsTests.
- activity.SetTag(SemanticConventions.AttributeHttpStatusCode, null);
+ activity.SetTag(SemanticConventions.AttributeHttpStatusCode, "200");
+ activity.SetTag("foo", "bar");
var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
@@ -59,11 +60,12 @@ public void ValidateHttpRequestData()
Assert.Equal("GET /search", requestData.Name);
Assert.Equal(activity.Context.SpanId.ToHexString(), requestData.Id);
Assert.Equal(httpUrl, requestData.Url);
- Assert.Equal("0", requestData.ResponseCode);
+ Assert.Equal("200", requestData.ResponseCode);
Assert.Equal(activity.Duration.ToString("c", CultureInfo.InvariantCulture), requestData.Duration);
- Assert.False(requestData.Success);
+ Assert.True(requestData.Success);
Assert.Null(requestData.Source);
- Assert.True(requestData.Properties.Count == 0);
+ Assert.True(requestData.Properties.Count == 1);
+ Assert.Equal("bar", requestData.Properties["foo"]);
Assert.True(requestData.Measurements.Count == 0);
}
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 7ec1993fe449..db041415747a 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
@@ -4,11 +4,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Linq;
using System.Net;
-using Xunit;
+using Azure.Monitor.OpenTelemetry.Exporter.Internals;
using Azure.Monitor.OpenTelemetry.Exporter.Models;
+using OpenTelemetry;
using OpenTelemetry.Resources;
-using Azure.Monitor.OpenTelemetry.Exporter.Internals;
+using Xunit;
namespace Azure.Monitor.OpenTelemetry.Exporter.Tests
{
@@ -141,9 +143,10 @@ public void HttpMethodAndHttpRouteIsUsedForHttpRequestOperationName(string? rout
}
var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
- var telemetryItem = new TelemetryItem(activity, ref activityTagsProcessor, null, string.Empty);
+ var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(new Batch(new Activity[] { activity }, 1), null, "instrumentationKey");
+ var telemetryItem = telemetryItems.FirstOrDefault();
- Assert.Equal(expectedOperationName, telemetryItem.Tags[ContextTagKeys.AiOperationName.ToString()]);
+ Assert.Equal(expectedOperationName, telemetryItem?.Tags[ContextTagKeys.AiOperationName.ToString()]);
}
[Fact]
@@ -163,9 +166,10 @@ public void HttpMethodAndHttpUrlPathIsUsedForHttpRequestOperationName()
activity.SetTag(SemanticConventions.AttributeHttpUrl, "https://www.foo.bar/path?id=1");
var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
- var telemetryItem = new TelemetryItem(activity, ref activityTagsProcessor, null, string.Empty);
+ var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(new Batch(new Activity[] { activity }, 1), null, "instrumentationKey");
+ var telemetryItem = telemetryItems.FirstOrDefault();
- Assert.Equal("GET /path", telemetryItem.Tags[ContextTagKeys.AiOperationName.ToString()]);
+ Assert.Equal("GET /path", telemetryItem?.Tags[ContextTagKeys.AiOperationName.ToString()]);
}
[Fact]
@@ -180,11 +184,13 @@ public void ActivityNameIsUsedByDefaultForRequestOperationName()
Assert.NotNull(activity);
activity.DisplayName = "displayname";
+ activity.SetTag(SemanticConventions.AttributeHttpRequestMethod, "GET");
var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
- var telemetryItem = new TelemetryItem(activity, ref activityTagsProcessor, null, string.Empty);
+ var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(new Batch(new Activity[] { activity }, 1), null, "instrumentationKey");
+ var telemetryItem = telemetryItems.FirstOrDefault();
- Assert.Equal("displayname", telemetryItem.Tags[ContextTagKeys.AiOperationName.ToString()]);
+ Assert.Equal("displayname", telemetryItem?.Tags[ContextTagKeys.AiOperationName.ToString()]);
}
[Fact]
@@ -199,11 +205,13 @@ public void AiLocationIpIsSetAsHttpClientIpForHttpServerSpans()
Assert.NotNull(activity);
activity.SetTag(SemanticConventions.AttributeHttpClientIP, "127.0.0.1");
+ activity.SetTag(SemanticConventions.AttributeHttpRequestMethod, "GET");
var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
- var telemetryItem = new TelemetryItem(activity, ref activityTagsProcessor, null, string.Empty);
+ var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(new Batch(new Activity[] { activity }, 1), null, "instrumentationKey");
+ var telemetryItem = telemetryItems.FirstOrDefault();
- Assert.Equal("127.0.0.1", telemetryItem.Tags[ContextTagKeys.AiLocationIp.ToString()]);
+ Assert.Equal("127.0.0.1", telemetryItem?.Tags[ContextTagKeys.AiLocationIp.ToString()]);
}
[Fact]
@@ -218,11 +226,13 @@ public void AiLocationIpIsSetAsNetPeerIpForServerSpans()
Assert.NotNull(activity);
activity.SetTag(SemanticConventions.AttributeNetPeerIp, "127.0.0.1");
+ activity.SetTag(SemanticConventions.AttributeHttpRequestMethod, "GET");
var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
- var telemetryItem = new TelemetryItem(activity, ref activityTagsProcessor, null, string.Empty);
+ var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(new Batch(new Activity[] { activity }, 1), null, "instrumentationKey");
+ var telemetryItem = telemetryItems.FirstOrDefault();
- Assert.Equal("127.0.0.1", telemetryItem.Tags[ContextTagKeys.AiLocationIp.ToString()]);
+ Assert.Equal("127.0.0.1", telemetryItem?.Tags[ContextTagKeys.AiLocationIp.ToString()]);
}
[Fact]
@@ -240,9 +250,10 @@ public void AiUserAgentIsSetAsHttpUserAgent()
activity.SetTag(SemanticConventions.AttributeHttpUserAgent, userAgent);
var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
- var telemetryItem = new TelemetryItem(activity, ref activityTagsProcessor, null, string.Empty);
+ var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(new Batch(new Activity[] { activity }, 1), null, "instrumentationKey");
+ var telemetryItem = telemetryItems.FirstOrDefault();
- Assert.Equal(userAgent, telemetryItem.Tags["ai.user.userAgent"]);
+ Assert.Equal(userAgent, telemetryItem?.Tags["ai.user.userAgent"]);
}
[Fact]
@@ -254,12 +265,14 @@ public void AiLocationIpIsNullByDefault()
ActivityKind.Server,
null,
startTime: DateTime.UtcNow);
+ activity?.SetTag(SemanticConventions.AttributeHttpRequestMethod, "GET");
Assert.NotNull(activity);
var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
- var telemetryItem = new TelemetryItem(activity, ref activityTagsProcessor, null, string.Empty);
+ var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(new Batch(new Activity[] { activity }, 1), null, "instrumentationKey");
+ var telemetryItem = telemetryItems.FirstOrDefault();
- Assert.Null(telemetryItem.Tags[ContextTagKeys.AiLocationIp.ToString()]);
+ Assert.Null(telemetryItem?.Tags[ContextTagKeys.AiLocationIp.ToString()]);
}
[Fact]
@@ -319,10 +332,8 @@ public void RoleInstanceIsNotOverwrittenIfSetViaServiceInstanceId()
Assert.Equal("serviceinstance", telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()]);
}
- [Theory]
- [InlineData("GET")]
- [InlineData(null)]
- public void RequestNameMatchesOperationName(string? httpMethod)
+ [Fact]
+ public void RequestNameMatchesOperationName()
{
using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
using var activity = activitySource.StartActivity(
@@ -333,15 +344,15 @@ public void RequestNameMatchesOperationName(string? httpMethod)
Assert.NotNull(activity);
activity.DisplayName = "displayname";
- if (httpMethod != null)
- {
- activity.SetTag(SemanticConventions.AttributeHttpMethod, httpMethod);
- }
+
+ activity.SetTag(SemanticConventions.AttributeHttpMethod, "GET");
+
var activityTagsProcessor = TraceHelper.EnumerateActivityTags(activity);
- var telemetryItem = new TelemetryItem(activity, ref activityTagsProcessor, null, string.Empty);
+ var telemetryItems = TraceHelper.OtelToAzureMonitorTrace(new Batch(new Activity[] { activity }, 1), null, "instrumentationKey");
+ var telemetryItem = telemetryItems.FirstOrDefault();
var requestData = new RequestData(2, activity, ref activityTagsProcessor);
- Assert.Equal(requestData.Name, telemetryItem.Tags[ContextTagKeys.AiOperationName.ToString()]);
+ Assert.Equal(requestData.Name, telemetryItem?.Tags[ContextTagKeys.AiOperationName.ToString()]);
}
///
@@ -361,9 +372,12 @@ private static Resource CreateTestResource(string? serviceName = null, string? s
{
var testAttributes = new Dictionary();
- if (serviceName != null) testAttributes.Add("service.name", serviceName);
- if (serviceNamespace != null) testAttributes.Add("service.namespace", serviceNamespace);
- if (serviceInstance != null) testAttributes.Add("service.instance.id", serviceInstance);
+ if (serviceName != null)
+ testAttributes.Add("service.name", serviceName);
+ if (serviceNamespace != null)
+ testAttributes.Add("service.namespace", serviceNamespace);
+ if (serviceInstance != null)
+ testAttributes.Add("service.instance.id", serviceInstance);
return ResourceBuilder.CreateDefault().AddAttributes(testAttributes).Build();
}
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TraceHelperNewTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TraceHelperNewTests.cs
index 32728d3d6c22..59dd7c1e0900 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TraceHelperNewTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/TraceHelperNewTests.cs
@@ -90,11 +90,11 @@ public void GetNewOperationName_WithNullHttpMethod_ReturnsActivityDisplayName(st
}
[Fact]
- public void GetNewOperationName_WithNullHttpRoute_ReturnsActivityDisplayName()
+ public void GetNewOperationName_WithNullHttpRoute_ReturnsUrlWithVerb()
{
// Arrange
- using var tracerProvider = Sdk.CreateTracerProviderBuilder().AddSource(nameof(GetNewOperationName_WithNullHttpRoute_ReturnsActivityDisplayName)).Build();
- using var activitySource = new ActivitySource(nameof(GetNewOperationName_WithNullHttpRoute_ReturnsActivityDisplayName));
+ using var tracerProvider = Sdk.CreateTracerProviderBuilder().AddSource(nameof(GetNewOperationName_WithNullHttpRoute_ReturnsUrlWithVerb)).Build();
+ using var activitySource = new ActivitySource(nameof(GetNewOperationName_WithNullHttpRoute_ReturnsUrlWithVerb));
using var activity = activitySource.StartActivity(
ActivityName,
ActivityKind.Server);
@@ -102,12 +102,14 @@ public void GetNewOperationName_WithNullHttpRoute_ReturnsActivityDisplayName()
var tagObjects = AzMonList.Initialize();
AzMonList.Add(ref tagObjects, new KeyValuePair(SemanticConventions.AttributeHttpRequestMethod, "POST"));
+ AzMonList.Add(ref tagObjects, new KeyValuePair(SemanticConventions.AttributeServerAddress, "example.com"));
+ AzMonList.Add(ref tagObjects, new KeyValuePair(SemanticConventions.AttributeUrlScheme, "http"));
// Act
var result = TraceHelper.GetNewSchemaOperationName(activity!, url: null, ref tagObjects);
// Assert
- Assert.Equal(ActivityName, result);
+ Assert.Equal("POST http://example.com", result);
}
[Fact]
@@ -132,6 +134,54 @@ public void GetNewOperationName_WithNullUrl_ReturnsFormattedStringFromMappedTags
Assert.Equal("GET /api/test", result);
}
+ [Fact]
+ public void GetHttpOperationNameAndUrl_V1()
+ {
+ // Arrange
+ using var tracerProvider = Sdk.CreateTracerProviderBuilder().AddSource(nameof(GetNewOperationName_WithNullUrl_ReturnsFormattedStringFromMappedTags)).Build();
+ using var activitySource = new ActivitySource(nameof(GetNewOperationName_WithNullUrl_ReturnsFormattedStringFromMappedTags));
+ using var activity = activitySource.StartActivity(
+ ActivityName,
+ ActivityKind.Server);
+ activity?.Stop();
+
+ var httpMappedTags = AzMonList.Initialize();
+ AzMonList.Add(ref httpMappedTags, new KeyValuePair(SemanticConventions.AttributeHttpUrl, "https://example.com"));
+ AzMonList.Add(ref httpMappedTags, new KeyValuePair(SemanticConventions.AttributeHttpMethod, "GET"));
+
+ // Act
+ var (requestUrl, operationName) = TraceHelper.GetHttpOperationNameAndUrl(activity!.DisplayName, OperationType.Http, ref httpMappedTags);
+
+ // Assert
+ Assert.Equal("https://example.com", requestUrl);
+ Assert.Equal("GET /", operationName);
+ }
+
+ [Fact]
+ public void GetHttpOperationNameAndUrl_V2()
+ {
+ // Arrange
+ using var tracerProvider = Sdk.CreateTracerProviderBuilder().AddSource(nameof(GetNewOperationName_WithNullUrl_ReturnsFormattedStringFromMappedTags)).Build();
+ using var activitySource = new ActivitySource(nameof(GetNewOperationName_WithNullUrl_ReturnsFormattedStringFromMappedTags));
+ using var activity = activitySource.StartActivity(
+ ActivityName,
+ ActivityKind.Server);
+ activity?.Stop();
+
+ var httpMappedTags = AzMonList.Initialize();
+ AzMonList.Add(ref httpMappedTags, new KeyValuePair(SemanticConventions.AttributeUrlScheme, "http"));
+ AzMonList.Add(ref httpMappedTags, new KeyValuePair(SemanticConventions.AttributeServerAddress, "example.com"));
+ AzMonList.Add(ref httpMappedTags, new KeyValuePair(SemanticConventions.AttributeHttpRequestMethod, "GET"));
+ AzMonList.Add(ref httpMappedTags, new KeyValuePair(SemanticConventions.AttributeUrlPath, "/search"));
+
+ // Act
+ var (requestUrl, operationName) = TraceHelper.GetHttpOperationNameAndUrl(activity!.DisplayName, OperationType.V2, ref httpMappedTags);
+
+ // Assert
+ Assert.Equal("http://example.com/search", requestUrl);
+ Assert.Equal("GET /search", operationName);
+ }
+
private string? GetExpectedMSlinks(IEnumerable links)
{
if (links != null && links.Any())