From 839b9fdf5ff3dfc7377f7ada4e12e416d18f3dd1 Mon Sep 17 00:00:00 2001 From: Vishwesh Bankwar Date: Mon, 31 Jul 2023 12:06:00 -0700 Subject: [PATCH 1/2] standard metrics for messaging --- .../Models/RemoteDependencyData.cs | 15 +- .../src/Internals/AzMonListExtensions.cs | 3 + .../StandardMetricsExtractionProcessor.cs | 17 +- .../src/Internals/TraceHelper.cs | 19 +++ ...ctivityTagsProcessorGetValuesBenchmarks.cs | 116 +++++++++++++ .../StandardMetricTests.cs | 158 +++++++++++++++++- 6 files changed, 303 insertions(+), 25 deletions(-) create mode 100644 sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Benchmarks/ActivityTagsProcessorGetValuesBenchmarks.cs 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 5d08c465e60e0..2de3e51bdbf8d 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 @@ -55,20 +55,7 @@ public RemoteDependencyData(int version, Activity activity, ref ActivityTagsProc if (activityTagsProcessor.AzureNamespace != null) { - if (activity.Kind == ActivityKind.Internal) - { - Type = $"InProc | {activityTagsProcessor.AzureNamespace}"; - } - else if (activity.Kind == ActivityKind.Producer) - { - Type = $"Queue Message | {activityTagsProcessor.AzureNamespace}"; - } - else - { - // The Azure SDK sets az.namespace with its resource provider information. - // When ActivityKind is not internal and az.namespace is present, set the value of Type to az.namespace. - Type = activityTagsProcessor.AzureNamespace ?? Type; - } + Type = TraceHelper.GetAzureSDKDependencyType(activity.Kind, activityTagsProcessor.AzureNamespace); } else if (activity.Kind == ActivityKind.Internal) { diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/AzMonListExtensions.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/AzMonListExtensions.cs index b6d546b2a7b16..77c86cb76ee14 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/AzMonListExtensions.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/AzMonListExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Diagnostics; using System.Runtime.CompilerServices; using Azure.Monitor.OpenTelemetry.Exporter.Models; @@ -344,6 +345,8 @@ internal static (string? DbName, string? DbTarget) GetDbDependencyTargetAndName( return tagObjects.GetHttpDependencyTarget(); case OperationType.Db: return tagObjects.GetDbDependencyTargetAndName().DbTarget; + case OperationType.Messaging: + return tagObjects.GetMessagingUrlAndSourceOrTarget(ActivityKind.Producer).SourceOrTarget; default: return null; } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/StandardMetricsExtractionProcessor.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/StandardMetricsExtractionProcessor.cs index e30c78cfdf4fb..8866e12026952 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/StandardMetricsExtractionProcessor.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/StandardMetricsExtractionProcessor.cs @@ -42,7 +42,7 @@ internal StandardMetricsExtractionProcessor(AzureMonitorMetricExporter metricExp public override void OnEnd(Activity activity) { - if (activity.Kind == ActivityKind.Server) + if (activity.Kind == ActivityKind.Server || activity.Kind == ActivityKind.Consumer) { if (_requestDuration.Enabled) { @@ -50,7 +50,7 @@ public override void OnEnd(Activity activity) ReportRequestDurationMetric(activity); } } - if (activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Internal) + if (activity.Kind == ActivityKind.Client || activity.Kind == ActivityKind.Internal || activity.Kind == ActivityKind.Producer) { if (_dependencyDuration.Enabled) { @@ -58,9 +58,6 @@ public override void OnEnd(Activity activity) ReportDependencyDurationMetric(activity); } } - - // TODO: other activity kinds - // (2023-07) fix before GA } private void ReportRequestDurationMetric(Activity activity) @@ -110,7 +107,15 @@ private void ReportDependencyDurationMetric(Activity activity) statusCode = AzMonList.GetTagValue(ref activityTagsProcessor.MappedTags, SemanticConventions.AttributeHttpStatusCode)?.ToString(); } - var dependencyType = activityTagsProcessor.MappedTags.GetDependencyType(activityTagsProcessor.activityType); + string? dependencyType; + if (activityTagsProcessor.AzureNamespace != null) + { + dependencyType = TraceHelper.GetAzureSDKDependencyType(activity.Kind, activityTagsProcessor.AzureNamespace); + } + else + { + dependencyType = activity.Kind == ActivityKind.Internal ? "InProc" : activityTagsProcessor.MappedTags.GetDependencyType(activityTagsProcessor.activityType); + } TagList tags = default; tags.Add(new KeyValuePair(StandardMetricConstants.DependencyTargetKey, dependencyTarget)); 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 63e92667a6ccc..59d3569905c45 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/TraceHelper.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/Internals/TraceHelper.cs @@ -404,5 +404,24 @@ private static void AddContextToMSLinks(StringBuilder linksJson, ActivityLink li linksJson .Append("},"); } + + internal static string GetAzureSDKDependencyType(ActivityKind kind, string azureNamespace) + { + // TODO: see if the values can be cached to avoid allocation. + if (kind == ActivityKind.Internal) + { + return $"InProc | {azureNamespace}"; + } + else if (kind == ActivityKind.Producer) + { + return $"Queue Message | {azureNamespace}"; + } + else + { + // The Azure SDK sets az.namespace with its resource provider information. + // When ActivityKind is not internal and az.namespace is present, set the value of Type to az.namespace. + return azureNamespace; + } + } } } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Benchmarks/ActivityTagsProcessorGetValuesBenchmarks.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Benchmarks/ActivityTagsProcessorGetValuesBenchmarks.cs new file mode 100644 index 0000000000000..25910ea0808d9 --- /dev/null +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Benchmarks/ActivityTagsProcessorGetValuesBenchmarks.cs @@ -0,0 +1,116 @@ +// 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 BenchmarkDotNet.Attributes; + +/* +BenchmarkDotNet=v0.13.4, OS=Windows 11 (10.0.22621.1702) +Intel Core i7-8850H CPU 2.60GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores +.NET SDK=7.0.203 + [Host] : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2 + DefaultJob : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2 + + +| Method | Mean | Error | StdDev | Allocated | +|-------------------------------- |---------:|--------:|--------:|----------:| +| Benchmark_ActivityTagsProcessor | 262.0 ns | 2.51 ns | 2.10 ns | - | +*/ + +namespace Azure.Monitor.OpenTelemetry.Exporter.Benchmarks +{ + [MemoryDiagnoser] + public class ActivityTagsProcessorGetValuesBenchmarks + { + private Activity? _activity; + private ActivityTagsProcessor _activityTagsProcessor; + + static ActivityTagsProcessorGetValuesBenchmarks() + { + Activity.DefaultIdFormat = ActivityIdFormat.W3C; + Activity.ForceDefaultIdFormat = true; + + var listener = new ActivityListener + { + ShouldListenTo = _ => true, + Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllData, + }; + + ActivitySource.AddActivityListener(listener); + } + + [GlobalSetup] + public void Setup() + { + IEnumerable> tagObjects = new Dictionary + { + [SemanticConventions.AttributeUrlScheme] = "https", + [SemanticConventions.AttributeHttpRequestMethod] = "GET", + [SemanticConventions.AttributeServerAddress] = "localhost", + ["somekey"] = "value", + [SemanticConventions.AttributeUrlPath] = "/path", + [SemanticConventions.AttributeUrlQuery] = "?test", + [SemanticConventions.AttributeUserAgentOriginal] = "userAgent", + [SemanticConventions.AttributeHttpRoute] = "route", + [SemanticConventions.AttributeHttpResponseStatusCode] = "200", + }; + + _activity = CreateTestActivity(tagObjects!); + _activityTagsProcessor = new ActivityTagsProcessor(); + _activityTagsProcessor.CategorizeTags(_activity!); + } + + [Benchmark] + public void Benchmark_ActivityTagsProcessorGetValue() + { + var httpRoute = AzMonList.GetTagValue(ref _activityTagsProcessor.MappedTags, SemanticConventions.AttributeHttpRoute)?.ToString(); + var httpMethod = AzMonList.GetTagValue(ref _activityTagsProcessor.MappedTags, SemanticConventions.AttributeHttpRequestMethod)?.ToString(); + } + + [Benchmark] + public void Benchmark_ActivityTagsProcessorGetValues() + { + var httpRouteAndMethod = AzMonList.GetTagValues(ref _activityTagsProcessor.MappedTags, SemanticConventions.AttributeHttpRequestMethod, SemanticConventions.AttributeHttpRoute); + } + + private static Activity? CreateTestActivity(IEnumerable>? additionalAttributes = null) + { + var startTimestamp = DateTime.UtcNow; + var endTimestamp = startTimestamp.AddSeconds(60); + var eventTimestamp = DateTime.UtcNow; + var traceId = ActivityTraceId.CreateRandom(); + + var parentSpanId = ActivitySpanId.CreateRandom(); + + Dictionary? attributes = null; + if (additionalAttributes != null) + { + attributes = new Dictionary(); + foreach (var attribute in additionalAttributes) + { + attributes.Add(attribute.Key, attribute.Value); + } + } + + var activitySource = new ActivitySource(nameof(CreateTestActivity)); + + var activity = activitySource.StartActivity( + "Name", + ActivityKind.Server, + parentContext: new ActivityContext(traceId, parentSpanId, ActivityTraceFlags.Recorded), + attributes!, + null, + startTime: startTimestamp); + + activity?.SetEndTime(endTimestamp); + activity?.Stop(); + + return activity; + } + } +} diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/StandardMetricTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/StandardMetricTests.cs index 9d4a76d77d988..8bbb12c9d5cf7 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/StandardMetricTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/StandardMetricTests.cs @@ -118,7 +118,61 @@ public void ValidateRequestDurationMetricNew() } [Fact] - public void ValidateDependencyDurationMetric() + public void ValidateRequestDurationMetricConsumerKind() + { + var activitySource = new ActivitySource(nameof(StandardMetricTests.ValidateRequestDurationMetricConsumerKind)); + var traceTelemetryItems = new List(); + var metricTelemetryItems = new List(); + + var standardMetricCustomProcessor = new StandardMetricsExtractionProcessor(new AzureMonitorMetricExporter(new MockTransmitter(metricTelemetryItems))); + + var traceServiceName = new KeyValuePair("service.name", "trace.service"); + var resourceAttributes = new KeyValuePair[] { traceServiceName }; + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .SetSampler(new AlwaysOnSampler()) + .SetResourceBuilder(ResourceBuilder.CreateDefault().AddAttributes(resourceAttributes)) + .AddSource(nameof(StandardMetricTests.ValidateRequestDurationMetricConsumerKind)) + .AddProcessor(standardMetricCustomProcessor) + .AddProcessor(new BatchActivityExportProcessor(new AzureMonitorTraceExporter(new AzureMonitorExporterOptions(), new MockTransmitter(traceTelemetryItems)))) + .Build(); + + using (var activity = activitySource.StartActivity("Test", ActivityKind.Consumer)) + { + activity?.SetTag(SemanticConventions.AttributeMessagingSystem, "messagingsystem"); + activity?.SetTag(SemanticConventions.AttributeServerAddress, "localhost"); + activity?.SetTag(SemanticConventions.AttributeMessagingDestinationName, "destination"); + activity?.SetStatus(ActivityStatusCode.Ok); + } + + tracerProvider?.ForceFlush(); + + WaitForActivityExport(traceTelemetryItems); + + standardMetricCustomProcessor._meterProvider?.ForceFlush(); + + Assert.Single(metricTelemetryItems); + + var metricTelemetry = metricTelemetryItems.Last()!; + Assert.Equal("MetricData", metricTelemetry.Data.BaseType); + var metricData = (MetricsData)metricTelemetry.Data.BaseData; + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.RequestSuccessKey, out var isSuccess)); + Assert.Equal("True", isSuccess); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.RequestResultCodeKey, out var resultCode)); + Assert.Equal("0", resultCode); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.IsAutoCollectedKey, out var isAutoCollectedFlag)); + Assert.Equal("True", isAutoCollectedFlag); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.CloudRoleInstanceKey, out _)); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.CloudRoleNameKey, out var cloudRoleName)); + Assert.Equal("trace.service", cloudRoleName); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.MetricIdKey, out var metricId)); + Assert.Equal(StandardMetricConstants.RequestDurationMetricIdValue, metricId); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ValidateDependencyDurationMetric(bool isAzureSDK) { var activitySource = new ActivitySource(nameof(StandardMetricTests.ValidateDependencyDurationMetric)); var traceTelemetryItems = new List(); @@ -139,6 +193,10 @@ public void ValidateDependencyDurationMetric() using (var activity = activitySource.StartActivity("Test", ActivityKind.Client)) { + if (isAzureSDK) + { + activity?.SetTag(SemanticConventions.AttributeAzureNameSpace, "aznamespace"); + } activity?.SetTag(SemanticConventions.AttributeHttpStatusCode, 200); activity?.SetTag(SemanticConventions.AttributeHttpMethod, "Get"); activity?.SetTag(SemanticConventions.AttributeHttpUrl, "https://www.foo.com"); @@ -167,13 +225,91 @@ public void ValidateDependencyDurationMetric() Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.MetricIdKey, out var metricId)); Assert.Equal(StandardMetricConstants.DependencyDurationMetricIdValue, metricId); Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.DependencyTypeKey, out var dependencyType)); - Assert.Equal("Http", dependencyType); + if (isAzureSDK) + { + Assert.Equal("aznamespace", dependencyType); + } + else + { + Assert.Equal("Http", dependencyType); + } + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.DependencyTargetKey, out var dependencyTarget)); Assert.Equal("www.foo.com", dependencyTarget); } - [Fact] - public void ValidateDependencyDurationMetricNew() + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ValidateDependencyDurationMetricForProducerKind(bool isAzureSDKSpan) + { + var activitySource = new ActivitySource(nameof(StandardMetricTests.ValidateDependencyDurationMetricForProducerKind)); + var traceTelemetryItems = new List(); + var metricTelemetryItems = new List(); + + var standardMetricCustomProcessor = new StandardMetricsExtractionProcessor(new AzureMonitorMetricExporter(new MockTransmitter(metricTelemetryItems))); + + var traceServiceName = new KeyValuePair("service.name", "trace.service"); + var resourceAttributes = new KeyValuePair[] { traceServiceName }; + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .SetSampler(new AlwaysOnSampler()) + .SetResourceBuilder(ResourceBuilder.CreateDefault().AddAttributes(resourceAttributes)) + .AddSource(nameof(StandardMetricTests.ValidateDependencyDurationMetricForProducerKind)) + .AddProcessor(standardMetricCustomProcessor) + .AddProcessor(new BatchActivityExportProcessor(new AzureMonitorTraceExporter(new AzureMonitorExporterOptions(), new MockTransmitter(traceTelemetryItems)))) + .Build(); + + using (var activity = activitySource.StartActivity("Test", ActivityKind.Producer)) + { + if (isAzureSDKSpan) + { + activity?.SetTag(SemanticConventions.AttributeAzureNameSpace, "aznamespace"); + } + activity?.SetTag(SemanticConventions.AttributeMessagingSystem, "messagingsystem"); + activity?.SetTag(SemanticConventions.AttributeServerAddress, "localhost"); + activity?.SetTag(SemanticConventions.AttributeMessagingDestinationName, "destination"); + } + + tracerProvider?.ForceFlush(); + + WaitForActivityExport(traceTelemetryItems); + + standardMetricCustomProcessor._meterProvider?.ForceFlush(); + + Assert.Single(metricTelemetryItems); + + var metricTelemetry = metricTelemetryItems.Last()!; + Assert.Equal("MetricData", metricTelemetry.Data.BaseType); + var metricData = (MetricsData)metricTelemetry.Data.BaseData; + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.DependencySuccessKey, out var isSuccess)); + Assert.Equal("True", isSuccess); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.DependencyResultCodeKey, out var resultCode)); + Assert.Equal("0", resultCode); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.IsAutoCollectedKey, out var isAutoCollectedFlag)); + Assert.Equal("True", isAutoCollectedFlag); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.CloudRoleInstanceKey, out _)); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.CloudRoleNameKey, out var cloudRoleName)); + Assert.Equal("trace.service", cloudRoleName); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.MetricIdKey, out var metricId)); + Assert.Equal(StandardMetricConstants.DependencyDurationMetricIdValue, metricId); + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.DependencyTypeKey, out var dependencyType)); + if (isAzureSDKSpan) + { + Assert.Equal("Queue Message | aznamespace", dependencyType); + } + else + { + Assert.Equal("messagingsystem", dependencyType); + } + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.DependencyTargetKey, out var dependencyTarget)); + Assert.Equal("localhost/destination", dependencyTarget); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ValidateDependencyDurationMetricNew(bool isAzureSDK) { var activitySource = new ActivitySource(nameof(StandardMetricTests.ValidateDependencyDurationMetric)); var traceTelemetryItems = new List(); @@ -194,6 +330,10 @@ public void ValidateDependencyDurationMetricNew() using (var activity = activitySource.StartActivity("Test", ActivityKind.Client)) { + if (isAzureSDK) + { + activity?.SetTag(SemanticConventions.AttributeAzureNameSpace, "aznamespace"); + } activity?.SetTag(SemanticConventions.AttributeHttpResponseStatusCode, 200); activity?.SetTag(SemanticConventions.AttributeHttpRequestMethod, "Get"); activity?.SetTag(SemanticConventions.AttributeServerAddress, "foo.com"); @@ -222,7 +362,15 @@ public void ValidateDependencyDurationMetricNew() Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.MetricIdKey, out var metricId)); Assert.Equal(StandardMetricConstants.DependencyDurationMetricIdValue, metricId); Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.DependencyTypeKey, out var dependencyType)); - Assert.Equal("Http", dependencyType); + if (isAzureSDK) + { + Assert.Equal("aznamespace", dependencyType); + } + else + { + Assert.Equal("Http", dependencyType); + } + Assert.True(metricData.Properties.TryGetValue(StandardMetricConstants.DependencyTargetKey, out var dependencyTarget)); Assert.Equal("foo.com", dependencyTarget); } From 792a07fc1b72e93f2060bb4a64b9c5d9c6bbc5ec Mon Sep 17 00:00:00 2001 From: Vishwesh Bankwar Date: Mon, 31 Jul 2023 12:47:26 -0700 Subject: [PATCH 2/2] revert change --- ...ctivityTagsProcessorGetValuesBenchmarks.cs | 116 ------------------ 1 file changed, 116 deletions(-) delete mode 100644 sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Benchmarks/ActivityTagsProcessorGetValuesBenchmarks.cs diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Benchmarks/ActivityTagsProcessorGetValuesBenchmarks.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Benchmarks/ActivityTagsProcessorGetValuesBenchmarks.cs deleted file mode 100644 index 25910ea0808d9..0000000000000 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Benchmarks/ActivityTagsProcessorGetValuesBenchmarks.cs +++ /dev/null @@ -1,116 +0,0 @@ -// 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 BenchmarkDotNet.Attributes; - -/* -BenchmarkDotNet=v0.13.4, OS=Windows 11 (10.0.22621.1702) -Intel Core i7-8850H CPU 2.60GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores -.NET SDK=7.0.203 - [Host] : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2 - DefaultJob : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2 - - -| Method | Mean | Error | StdDev | Allocated | -|-------------------------------- |---------:|--------:|--------:|----------:| -| Benchmark_ActivityTagsProcessor | 262.0 ns | 2.51 ns | 2.10 ns | - | -*/ - -namespace Azure.Monitor.OpenTelemetry.Exporter.Benchmarks -{ - [MemoryDiagnoser] - public class ActivityTagsProcessorGetValuesBenchmarks - { - private Activity? _activity; - private ActivityTagsProcessor _activityTagsProcessor; - - static ActivityTagsProcessorGetValuesBenchmarks() - { - Activity.DefaultIdFormat = ActivityIdFormat.W3C; - Activity.ForceDefaultIdFormat = true; - - var listener = new ActivityListener - { - ShouldListenTo = _ => true, - Sample = (ref ActivityCreationOptions options) => ActivitySamplingResult.AllData, - }; - - ActivitySource.AddActivityListener(listener); - } - - [GlobalSetup] - public void Setup() - { - IEnumerable> tagObjects = new Dictionary - { - [SemanticConventions.AttributeUrlScheme] = "https", - [SemanticConventions.AttributeHttpRequestMethod] = "GET", - [SemanticConventions.AttributeServerAddress] = "localhost", - ["somekey"] = "value", - [SemanticConventions.AttributeUrlPath] = "/path", - [SemanticConventions.AttributeUrlQuery] = "?test", - [SemanticConventions.AttributeUserAgentOriginal] = "userAgent", - [SemanticConventions.AttributeHttpRoute] = "route", - [SemanticConventions.AttributeHttpResponseStatusCode] = "200", - }; - - _activity = CreateTestActivity(tagObjects!); - _activityTagsProcessor = new ActivityTagsProcessor(); - _activityTagsProcessor.CategorizeTags(_activity!); - } - - [Benchmark] - public void Benchmark_ActivityTagsProcessorGetValue() - { - var httpRoute = AzMonList.GetTagValue(ref _activityTagsProcessor.MappedTags, SemanticConventions.AttributeHttpRoute)?.ToString(); - var httpMethod = AzMonList.GetTagValue(ref _activityTagsProcessor.MappedTags, SemanticConventions.AttributeHttpRequestMethod)?.ToString(); - } - - [Benchmark] - public void Benchmark_ActivityTagsProcessorGetValues() - { - var httpRouteAndMethod = AzMonList.GetTagValues(ref _activityTagsProcessor.MappedTags, SemanticConventions.AttributeHttpRequestMethod, SemanticConventions.AttributeHttpRoute); - } - - private static Activity? CreateTestActivity(IEnumerable>? additionalAttributes = null) - { - var startTimestamp = DateTime.UtcNow; - var endTimestamp = startTimestamp.AddSeconds(60); - var eventTimestamp = DateTime.UtcNow; - var traceId = ActivityTraceId.CreateRandom(); - - var parentSpanId = ActivitySpanId.CreateRandom(); - - Dictionary? attributes = null; - if (additionalAttributes != null) - { - attributes = new Dictionary(); - foreach (var attribute in additionalAttributes) - { - attributes.Add(attribute.Key, attribute.Value); - } - } - - var activitySource = new ActivitySource(nameof(CreateTestActivity)); - - var activity = activitySource.StartActivity( - "Name", - ActivityKind.Server, - parentContext: new ActivityContext(traceId, parentSpanId, ActivityTraceFlags.Recorded), - attributes!, - null, - startTime: startTimestamp); - - activity?.SetEndTime(endTimestamp); - activity?.Stop(); - - return activity; - } - } -}