Skip to content

Commit ec71d1d

Browse files
Azure Monitor Exporter - Refactor AzureMonitorConvertor (Azure#17056)
* Refactor AzureMonitorConvertor * PR feedback
1 parent 07edd0b commit ec71d1d

File tree

8 files changed

+384
-316
lines changed

8 files changed

+384
-316
lines changed
Lines changed: 13 additions & 271 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
using System;
54
using System.Collections.Generic;
65
using System.Diagnostics;
7-
using System.Globalization;
8-
using System.Runtime.CompilerServices;
9-
using System.Text;
10-
using Microsoft.OpenTelemetry.Exporter.AzureMonitor.Models;
11-
126
using OpenTelemetry;
13-
using OpenTelemetry.Resources;
14-
using OpenTelemetry.Trace;
7+
using Microsoft.OpenTelemetry.Exporter.AzureMonitor.Models;
158

169
namespace Microsoft.OpenTelemetry.Exporter.AzureMonitor
1710
{
@@ -29,284 +22,33 @@ internal static class AzureMonitorConverter
2922
[TelemetryType.Event] = "EventData",
3023
};
3124

32-
private static readonly IReadOnlyDictionary<TelemetryType, string> PartA_Name_Mapping = new Dictionary<TelemetryType, string>
33-
{
34-
[TelemetryType.Request] = "Request",
35-
[TelemetryType.Dependency] = "RemoteDependency",
36-
[TelemetryType.Message] = "Message",
37-
[TelemetryType.Event] = "Event",
38-
};
39-
40-
private static readonly IReadOnlyDictionary<string, PartBType> Part_B_Mapping = new Dictionary<string, PartBType>()
41-
{
42-
[SemanticConventions.AttributeDbStatement] = PartBType.Db,
43-
[SemanticConventions.AttributeDbSystem] = PartBType.Db,
44-
45-
[SemanticConventions.AttributeHttpMethod] = PartBType.Http,
46-
[SemanticConventions.AttributeHttpUrl] = PartBType.Http,
47-
[SemanticConventions.AttributeHttpStatusCode] = PartBType.Http,
48-
[SemanticConventions.AttributeHttpScheme] = PartBType.Http,
49-
[SemanticConventions.AttributeHttpHost] = PartBType.Http,
50-
[SemanticConventions.AttributeHttpHostPort] = PartBType.Http,
51-
[SemanticConventions.AttributeHttpTarget] = PartBType.Http,
52-
53-
[SemanticConventions.AttributeNetPeerName] = PartBType.Common,
54-
[SemanticConventions.AttributeNetPeerIp] = PartBType.Common,
55-
[SemanticConventions.AttributeNetPeerPort] = PartBType.Common,
56-
[SemanticConventions.AttributeNetTransport] = PartBType.Common,
57-
[SemanticConventions.AttributeNetHostIp] = PartBType.Common,
58-
[SemanticConventions.AttributeNetHostPort] = PartBType.Common,
59-
[SemanticConventions.AttributeNetHostName] = PartBType.Common,
60-
[SemanticConventions.AttributeComponent] = PartBType.Common,
61-
62-
[SemanticConventions.AttributeRpcService] = PartBType.Rpc,
63-
[SemanticConventions.AttributeRpcSystem] = PartBType.Rpc,
64-
[SemanticConventions.AttributeRpcStatus] = PartBType.Rpc,
65-
66-
[SemanticConventions.AttributeFaasTrigger] = PartBType.FaaS,
67-
[SemanticConventions.AttributeFaasExecution] = PartBType.FaaS,
68-
[SemanticConventions.AttributeFaasColdStart] = PartBType.FaaS,
69-
[SemanticConventions.AttributeFaasDocumentCollection] = PartBType.FaaS,
70-
[SemanticConventions.AttributeFaasDocumentOperation] = PartBType.FaaS,
71-
[SemanticConventions.AttributeFaasDocumentTime] = PartBType.FaaS,
72-
[SemanticConventions.AttributeFaasDocumentName] = PartBType.FaaS,
73-
[SemanticConventions.AttributeFaasCron] = PartBType.FaaS,
74-
[SemanticConventions.AttributeFaasTime] = PartBType.FaaS,
75-
76-
[SemanticConventions.AttributeAzureNameSpace] = PartBType.Azure,
77-
[SemanticConventions.AttributeMessageBusDestination] = PartBType.Azure,
78-
79-
[SemanticConventions.AttributeEndpointAddress] = PartBType.Messaging,
80-
[SemanticConventions.AttributeMessagingSystem] = PartBType.Messaging,
81-
[SemanticConventions.AttributeMessagingDestination] = PartBType.Messaging,
82-
[SemanticConventions.AttributeMessagingDestinationKind] = PartBType.Messaging,
83-
[SemanticConventions.AttributeMessagingTempDestination] = PartBType.Messaging,
84-
[SemanticConventions.AttributeMessagingUrl] = PartBType.Messaging
85-
};
86-
87-
internal static string RoleName { get; set; } = null;
88-
89-
internal static string RoleInstance { get; set; } = null;
90-
9125
internal static List<TelemetryItem> Convert(Batch<Activity> batchActivity, string instrumentationKey)
9226
{
9327
List<TelemetryItem> telemetryItems = new List<TelemetryItem>();
9428
TelemetryItem telemetryItem;
9529

9630
foreach (var activity in batchActivity)
9731
{
98-
telemetryItem = GeneratePartAEnvelope(activity);
99-
telemetryItem.InstrumentationKey = instrumentationKey;
100-
telemetryItem.Data = GenerateTelemetryData(activity);
101-
telemetryItems.Add(telemetryItem);
102-
}
103-
104-
return telemetryItems;
105-
}
106-
107-
internal static TelemetryItem GeneratePartAEnvelope(Activity activity)
108-
{
109-
TelemetryItem telemetryItem = new TelemetryItem(PartA_Name_Mapping[activity.GetTelemetryType()], activity.StartTimeUtc.ToString(CultureInfo.InvariantCulture));
110-
InitRoleInfo(activity);
111-
telemetryItem.Tags[ContextTagKeys.AiCloudRole.ToString()] = RoleName;
112-
telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()] = RoleInstance;
113-
telemetryItem.Tags[ContextTagKeys.AiOperationId.ToString()] = activity.TraceId.ToHexString();
114-
if (activity.Parent != null)
115-
{
116-
telemetryItem.Tags[ContextTagKeys.AiOperationParentId.ToString()] = activity.Parent.SpanId.ToHexString();
117-
}
118-
// TODO: Handle exception
119-
telemetryItem.Tags[ContextTagKeys.AiInternalSdkVersion.ToString()] = SdkVersionUtils.SdkVersion;
120-
121-
return telemetryItem;
122-
}
123-
124-
internal static void InitRoleInfo(Activity activity)
125-
{
126-
if (RoleName != null || RoleInstance != null)
127-
{
128-
return;
129-
}
130-
131-
var resource = activity.GetResource();
132-
133-
if (resource == null)
134-
{
135-
return;
136-
}
137-
138-
string serviceName = null;
139-
string serviceNamespace = null;
140-
141-
foreach (var attribute in resource.Attributes)
142-
{
143-
if (attribute.Key == Resource.ServiceNameKey && attribute.Value is string)
144-
{
145-
serviceName = attribute.Value.ToString();
146-
}
147-
else if (attribute.Key == Resource.ServiceNamespaceKey && attribute.Value is string)
148-
{
149-
serviceNamespace = attribute.Value.ToString();
150-
}
151-
else if (attribute.Key == Resource.ServiceInstanceIdKey && attribute.Value is string)
152-
{
153-
RoleInstance = attribute.Value.ToString();
154-
}
155-
}
156-
157-
if (serviceName != null && serviceNamespace != null)
158-
{
159-
RoleName = string.Concat(serviceNamespace, ".", serviceName);
160-
}
161-
else
162-
{
163-
RoleName = serviceName;
164-
}
165-
}
32+
MonitorBase telemetryData = new MonitorBase();
33+
telemetryItem = TelemetryPartA.GetTelemetryItem(activity, instrumentationKey);
16634

