99} from "@opentelemetry/sdk-metrics" ;
1010import { AzureMonitorOpenTelemetryConfig } from "../shared/config" ;
1111import { AzureMonitorMetricExporter } from "@azure/monitor-opentelemetry-exporter" ;
12- import { Attributes , Histogram , Meter , SpanKind , ValueType } from "@opentelemetry/api" ;
13- import { ReadableSpan , Span } from "@opentelemetry/sdk-trace-base" ;
12+ import { Attributes , Counter , Histogram , Meter , SpanKind , ValueType } from "@opentelemetry/api" ;
13+ import { ReadableSpan , Span , TimedEvent } from "@opentelemetry/sdk-trace-base" ;
1414import {
1515 SemanticAttributes ,
1616 SemanticResourceAttributes ,
@@ -20,20 +20,24 @@ import {
2020 MetricRequestDimensions ,
2121 StandardMetricBaseDimensions ,
2222} from "./types" ;
23+ import { LogRecord } from "@opentelemetry/sdk-logs" ;
24+ import { Resource } from "@opentelemetry/resources" ;
2325
2426/**
2527 * Azure Monitor Standard Metrics
2628 * @internal
2729 */
2830export class StandardMetrics {
31+ private _config : AzureMonitorOpenTelemetryConfig ;
2932 private _collectionInterval = 60000 ; // 60 seconds
3033 private _meterProvider : MeterProvider ;
3134 private _azureExporter : AzureMonitorMetricExporter ;
3235 private _metricReader : PeriodicExportingMetricReader ;
3336 private _meter : Meter ;
3437 private _incomingRequestDurationHistogram : Histogram ;
3538 private _outgoingRequestDurationHistogram : Histogram ;
36- private _config : AzureMonitorOpenTelemetryConfig ;
39+ private _exceptionsCounter : Counter ;
40+ private _tracesCounter : Counter ;
3741
3842 /**
3943 * Initializes a new instance of the StandardMetrics class.
@@ -54,11 +58,24 @@ export class StandardMetrics {
5458 this . _metricReader = new PeriodicExportingMetricReader ( metricReaderOptions ) ;
5559 this . _meterProvider . addMetricReader ( this . _metricReader ) ;
5660 this . _meter = this . _meterProvider . getMeter ( "AzureMonitorStandardMetricsMeter" ) ;
57- this . _incomingRequestDurationHistogram = this . _meter . createHistogram ( "REQUEST_DURATION" , {
58- valueType : ValueType . DOUBLE ,
61+ this . _incomingRequestDurationHistogram = this . _meter . createHistogram (
62+ "azureMonitor.http.requestDuration" ,
63+ {
64+ valueType : ValueType . DOUBLE ,
65+ }
66+ ) ;
67+ this . _outgoingRequestDurationHistogram = this . _meter . createHistogram (
68+ "azureMonitor.http.dependencyDuration" ,
69+ {
70+ valueType : ValueType . DOUBLE ,
71+ }
72+ ) ;
73+
74+ this . _exceptionsCounter = this . _meter . createCounter ( "azureMonitor.exceptionCount" , {
75+ valueType : ValueType . INT ,
5976 } ) ;
60- this . _outgoingRequestDurationHistogram = this . _meter . createHistogram ( "DEPENDENCY_DURATION ", {
61- valueType : ValueType . DOUBLE ,
77+ this . _tracesCounter = this . _meter . createCounter ( "azureMonitor.traceCount ", {
78+ valueType : ValueType . INT ,
6279 } ) ;
6380 }
6481
@@ -108,10 +125,36 @@ export class StandardMetrics {
108125 this . _getDependencyDimensions ( span )
109126 ) ;
110127 }
128+ if ( span . events ) {
129+ span . events . forEach ( ( event : TimedEvent ) => {
130+ event . attributes = event . attributes || { } ;
131+ if ( event . name === "exception" ) {
132+ event . attributes [ "_MS.ProcessedByMetricExtractors" ] = "(Name:'Exceptions', Ver:'1.1')" ;
133+ this . _exceptionsCounter . add ( 1 , this . _getExceptionDimensions ( span . resource ) ) ;
134+ } else {
135+ event . attributes [ "_MS.ProcessedByMetricExtractors" ] = "(Name:'Traces', Ver:'1.1')" ;
136+ this . _tracesCounter . add ( 1 , this . _getTraceDimensions ( span . resource ) ) ;
137+ }
138+ } ) ;
139+ }
140+ }
141+
142+ /**
143+ * Record LogRecord metrics, add attribute so data is not aggregated again in ingestion
144+ * @internal
145+ */
146+ public recordLog ( logRecord : LogRecord ) : void {
147+ if ( this . _isExceptionTelemetry ( logRecord ) ) {
148+ logRecord . setAttribute ( "_MS.ProcessedByMetricExtractors" , "(Name:'Exceptions', Ver:'1.1')" ) ;
149+ this . _exceptionsCounter . add ( 1 , this . _getExceptionDimensions ( logRecord . resource ) ) ;
150+ } else if ( this . _isTraceTelemetry ( logRecord ) ) {
151+ logRecord . setAttribute ( "_MS.ProcessedByMetricExtractors" , "(Name:'Traces', Ver:'1.1')" ) ;
152+ this . _tracesCounter . add ( 1 , this . _getTraceDimensions ( logRecord . resource ) ) ;
153+ }
111154 }
112155
113156 private _getRequestDimensions ( span : ReadableSpan ) : Attributes {
114- const dimensions : MetricRequestDimensions = this . _getBaseDimensions ( span ) ;
157+ const dimensions : MetricRequestDimensions = this . _getBaseDimensions ( span . resource ) ;
115158 dimensions . metricId = "requests/duration" ;
116159 const statusCode = String ( span . attributes [ "http.status_code" ] ) ;
117160 dimensions . requestResultCode = statusCode ;
@@ -120,7 +163,7 @@ export class StandardMetrics {
120163 }
121164
122165 private _getDependencyDimensions ( span : ReadableSpan ) : Attributes {
123- const dimensions : MetricDependencyDimensions = this . _getBaseDimensions ( span ) ;
166+ const dimensions : MetricDependencyDimensions = this . _getBaseDimensions ( span . resource ) ;
124167 dimensions . metricId = "dependencies/duration" ;
125168 const statusCode = String ( span . attributes [ "http.status_code" ] ) ;
126169 dimensions . dependencyTarget = this . _getDependencyTarget ( span . attributes ) ;
@@ -130,11 +173,23 @@ export class StandardMetrics {
130173 return dimensions as Attributes ;
131174 }
132175
133- private _getBaseDimensions ( span : ReadableSpan ) : StandardMetricBaseDimensions {
176+ private _getExceptionDimensions ( resource : Resource ) : Attributes {
177+ const dimensions : StandardMetricBaseDimensions = this . _getBaseDimensions ( resource ) ;
178+ dimensions . metricId = "exceptions/count" ;
179+ return dimensions as Attributes ;
180+ }
181+
182+ private _getTraceDimensions ( resource : Resource ) : Attributes {
183+ const dimensions : StandardMetricBaseDimensions = this . _getBaseDimensions ( resource ) ;
184+ dimensions . metricId = "traces/count" ;
185+ return dimensions as Attributes ;
186+ }
187+
188+ private _getBaseDimensions ( resource : Resource ) : StandardMetricBaseDimensions {
134189 const dimensions : StandardMetricBaseDimensions = { } ;
135190 dimensions . IsAutocollected = "True" ;
136- if ( span . resource ) {
137- const spanResourceAttributes = span . resource . attributes ;
191+ if ( resource ) {
192+ const spanResourceAttributes = resource . attributes ;
138193 const serviceName = spanResourceAttributes [ SemanticResourceAttributes . SERVICE_NAME ] ;
139194 const serviceNamespace = spanResourceAttributes [ SemanticResourceAttributes . SERVICE_NAMESPACE ] ;
140195 if ( serviceName ) {
@@ -173,4 +228,32 @@ export class StandardMetrics {
173228 }
174229 return "" ;
175230 }
231+
232+ private _isExceptionTelemetry ( logRecord : LogRecord ) {
233+ const baseType = logRecord . attributes [ "_MS.baseType" ] ;
234+ // If Application Insights Legacy logs
235+ if ( baseType && baseType === "ExceptionData" ) {
236+ return true ;
237+ } else if (
238+ logRecord . attributes [ SemanticAttributes . EXCEPTION_MESSAGE ] ||
239+ logRecord . attributes [ SemanticAttributes . EXCEPTION_TYPE ]
240+ ) {
241+ return true ;
242+ }
243+ return false ;
244+ }
245+
246+ private _isTraceTelemetry ( logRecord : LogRecord ) {
247+ const baseType = logRecord . attributes [ "_MS.baseType" ] ;
248+ // If Application Insights Legacy logs
249+ if ( baseType && baseType === "MessageData" ) {
250+ return true ;
251+ } else if (
252+ ! logRecord . attributes [ SemanticAttributes . EXCEPTION_MESSAGE ] &&
253+ ! logRecord . attributes [ SemanticAttributes . EXCEPTION_TYPE ]
254+ ) {
255+ return true ;
256+ }
257+ return false ;
258+ }
176259}
0 commit comments