Skip to content

Commit 0a0ba46

Browse files
[AzureMonitorExporter] Add support new HTTP semantics - Dependency Telemetry (Azure#37464)
* Add support new HTTP semantics - Dependency Telemetry * Merge two conditions. * PR feedback
1 parent a919c48 commit 0a0ba46

File tree

15 files changed

+452
-166
lines changed

15 files changed

+452
-166
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Diagnostics;
5+
using System.Globalization;
6+
using Azure.Core;
7+
using Azure.Monitor.OpenTelemetry.Exporter.Internals;
8+
9+
namespace Azure.Monitor.OpenTelemetry.Exporter.Models;
10+
11+
internal partial class RemoteDependencyData
12+
{
13+
public RemoteDependencyData(int version, Activity activity, ref ActivityTagsProcessor activityTagsProcessor, string schemaVersion) : base(version)
14+
{
15+
Properties = new ChangeTrackingDictionary<string, string>();
16+
Measurements = new ChangeTrackingDictionary<string, double>();
17+
18+
string? httpUrl = null;
19+
string dependencyName;
20+
21+
if (activityTagsProcessor.activityType.HasFlag(OperationType.Http))
22+
{
23+
httpUrl = AzMonList.GetTagValue(ref activityTagsProcessor.MappedTags, SemanticConventions.AttributeUrlFull)?.ToString();
24+
dependencyName = activityTagsProcessor.MappedTags.GetNewSchemaHttpDependencyName(httpUrl) ?? activity.DisplayName;
25+
Data = httpUrl.Truncate(SchemaConstants.RemoteDependencyData_Data_MaxLength);
26+
Target = activityTagsProcessor.MappedTags.GetNewSchemaHttpDependencyTarget().Truncate(SchemaConstants.RemoteDependencyData_Target_MaxLength);
27+
Type = "Http";
28+
ResultCode = AzMonList.GetTagValue(ref activityTagsProcessor.MappedTags, SemanticConventions.AttributeHttpResponseStatusCode)
29+
?.ToString().Truncate(SchemaConstants.RemoteDependencyData_ResultCode_MaxLength)
30+
?? "0";
31+
}
32+
else
33+
{
34+
dependencyName = activity.DisplayName;
35+
}
36+
37+
Name = dependencyName.Truncate(SchemaConstants.RemoteDependencyData_Name_MaxLength);
38+
Id = activity.Context.SpanId.ToHexString();
39+
Duration = activity.Duration < SchemaConstants.RemoteDependencyData_Duration_LessThanDays
40+
? activity.Duration.ToString("c", CultureInfo.InvariantCulture)
41+
: SchemaConstants.Duration_MaxValue;
42+
Success = activity.Status != ActivityStatusCode.Error;
43+
44+
// TODO: Other operation types.
45+
46+
if (activityTagsProcessor.AzureNamespace != null)
47+
{
48+
if (activity.Kind == ActivityKind.Internal)
49+
{
50+
Type = $"InProc | {activityTagsProcessor.AzureNamespace}";
51+
}
52+
else if (activity.Kind == ActivityKind.Producer)
53+
{
54+
Type = $"Queue Message | {activityTagsProcessor.AzureNamespace}";
55+
}
56+
else
57+
{
58+
// The Azure SDK sets az.namespace with its resource provider information.
59+
// When ActivityKind is not internal and az.namespace is present, set the value of Type to az.namespace.
60+
Type = activityTagsProcessor.AzureNamespace ?? Type;
61+
}
62+
}
63+
else if (activity.Kind == ActivityKind.Internal)
64+
{
65+
Type = "InProc";
66+
}
67+
68+
TraceHelper.AddActivityLinksToProperties(activity, ref activityTagsProcessor.UnMappedTags);
69+
TraceHelper.AddPropertiesToTelemetry(Properties, ref activityTagsProcessor.UnMappedTags);
70+
}
71+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Diagnostics;
5+
using System.Globalization;
6+
using Azure.Core;
7+
using Azure.Monitor.OpenTelemetry.Exporter.Internals;
8+
9+
namespace Azure.Monitor.OpenTelemetry.Exporter.Models;
10+
11+
internal partial class RequestData
12+
{
13+
public RequestData(int version, Activity activity, ref ActivityTagsProcessor activityTagsProcessor, string schemaVersion) : base(version)
14+
{
15+
string? url = null;
16+
17+
if (activityTagsProcessor.activityType.HasFlag(OperationType.Http))
18+
{
19+
url = activityTagsProcessor.MappedTags.GetNewSchemaRequestUrl();
20+
}
21+
22+
Id = activity.Context.SpanId.ToHexString();
23+
Name = TraceHelper.GetNewSchemaOperationName(activity, url, ref activityTagsProcessor.MappedTags).Truncate(SchemaConstants.RequestData_Name_MaxLength);
24+
Duration = activity.Duration < SchemaConstants.RequestData_Duration_LessThanDays
25+
? activity.Duration.ToString("c", CultureInfo.InvariantCulture)
26+
: SchemaConstants.Duration_MaxValue;
27+
ResponseCode = AzMonList.GetTagValue(ref activityTagsProcessor.MappedTags, SemanticConventions.AttributeHttpResponseStatusCode)
28+
?.ToString().Truncate(SchemaConstants.RequestData_ResponseCode_MaxLength)
29+
?? "0";
30+
31+
Success = IsSuccess(activity, ResponseCode, activityTagsProcessor.activityType);
32+
33+
Url = url.Truncate(SchemaConstants.RequestData_Url_MaxLength);
34+
Properties = new ChangeTrackingDictionary<string, string>();
35+
Measurements = new ChangeTrackingDictionary<string, double>();
36+
37+
if (activity.Kind == ActivityKind.Consumer)
38+
{
39+
TraceHelper.AddEnqueuedTimeToMeasurementsAndLinksToProperties(activity, Measurements, ref activityTagsProcessor.UnMappedTags);
40+
}
41+
else
42+
{
43+
TraceHelper.AddActivityLinksToProperties(activity, ref activityTagsProcessor.UnMappedTags);
44+
}
45+
46+
TraceHelper.AddPropertiesToTelemetry(Properties, ref activityTagsProcessor.UnMappedTags);
47+
}
48+
}

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/RequestDataV2.cs

Lines changed: 0 additions & 49 deletions
This file was deleted.

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Customizations/Models/TelemetryItem.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public TelemetryItem(Activity activity, ref ActivityTagsProcessor activityTagsPr
3838
if (activity.Kind == ActivityKind.Server)
3939
{
4040
Tags[ContextTagKeys.AiOperationName.ToString()] = activityTagsProcessor.activityType.HasFlag(OperationType.V2)
41-
? TraceHelper.GetV2OperationName(activity, null, ref activityTagsProcessor.MappedTags)
41+
? TraceHelper.GetNewSchemaOperationName(activity, null, ref activityTagsProcessor.MappedTags)
4242
: TraceHelper.GetOperationName(activity, ref activityTagsProcessor.MappedTags);
4343
Tags[ContextTagKeys.AiLocationIp.ToString()] = TraceHelper.GetLocationIp(ref activityTagsProcessor.MappedTags);
4444
}

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/AzMonListExtensionsV2.cs

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
7+
namespace Azure.Monitor.OpenTelemetry.Exporter.Internals;
8+
9+
internal static class AzMonNewListExtensions
10+
{
11+
///<summary>
12+
/// Gets http request url from activity tag objects.
13+
///</summary>
14+
internal static string? GetNewSchemaRequestUrl(this AzMonList tagObjects)
15+
{
16+
try
17+
{
18+
var serverAddress = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeServerAddress)?.ToString();
19+
if (serverAddress != null)
20+
{
21+
UriBuilder uriBuilder = new()
22+
{
23+
Scheme = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeUrlScheme)?.ToString(),
24+
Host = serverAddress,
25+
Path = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeUrlPath)?.ToString(),
26+
Query = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeUrlQuery)?.ToString()
27+
};
28+
29+
if (int.TryParse(AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeServerPort)?.ToString(), out int port))
30+
{
31+
uriBuilder.Port = port;
32+
}
33+
34+
return uriBuilder.Uri.AbsoluteUri;
35+
}
36+
}
37+
catch
38+
{
39+
// If URI building fails, there is no need to throw an exception. Instead, we can simply return null.
40+
}
41+
42+
return null;
43+
}
44+
45+
///<summary>
46+
/// Gets Http dependency target from activity tag objects.
47+
///</summary>
48+
internal static string? GetNewSchemaHttpDependencyTarget(this AzMonList tagObjects)
49+
{
50+
var tagValues = AzMonList.GetTagValues(ref tagObjects, SemanticConventions.AttributeServerAddress, SemanticConventions.AttributeServerPort);
51+
var serverAddress = tagValues[0]?.ToString(); // tagValues[0] => SemanticConventions.AttributeServerAddress.
52+
var serverPort = tagValues[1]?.ToString(); // tagValues[1] => SemanticConventions.AttributeServerPort.
53+
54+
if (string.IsNullOrWhiteSpace(serverAddress))
55+
{
56+
return null;
57+
}
58+
59+
if (int.TryParse(serverPort, out int port) && !IsDefaultPort(port))
60+
{
61+
return $"{serverAddress}:{serverPort}";
62+
}
63+
64+
return serverAddress;
65+
}
66+
67+
internal static string? GetNewSchemaHttpDependencyName(this AzMonList tagObjects, string? httpUrl)
68+
{
69+
if (string.IsNullOrWhiteSpace(httpUrl))
70+
{
71+
return null;
72+
}
73+
74+
var httpMethod = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpRequestMethod)?.ToString();
75+
if (!string.IsNullOrWhiteSpace(httpMethod))
76+
{
77+
if (Uri.TryCreate(httpUrl!.ToString(), UriKind.Absolute, out var uri) && uri.IsAbsoluteUri)
78+
{
79+
return $"{httpMethod} {uri.AbsolutePath}";
80+
}
81+
}
82+
83+
return null;
84+
}
85+
86+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
87+
private static bool IsDefaultPort(int port)
88+
{
89+
return port == 0 || port == 80 || port == 443;
90+
}
91+
}

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/OperationType.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ internal enum OperationType
1616
Http = 16,
1717
Messaging = 32,
1818
Rpc = 64,
19+
// TODO: https://github.com/Azure/azure-sdk-for-net/pull/37357/files#r1253383825
20+
// Check if V2 could be moved outside of this Enum.
1921
V2 = 128
2022
}
2123
}

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/SchemaConstants.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,7 @@ internal static class SchemaConstants
115115
public const int TelemetryEnvelope_Name_MaxLength = 1024;
116116
public const int TelemetryEnvelope_Time_MaxLength = 64;
117117
public const int TelemetryEnvelope_InstrumentationKey_MaxLength = 40;
118+
119+
public const string DefaultSchemaVersion = "1.21.0";
118120
}
119121
}

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/TraceHelper.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ internal static List<TelemetryItem> OtelToAzureMonitorTrace(Batch<Activity> batc
4949
{
5050
BaseType = "RequestData",
5151
BaseData = activityTagsProcessor.activityType.HasFlag(OperationType.V2)
52-
? new RequestData(Version, activity, ref activityTagsProcessor, schemaVersion: "V2")
52+
? new RequestData(Version, activity, ref activityTagsProcessor, schemaVersion: SchemaConstants.DefaultSchemaVersion)
5353
: new RequestData(Version, activity, ref activityTagsProcessor)
5454
};
5555
break;
@@ -173,7 +173,7 @@ internal static string GetOperationName(Activity activity, ref AzMonList MappedT
173173
return activity.DisplayName;
174174
}
175175

176-
internal static string GetV2OperationName(Activity activity, string? url, ref AzMonList MappedTags)
176+
internal static string GetNewSchemaOperationName(Activity activity, string? url, ref AzMonList MappedTags)
177177
{
178178
var httpMethod = AzMonList.GetTagValue(ref MappedTags, SemanticConventions.AttributeHttpRequestMethod)?.ToString();
179179
if (!string.IsNullOrWhiteSpace(httpMethod))
@@ -187,7 +187,7 @@ internal static string GetV2OperationName(Activity activity, string? url, ref A
187187
return $"{httpMethod} {httpRoute}";
188188
}
189189

190-
url ??= MappedTags.GetV2RequestUrl();
190+
url ??= MappedTags.GetNewSchemaRequestUrl();
191191
if (url != null)
192192
{
193193
return $"{httpMethod} {url}";

sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/AzMonListExtensionsV2Tests.cs

Lines changed: 0 additions & 38 deletions
This file was deleted.

0 commit comments

Comments
 (0)