167-
private static MonitorBase GenerateTelemetryData(Activity activity)
168-
{
169-
var telemetryType = activity.GetTelemetryType();
170-
var monitorTags = new TagEnumerationState
171-
{
172-
PartBTags = AzMonList.Initialize(),
173-
PartCTags = AzMonList.Initialize()
174-
};
175-
176-
activity.EnumerateTags(ref monitorTags);
177-
178-
MonitorBase telemetry = new MonitorBase
179-
{
180-
BaseType = Telemetry_Base_Type_Mapping[telemetryType]
181-
};
182-
183-
if (telemetryType == TelemetryType.Request)
184-
{
185-
monitorTags.PartBTags.GenerateUrlAndAuthority(out var url, out var urlAuthority);
186-
var statusCode = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpStatusCode)?.ToString() ?? "0";
187-
var success = activity.GetStatus() != Status.Error;
188-
var request = new RequestData(2, activity.Context.SpanId.ToHexString(), activity.Duration.ToString("c", CultureInfo.InvariantCulture), success, statusCode)
189-
{
190-
Name = activity.DisplayName,
191-
Url = url,
192-
Source = urlAuthority
193-
};
194-
195-
// TODO: Handle activity.TagObjects, extract well-known tags
196-
AddPropertiesToTelemetry(request.Properties, monitorTags.PartCTags);
197-
telemetry.BaseData = request;
198-
}
199-
else if (telemetryType == TelemetryType.Dependency)
200-
{
201-
var dependency = new RemoteDependencyData(2, activity.DisplayName, activity.Duration.ToString("c", CultureInfo.InvariantCulture))
35+
switch (activity.GetTelemetryType())
20236
{
203-
Id = activity.Context.SpanId.ToHexString(),
204-
Success = activity.GetStatus() != Status.Error
205-
};
206-
207-
switch (monitorTags.activityType)
208-
{
209-
case PartBType.Http:
210-
monitorTags.PartBTags.GenerateUrlAndAuthority(out var url, out var urlAuthority);
211-
dependency.Data = url;
212-
dependency.Target = urlAuthority;
213-
dependency.Type = "Http";
214-
dependency.ResultCode = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpStatusCode)?.ToString() ?? "0";
215-
break;
216-
case PartBType.Db:
217-
var depDataAndType = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeDbStatement, SemanticConventions.AttributeDbSystem);
218-
dependency.Data = depDataAndType[0]?.ToString();
219-
dependency.Type = depDataAndType[1]?.ToString();
37+
case TelemetryType.Request:
38+
telemetryData.BaseType = Telemetry_Base_Type_Mapping[TelemetryType.Request];
39+
telemetryData.BaseData = TelemetryPartB.GetRequestData(activity);
22040
break;
221-
case PartBType.Rpc:
222-
var depInfo = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeRpcService, SemanticConventions.AttributeRpcSystem, SemanticConventions.AttributeRpcStatus);
223-
dependency.Data = depInfo[0]?.ToString();
224-
dependency.Type = depInfo[1]?.ToString();
225-
dependency.ResultCode = depInfo[2]?.ToString();
226-
break;
227-
case PartBType.Messaging:
228-
depDataAndType = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeMessagingUrl, SemanticConventions.AttributeMessagingSystem);
229-
dependency.Data = depDataAndType[0]?.ToString();
230-
dependency.Type = depDataAndType[1]?.ToString();
41+
case TelemetryType.Dependency:
42+
telemetryData.BaseType = Telemetry_Base_Type_Mapping[TelemetryType.Dependency];
43+
telemetryData.BaseData = TelemetryPartB.GetRemoteDependencyData(activity);
23144
break;
23245
}
23346

