11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT License.
33
4- using System ;
54using System . Collections . Generic ;
65using System . Diagnostics ;
7- using System . Globalization ;
8- using System . Runtime . CompilerServices ;
9- using System . Text ;
10- using Microsoft . OpenTelemetry . Exporter . AzureMonitor . Models ;
11-
126using OpenTelemetry ;
13- using OpenTelemetry . Resources ;
14- using OpenTelemetry . Trace ;
7+ using Microsoft . OpenTelemetry . Exporter . AzureMonitor . Models ;
158
169namespace 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}
0 commit comments