234-
AddPropertiesToTelemetry(dependency.Properties, monitorTags.PartCTags);
235-
telemetry.BaseData = dependency;
236-
}
237-
238-
return telemetry;
239-
}
240-
241-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
242-
internal static void AddPropertiesToTelemetry(IDictionary<string, string> destination, AzMonList PartCTags)
243-
{
244-
// TODO: Iterate only interested fields. Ref: https://github.com/Azure/azure-sdk-for-net/pull/14254#discussion_r470907560
245-
for (int i = 0; i < PartCTags.Length; i++)
246-
{
247-
destination.Add(PartCTags[i].Key, PartCTags[i].Value?.ToString());
47+
telemetryItem.Data = telemetryData;
48+
telemetryItems.Add(telemetryItem);
24849
}
249-
}
25050

251-
internal struct TagEnumerationState : IActivityEnumerator<KeyValuePair<string, object>>
252-
{
253-
public AzMonList PartBTags;
254-
public AzMonList PartCTags;
255-
256-
private PartBType tempActivityType;
257-
public PartBType activityType;
258-
259-
public bool ForEach(KeyValuePair<string, object> activityTag)
260-
{
261-
if (activityTag.Value == null)
262-
{
263-
return true;
264-
}
265-
266-
if (activityTag.Value is Array array)
267-
{
268-
StringBuilder sw = new StringBuilder();
269-
foreach (var item in array)
270-
{
271-
// TODO: Consider changing it to JSon array.
272-
if (item != null)
273-
{
274-
sw.Append(item);
275-
sw.Append(',');
276-
}
277-
}
278-
279-
if (sw.Length > 0)
280-
{
281-
sw.Length--;
282-
}
283-
284-
AzMonList.Add(ref PartCTags, new KeyValuePair<string, object>(activityTag.Key, sw.ToString()));
285-
return true;
286-
}
287-
288-
if (!Part_B_Mapping.TryGetValue(activityTag.Key, out tempActivityType))
289-
{
290-
AzMonList.Add(ref PartCTags, activityTag);
291-
return true;
292-
}
293-
294-
if (activityType == PartBType.Unknown || activityType == PartBType.Common)
295-
{
296-
activityType = tempActivityType;
297-
}
298-
299-
if (tempActivityType == activityType || tempActivityType == PartBType.Common)
300-
{
301-
AzMonList.Add(ref PartBTags, activityTag);
302-
}
303-
else
304-
{
305-
AzMonList.Add(ref PartCTags, activityTag);
306-
}
307-
308-
return true;
309-
}
51+
return telemetryItems;
31052
}
31153
}
31254
}

sdk/monitor/Microsoft.OpenTelemetry.Exporter.AzureMonitor/src/SdkVersionUtils.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
using System.Globalization;
66
using System.Linq;
77
using System.Reflection;
8-
9-
using OpenTelemetrySdk = OpenTelemetry.Sdk;
8+
using OpenTelemetry;
109

1110
namespace Microsoft.OpenTelemetry.Exporter.AzureMonitor
1211
{
@@ -19,7 +18,7 @@ private static string GetSdkVersion()
1918
try
2019
{
2120
Version dotnetSdkVersion = GetVersion(typeof(object));
22-
Version otelSdkVersion = GetVersion(typeof(OpenTelemetrySdk));
21+
Version otelSdkVersion = GetVersion(typeof(Sdk));
2322
Version extensionVersion = GetVersion(typeof(AzureMonitorTraceExporter));
2423

2524
return string.Format(CultureInfo.InvariantCulture, $"dotnet{dotnetSdkVersion.ToString(2)}:otel{otelSdkVersion.ToString(3)}:ext{extensionVersion.ToString(3)}");

0 commit comments

Comments
 (0)