From d63cf3c691d88efaae7f8167b25561530f255222 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Tue, 28 Jan 2020 11:47:16 -0800 Subject: [PATCH] Include resource namespace in diagnostics scope (#9655) --- .../src/Azure.Data.AppConfiguration.csproj | 1 + .../src/Properties/AssemblyInfo.cs | 1 + sdk/core/Azure.Core/src/Azure.Core.csproj | 16 +++--- .../src/Pipeline/HttpPipelineBuilder.cs | 2 +- .../Internal/RequestActivityPolicy.cs | 45 ++++++++++------- ...AzureResourceProviderNamespaceAttribute.cs | 22 +++++++++ .../src/Shared/ClientDiagnostics.cs | 34 +++++++++++-- .../Azure.Core/tests/Azure.Core.Tests.csproj | 1 + .../tests/ClientDiagnosticsTests.cs | 46 +++++++++++++++-- .../ClientTestBaseDiagnosticScopeTests.cs | 4 +- .../tests/RequestActivityPolicyTests.cs | 37 +++++++++++++- .../TestFramework/ClientDiagnosticListener.cs | 44 +++++++++++++---- .../DiagnosticScopeValidatingInterceptor.cs | 49 +++++++++---------- .../Diagnostics/EventDataInstrumentation.cs | 2 +- .../Azure.Identity/src/Azure.Identity.csproj | 1 + .../src/Properties/AssemblyInfo.cs | 1 + ...zure.Security.KeyVault.Certificates.csproj | 1 + .../src/Properties/AssemblyInfo.cs | 1 + .../src/Azure.Security.KeyVault.Keys.csproj | 1 + .../src/Properties/AssemblyInfo.cs | 1 + .../Azure.Security.KeyVault.Secrets.csproj | 1 + .../src/Properties/AssemblyInfo.cs | 1 + .../src/AssemblyInfo.cs | 1 + .../src/Azure.Storage.Blobs.Batch.csproj | 1 + .../Azure.Storage.Blobs/src/AssemblyInfo.cs | 1 + .../src/Azure.Storage.Blobs.csproj | 1 + .../src/AssemblyInfo.cs | 1 + .../src/Azure.Storage.Files.DataLake.csproj | 1 + .../src/AssemblyInfo.cs | 1 + .../src/Azure.Storage.Files.Shares.csproj | 1 + .../Azure.Storage.Queues/src/AssemblyInfo.cs | 1 + .../src/Azure.Storage.Queues.csproj | 1 + .../src/Azure.AI.TextAnalytics.csproj | 1 + .../src/Properties/AssemblyInfo.cs | 1 + 34 files changed, 250 insertions(+), 74 deletions(-) create mode 100644 sdk/core/Azure.Core/src/Shared/AzureResourceProviderNamespaceAttribute.cs diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Azure.Data.AppConfiguration.csproj b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Azure.Data.AppConfiguration.csproj index e4cd0ebb37552..4fd3ac0f8b739 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Azure.Data.AppConfiguration.csproj +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Azure.Data.AppConfiguration.csproj @@ -20,6 +20,7 @@ + diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Properties/AssemblyInfo.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Properties/AssemblyInfo.cs index a19313a939005..df6399f1e1944 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Properties/AssemblyInfo.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/Properties/AssemblyInfo.cs @@ -7,3 +7,4 @@ // See https://github.com/castleproject/Core/blob/master/src/Castle.Core/Core/Internal/InternalsVisible.cs for values [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.AppConfiguration")] \ No newline at end of file diff --git a/sdk/core/Azure.Core/src/Azure.Core.csproj b/sdk/core/Azure.Core/src/Azure.Core.csproj index f65bb51cc2cc8..a19a45107f58e 100644 --- a/sdk/core/Azure.Core/src/Azure.Core.csproj +++ b/sdk/core/Azure.Core/src/Azure.Core.csproj @@ -21,13 +21,13 @@ - - - - - - - - + + + + + + + + diff --git a/sdk/core/Azure.Core/src/Pipeline/HttpPipelineBuilder.cs b/sdk/core/Azure.Core/src/Pipeline/HttpPipelineBuilder.cs index 1c8c33c72727e..6ad94a2c06f9f 100644 --- a/sdk/core/Azure.Core/src/Pipeline/HttpPipelineBuilder.cs +++ b/sdk/core/Azure.Core/src/Pipeline/HttpPipelineBuilder.cs @@ -75,7 +75,7 @@ public static HttpPipeline Build(ClientOptions options, HttpPipelinePolicy[] per policies.Add(BufferResponsePolicy.Shared); - policies.Add(new RequestActivityPolicy(isDistributedTracingEnabled)); + policies.Add(new RequestActivityPolicy(isDistributedTracingEnabled, ClientDiagnostics.GetResourceProviderNamespace(options.GetType().Assembly))); policies.RemoveAll(policy => policy == null); diff --git a/sdk/core/Azure.Core/src/Pipeline/Internal/RequestActivityPolicy.cs b/sdk/core/Azure.Core/src/Pipeline/Internal/RequestActivityPolicy.cs index 7dba1acf836f9..309bbd055d1b6 100644 --- a/sdk/core/Azure.Core/src/Pipeline/Internal/RequestActivityPolicy.cs +++ b/sdk/core/Azure.Core/src/Pipeline/Internal/RequestActivityPolicy.cs @@ -11,6 +11,7 @@ namespace Azure.Core.Pipeline internal class RequestActivityPolicy : HttpPipelinePolicy { private readonly bool _isDistributedTracingEnabled; + private readonly string? _resourceProviderNamespace; private const string TraceParentHeaderName = "traceparent"; private const string TraceStateHeaderName = "tracestate"; @@ -18,9 +19,10 @@ internal class RequestActivityPolicy : HttpPipelinePolicy private static readonly DiagnosticListener s_diagnosticSource = new DiagnosticListener("Azure.Core"); - public RequestActivityPolicy(bool isDistributedTracingEnabled) + public RequestActivityPolicy(bool isDistributedTracingEnabled, string? resourceProviderNamespace) { _isDistributedTracingEnabled = isDistributedTracingEnabled; + _resourceProviderNamespace = resourceProviderNamespace; } public override ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory pipeline) @@ -62,6 +64,11 @@ private async ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory + /// This attribute should be set on all client assemblies with value of one of the resource providers + /// from the https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/azure-services-resource-providers list. + /// + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] + internal class AzureResourceProviderNamespaceAttribute : Attribute + { + public string ResourceProviderNamespace { get; } + + public AzureResourceProviderNamespaceAttribute(string resourceProviderNamespace) + { + ResourceProviderNamespace = resourceProviderNamespace; + } + } +} \ No newline at end of file diff --git a/sdk/core/Azure.Core/src/Shared/ClientDiagnostics.cs b/sdk/core/Azure.Core/src/Shared/ClientDiagnostics.cs index a7e629a750bd8..b9310bd0866d6 100644 --- a/sdk/core/Azure.Core/src/Shared/ClientDiagnostics.cs +++ b/sdk/core/Azure.Core/src/Shared/ClientDiagnostics.cs @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Diagnostics; +using System.Reflection; #nullable enable @@ -11,12 +13,14 @@ namespace Azure.Core.Pipeline internal sealed class ClientDiagnostics #pragma warning restore CA1001 // Types that own disposable fields should be disposable { + private readonly string? _resourceProviderNamespace; private readonly DiagnosticListener? _source; public bool IsActivityEnabled { get; } - public ClientDiagnostics(string clientNamespace, bool isActivityEnabled) + public ClientDiagnostics(string clientNamespace, string? resourceProviderNamespace, bool isActivityEnabled) { + _resourceProviderNamespace = resourceProviderNamespace; IsActivityEnabled = isActivityEnabled; if (IsActivityEnabled) { @@ -24,7 +28,10 @@ public ClientDiagnostics(string clientNamespace, bool isActivityEnabled) } } - public ClientDiagnostics(ClientOptions options) : this(options.GetType().Namespace, options.Diagnostics.IsDistributedTracingEnabled) + public ClientDiagnostics(ClientOptions options) : this( + options.GetType().Namespace, + GetResourceProviderNamespace(options.GetType().Assembly), + options.Diagnostics.IsDistributedTracingEnabled) { } @@ -34,7 +41,28 @@ public DiagnosticScope CreateScope(string name) { return default; } - return new DiagnosticScope(name, _source); + var scope = new DiagnosticScope(name, _source); + + if (_resourceProviderNamespace != null) + { + scope.AddAttribute("az.namespace", _resourceProviderNamespace); + } + return scope; + } + + internal static string? GetResourceProviderNamespace(Assembly assembly) + { + foreach (var customAttribute in assembly.GetCustomAttributes(true)) + { + // Weak bind internal shared type + var attributeType = customAttribute.GetType(); + if (attributeType.Name == "AzureResourceProviderNamespaceAttribute") + { + return attributeType.GetProperty("ResourceProviderNamespace")?.GetValue(customAttribute) as string; + } + } + + return null; } } } diff --git a/sdk/core/Azure.Core/tests/Azure.Core.Tests.csproj b/sdk/core/Azure.Core/tests/Azure.Core.Tests.csproj index dac25eea6ca1b..394d2ab585884 100644 --- a/sdk/core/Azure.Core/tests/Azure.Core.Tests.csproj +++ b/sdk/core/Azure.Core/tests/Azure.Core.Tests.csproj @@ -29,6 +29,7 @@ + diff --git a/sdk/core/Azure.Core/tests/ClientDiagnosticsTests.cs b/sdk/core/Azure.Core/tests/ClientDiagnosticsTests.cs index 1f44345c68510..18a7a069bd7ad 100644 --- a/sdk/core/Azure.Core/tests/ClientDiagnosticsTests.cs +++ b/sdk/core/Azure.Core/tests/ClientDiagnosticsTests.cs @@ -5,10 +5,12 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using Azure.Core.Diagnostics; +using Azure.Core; using Azure.Core.Pipeline; using NUnit.Framework; +[assembly:AzureResourceProviderNamespace("Microsoft.Azure.Core.Cool.Tests")] + namespace Azure.Core.Tests { public class ClientDiagnosticsTests @@ -18,7 +20,7 @@ public void CreatesActivityWithNameAndTags() { using var testListener = new TestDiagnosticListener("Azure.Clients"); - ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Clients", true); + ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Clients", "Microsoft.Azure.Core.Cool.Tests", true); DiagnosticScope scope = clientDiagnostics.CreateScope("ActivityName"); @@ -44,13 +46,40 @@ public void CreatesActivityWithNameAndTags() CollectionAssert.Contains(activity.Tags, new KeyValuePair("Attribute1", "Value1")); CollectionAssert.Contains(activity.Tags, new KeyValuePair("Attribute2", "2")); CollectionAssert.Contains(activity.Tags, new KeyValuePair("Attribute3", "3")); + CollectionAssert.Contains(activity.Tags, new KeyValuePair("az.namespace", "Microsoft.Azure.Core.Cool.Tests")); + } + + [Test] + public void ResourceNameIsOptional() + { + + using var testListener = new TestDiagnosticListener("Azure.Clients"); + ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Clients", null, true); + + DiagnosticScope scope = clientDiagnostics.CreateScope("ActivityName"); + scope.Start(); + + (string Key, object Value, DiagnosticListener) startEvent = testListener.Events.Dequeue(); + + Activity activity = Activity.Current; + + scope.Dispose(); + + (string Key, object Value, DiagnosticListener) stopEvent = testListener.Events.Dequeue(); + + Assert.Null(Activity.Current); + Assert.AreEqual("ActivityName.Start", startEvent.Key); + Assert.AreEqual("ActivityName.Stop", stopEvent.Key); + + Assert.AreEqual(ActivityIdFormat.W3C, activity.IdFormat); + CollectionAssert.IsEmpty(activity.Tags); } [Test] public void AddLinkCallsPassesLinksAsPartOfStartPayload() { using var testListener = new TestDiagnosticListener("Azure.Clients"); - ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Clients", true); + ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Clients", "Microsoft.Azure.Core.Cool.Tests",true); DiagnosticScope scope = clientDiagnostics.CreateScope("ActivityName"); @@ -91,7 +120,7 @@ public void AddLinkCallsPassesLinksAsPartOfStartPayload() public void FailedStopsActivityAndWritesExceptionEvent() { using var testListener = new TestDiagnosticListener("Azure.Clients"); - ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Clients", true); + ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Clients", "Microsoft.Azure.Core.Cool.Tests", true); DiagnosticScope scope = clientDiagnostics.CreateScope("ActivityName"); @@ -120,12 +149,13 @@ public void FailedStopsActivityAndWritesExceptionEvent() CollectionAssert.Contains(activity.Tags, new KeyValuePair("Attribute1", "Value1")); CollectionAssert.Contains(activity.Tags, new KeyValuePair("Attribute2", "2")); + CollectionAssert.Contains(activity.Tags, new KeyValuePair("az.namespace", "Microsoft.Azure.Core.Cool.Tests")); } [Test] public void NoopsWhenDisabled() { - ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Clients", false); + ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Clients", "Microsoft.Azure.Core.Cool.Tests", false); DiagnosticScope scope = clientDiagnostics.CreateScope(""); scope.AddAttribute("Attribute1", "Value1"); @@ -133,5 +163,11 @@ public void NoopsWhenDisabled() scope.Failed(new Exception()); scope.Dispose(); } + + [Test] + public void GetResourceProviderNamespaceReturnsAttributeValue() + { + Assert.AreEqual("Microsoft.Azure.Core.Cool.Tests", ClientDiagnostics.GetResourceProviderNamespace(GetType().Assembly)); + } } } diff --git a/sdk/core/Azure.Core/tests/ClientTestBaseDiagnosticScopeTests.cs b/sdk/core/Azure.Core/tests/ClientTestBaseDiagnosticScopeTests.cs index 68a9dd107425d..3d94e73936f09 100644 --- a/sdk/core/Azure.Core/tests/ClientTestBaseDiagnosticScopeTests.cs +++ b/sdk/core/Azure.Core/tests/ClientTestBaseDiagnosticScopeTests.cs @@ -23,7 +23,7 @@ public void ThrowsWhenNoDiagnosticScope() { InvalidDiagnosticScopeTestClient client = InstrumentClient(new InvalidDiagnosticScopeTestClient()); InvalidOperationException ex = Assert.ThrowsAsync(async () => await client.NoScopeAsync()); - StringAssert.Contains("Expected some diagnostic event to fire", ex.Message); + StringAssert.Contains("Expected some diagnostic scopes to be created, found none", ex.Message); } [Test] @@ -57,7 +57,7 @@ public class InvalidDiagnosticScopeTestClient { private void FireScope(string method) { - ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Core.Tests", true); + ClientDiagnostics clientDiagnostics = new ClientDiagnostics("Azure.Core.Tests", "random", true); string activityName = $"{typeof(InvalidDiagnosticScopeTestClient).Name}.{method}"; DiagnosticScope scope = clientDiagnostics.CreateScope(activityName); scope.Start(); diff --git a/sdk/core/Azure.Core/tests/RequestActivityPolicyTests.cs b/sdk/core/Azure.Core/tests/RequestActivityPolicyTests.cs index 0fca228090bee..92cc73058cdc5 100644 --- a/sdk/core/Azure.Core/tests/RequestActivityPolicyTests.cs +++ b/sdk/core/Azure.Core/tests/RequestActivityPolicyTests.cs @@ -17,7 +17,7 @@ public RequestActivityPolicyTests(bool isAsync) : base(isAsync) { } - private static readonly RequestActivityPolicy s_enabledPolicy = new RequestActivityPolicy(true); + private static readonly RequestActivityPolicy s_enabledPolicy = new RequestActivityPolicy(true, "Microsoft.Azure.Core.Cool.Tests"); [Test] [NonParallelizable] @@ -61,9 +61,42 @@ public async Task ActivityIsCreatedForRequest() CollectionAssert.Contains(activity.Tags, new KeyValuePair("requestId", clientRequestId)); CollectionAssert.Contains(activity.Tags, new KeyValuePair("serviceRequestId", "server request id")); CollectionAssert.Contains(activity.Tags, new KeyValuePair("kind", "client")); + CollectionAssert.Contains(activity.Tags, new KeyValuePair("az.namespace", "Microsoft.Azure.Core.Cool.Tests")); } + [Test] + [NonParallelizable] + public void ActivityShouldBeStoppedWhenTransportThrows() + { + Activity activity = null; + (string Key, object Value, DiagnosticListener) startEvent = default; + using var testListener = new TestDiagnosticListener("Azure.Core"); + + MockTransport mockTransport = CreateMockTransport(_ => + { + activity = Activity.Current; + startEvent = testListener.Events.Dequeue(); + throw new Exception(); + }); + + string clientRequestId = null; + Assert.ThrowsAsync(async () => await SendRequestAsync(mockTransport, request => + { + request.Method = RequestMethod.Get; + request.Uri.Reset(new Uri("http://example.com")); + request.Headers.Add("User-Agent", "agent"); + clientRequestId = request.ClientRequestId; + }, s_enabledPolicy)); + + (string Key, object Value, DiagnosticListener) stopEvent = testListener.Events.Dequeue(); + + Assert.AreEqual("Azure.Core.Http.Request.Start", startEvent.Key); + Assert.AreEqual("Azure.Core.Http.Request.Stop", stopEvent.Key); + + Assert.AreEqual("Azure.Core.Http.Request", activity.OperationName); + } + [Test] [NonParallelizable] public async Task ActivityIdIsStampedOnRequest() @@ -180,7 +213,7 @@ public async Task ActivityIsNotCreatedWhenDisabled() var transport = new MockTransport(new MockResponse(200)); - await SendGetRequest(transport, new RequestActivityPolicy(isDistributedTracingEnabled: false)); + await SendGetRequest(transport, new RequestActivityPolicy(isDistributedTracingEnabled: false, "Microsoft.Azure.Core.Cool.Tests")); Assert.AreEqual(0, testListener.Events.Count); } diff --git a/sdk/core/Azure.Core/tests/TestFramework/ClientDiagnosticListener.cs b/sdk/core/Azure.Core/tests/TestFramework/ClientDiagnosticListener.cs index b0b78e1ad0665..be93836cc6cd2 100644 --- a/sdk/core/Azure.Core/tests/TestFramework/ClientDiagnosticListener.cs +++ b/sdk/core/Azure.Core/tests/TestFramework/ClientDiagnosticListener.cs @@ -11,7 +11,7 @@ namespace Azure.Core.Tests { public class ClientDiagnosticListener : IObserver>, IObserver, IDisposable { - private readonly string _diagnosticSourceName; + private readonly Func _sourceNameFilter; private List _subscriptions = new List(); @@ -19,7 +19,13 @@ public class ClientDiagnosticListener : IObserver>, public ClientDiagnosticListener(string name) { - _diagnosticSourceName = name; + _sourceNameFilter = n => n == name; + DiagnosticListener.AllListeners.Subscribe(this); + } + + public ClientDiagnosticListener(Func filter) + { + _sourceNameFilter = filter; DiagnosticListener.AllListeners.Subscribe(this); } @@ -51,6 +57,7 @@ public void OnNext(KeyValuePair value) Activity = Activity.Current, Links = links.Select(a => a.ParentId).ToList() }; + Scopes.Add(scope); } else if (value.Key.EndsWith(stopSuffix)) @@ -71,14 +78,14 @@ public void OnNext(KeyValuePair value) var name = value.Key.Substring(0, value.Key.Length - exceptionSuffix.Length); foreach (ProducedDiagnosticScope producedDiagnosticScope in Scopes) { - if (producedDiagnosticScope.IsCompleted) + if (producedDiagnosticScope.Activity.Id == Activity.Current.Id) { - throw new InvalidOperationException("Scope should not be stopped when calling Failed"); - } + if (producedDiagnosticScope.IsCompleted) + { + throw new InvalidOperationException("Scope should not be stopped when calling Failed"); + } - if (producedDiagnosticScope.Name == name) - { - producedDiagnosticScope.Exception = (Exception)value.Value; + producedDiagnosticScope.Exception = (Exception) value.Value; } } } @@ -88,7 +95,7 @@ public void OnNext(KeyValuePair value) public void OnNext(DiagnosticListener value) { List subscriptions = _subscriptions; - if (value.Name == _diagnosticSourceName && subscriptions != null) + if (_sourceNameFilter(value.Name) && subscriptions != null) { lock (subscriptions) { @@ -99,6 +106,11 @@ public void OnNext(DiagnosticListener value) public void Dispose() { + if (_subscriptions == null) + { + return; + } + List subscriptions; lock (_subscriptions) { @@ -115,7 +127,13 @@ public void Dispose() { if (!producedDiagnosticScope.IsCompleted) { - throw new InvalidOperationException($"'{producedDiagnosticScope.Name}' is not completed"); + // https://github.com/Azure/azure-sdk-for-net/issues/9656 + // A known issue with Azure.Core that is fixed but not all libraries are on latest Azure.Core yet + if (producedDiagnosticScope.Name == "Azure.Core.Http.Request") + { + continue; + } + throw new InvalidOperationException($"'{producedDiagnosticScope.Name}' scope is not completed"); } } } @@ -173,8 +191,14 @@ public class ProducedDiagnosticScope public string Name { get; set; } public Activity Activity { get; set; } public bool IsCompleted { get; set; } + public bool IsFailed => Exception != null; public Exception Exception { get; set; } public List Links { get; set; } = new List(); + + public override string ToString() + { + return Name; + } } } } diff --git a/sdk/core/Azure.Core/tests/TestFramework/DiagnosticScopeValidatingInterceptor.cs b/sdk/core/Azure.Core/tests/TestFramework/DiagnosticScopeValidatingInterceptor.cs index f8a04bfc8ad15..0c3eeb8636aa6 100644 --- a/sdk/core/Azure.Core/tests/TestFramework/DiagnosticScopeValidatingInterceptor.cs +++ b/sdk/core/Azure.Core/tests/TestFramework/DiagnosticScopeValidatingInterceptor.cs @@ -21,15 +21,13 @@ public void Intercept(IInvocation invocation) { Type declaringType = invocation.Method.DeclaringType; var ns = declaringType.Namespace; - var expectedEventPrefix = declaringType.Name + "." + methodName.Substring(0, methodName.Length - 5); - var expectedEvents = new List - { - expectedEventPrefix + ".Start" - }; - - using TestDiagnosticListener diagnosticListener = new TestDiagnosticListener(s => s.Name.StartsWith("Azure.")); + var expectedName = declaringType.Name + "." + methodName.Substring(0, methodName.Length - 5); + using ClientDiagnosticListener diagnosticListener = new ClientDiagnosticListener(s => s.StartsWith("Azure.")); invocation.Proceed(); + bool expectFailure = false; + bool skipChecks = false; + bool strict = !invocation.Method.GetCustomAttributes(true).Any(a => a.GetType().FullName == "Azure.Core.ForwardsClientCallsAttribute"); if (invocation.Method.ReturnType.Name.Contains("Pageable") || invocation.Method.ReturnType.Name.Contains("IAsyncEnumerable")) @@ -54,48 +52,49 @@ public void Intercept(IInvocation invocation) getResultMethod.Invoke( getAwaiterMethod.Invoke(returnValue, Array.Empty()), Array.Empty()); - } - - expectedEvents.Add(expectedEventPrefix + ".Stop"); } catch (Exception ex) { - expectedEvents.Add(expectedEventPrefix + ".Exception"); + expectFailure = true; if (ex is ArgumentException) { // Don't expect scope for argument validation failures - expectedEvents.Clear(); + skipChecks = true; } } finally { // Remove subscribers before enumerating events. diagnosticListener.Dispose(); - - if (strict) + if (!skipChecks) { - foreach (var expectedEvent in expectedEvents) + if (strict) { - (string Key, object Value, DiagnosticListener Listener) e = diagnosticListener.Events.FirstOrDefault(e => e.Key == expectedEvent); + ClientDiagnosticListener.ProducedDiagnosticScope e = diagnosticListener.Scopes.FirstOrDefault(e => e.Name == expectedName); if (e == default) { - throw new InvalidOperationException($"Expected diagnostic event not fired {expectedEvent} {Environment.NewLine} fired events {string.Join(", ", diagnosticListener.Events)} {Environment.NewLine} You may have forgotten to set your operationId to {expectedEvent} in {methodName} or applied the Azure.Core.ForwardsClientCallsAttribute to {methodName}."); + throw new InvalidOperationException($"Expected diagnostic scope not created {expectedName} {Environment.NewLine} created scopes {string.Join(", ", diagnosticListener.Scopes)} {Environment.NewLine} You may have forgotten to set your operationId to {expectedName} in {methodName} or applied the Azure.Core.ForwardsClientCallsAttribute to {methodName}."); + } + + if (!e.Activity.Tags.Any(tag => tag.Key == "az.namespace")) + { + throw new InvalidOperationException($"All diagnostic scopes should have 'az.namespace' attribute, make sure the assembly containing **ClientOptions type is marked with AzureResourceProviderNamespaceAttribute"); } - if (!ns.StartsWith(e.Listener.Name)) + if (expectFailure && !e.IsFailed) { - throw new InvalidOperationException($"{e.Key} event was written into wrong DiagnosticSource {e.Listener.Name}, expected: {ns}"); + throw new InvalidOperationException($"Expected scope {expectedName} to be marked as failed but it succeeded"); } } - } - else - { - if (!diagnosticListener.Events.Any()) + else { - throw new InvalidOperationException($"Expected some diagnostic event to fire found none"); + if (!diagnosticListener.Scopes.Any()) + { + throw new InvalidOperationException($"Expected some diagnostic scopes to be created, found none"); + } } } } @@ -106,4 +105,4 @@ public void Intercept(IInvocation invocation) } } } -} +} \ No newline at end of file diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Diagnostics/EventDataInstrumentation.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Diagnostics/EventDataInstrumentation.cs index 21b79dab23c11..9638934bab1bd 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Diagnostics/EventDataInstrumentation.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Diagnostics/EventDataInstrumentation.cs @@ -14,7 +14,7 @@ namespace Azure.Messaging.EventHubs.Diagnostics internal static class EventDataInstrumentation { /// The client diagnostics instance responsible for managing scope. - public static ClientDiagnostics ClientDiagnostics { get; } = new ClientDiagnostics("Azure.Messaging.EventHubs", true); + public static ClientDiagnostics ClientDiagnostics { get; } = new ClientDiagnostics("Azure.Messaging.EventHubs", "Microsoft.EventHub", true); /// /// Applies diagnostics instrumentation to a given event. diff --git a/sdk/identity/Azure.Identity/src/Azure.Identity.csproj b/sdk/identity/Azure.Identity/src/Azure.Identity.csproj index 9db15cb598941..e5455d1fffe07 100644 --- a/sdk/identity/Azure.Identity/src/Azure.Identity.csproj +++ b/sdk/identity/Azure.Identity/src/Azure.Identity.csproj @@ -22,6 +22,7 @@ + diff --git a/sdk/identity/Azure.Identity/src/Properties/AssemblyInfo.cs b/sdk/identity/Azure.Identity/src/Properties/AssemblyInfo.cs index 71a3eac179453..7a9d2b3c29834 100644 --- a/sdk/identity/Azure.Identity/src/Properties/AssemblyInfo.cs +++ b/sdk/identity/Azure.Identity/src/Properties/AssemblyInfo.cs @@ -6,3 +6,4 @@ [assembly: InternalsVisibleTo("Microsoft.Extensions.Azure.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d15ddcb29688295338af4b7686603fe614abd555e09efba8fb88ee09e1f7b1ccaeed2e8f823fa9eef3fdd60217fc012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593daa7b11b4")] [assembly: InternalsVisibleTo("Azure.Identity.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d15ddcb29688295338af4b7686603fe614abd555e09efba8fb88ee09e1f7b1ccaeed2e8f823fa9eef3fdd60217fc012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593daa7b11b4")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.ManagedIdentity")] \ No newline at end of file diff --git a/sdk/keyvault/Azure.Security.KeyVault.Certificates/src/Azure.Security.KeyVault.Certificates.csproj b/sdk/keyvault/Azure.Security.KeyVault.Certificates/src/Azure.Security.KeyVault.Certificates.csproj index fd6837d2cca68..9976581052781 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Certificates/src/Azure.Security.KeyVault.Certificates.csproj +++ b/sdk/keyvault/Azure.Security.KeyVault.Certificates/src/Azure.Security.KeyVault.Certificates.csproj @@ -25,6 +25,7 @@ + diff --git a/sdk/keyvault/Azure.Security.KeyVault.Certificates/src/Properties/AssemblyInfo.cs b/sdk/keyvault/Azure.Security.KeyVault.Certificates/src/Properties/AssemblyInfo.cs index a609ae08a2276..03b8e87b74be4 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Certificates/src/Properties/AssemblyInfo.cs +++ b/sdk/keyvault/Azure.Security.KeyVault.Certificates/src/Properties/AssemblyInfo.cs @@ -5,3 +5,4 @@ [assembly: InternalsVisibleTo("Azure.Security.KeyVault.Certificates.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d15ddcb29688295338af4b7686603fe614abd555e09efba8fb88ee09e1f7b1ccaeed2e8f823fa9eef3fdd60217fc012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593daa7b11b4")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.KeyVault")] \ No newline at end of file diff --git a/sdk/keyvault/Azure.Security.KeyVault.Keys/src/Azure.Security.KeyVault.Keys.csproj b/sdk/keyvault/Azure.Security.KeyVault.Keys/src/Azure.Security.KeyVault.Keys.csproj index 18ad5df5abd68..13247a513ed89 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Keys/src/Azure.Security.KeyVault.Keys.csproj +++ b/sdk/keyvault/Azure.Security.KeyVault.Keys/src/Azure.Security.KeyVault.Keys.csproj @@ -27,6 +27,7 @@ + diff --git a/sdk/keyvault/Azure.Security.KeyVault.Keys/src/Properties/AssemblyInfo.cs b/sdk/keyvault/Azure.Security.KeyVault.Keys/src/Properties/AssemblyInfo.cs index 2cec053ee8bed..5a4e797676959 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Keys/src/Properties/AssemblyInfo.cs +++ b/sdk/keyvault/Azure.Security.KeyVault.Keys/src/Properties/AssemblyInfo.cs @@ -5,3 +5,4 @@ [assembly: InternalsVisibleTo("Azure.Security.KeyVault.Keys.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d15ddcb29688295338af4b7686603fe614abd555e09efba8fb88ee09e1f7b1ccaeed2e8f823fa9eef3fdd60217fc012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593daa7b11b4")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.KeyVault")] \ No newline at end of file diff --git a/sdk/keyvault/Azure.Security.KeyVault.Secrets/src/Azure.Security.KeyVault.Secrets.csproj b/sdk/keyvault/Azure.Security.KeyVault.Secrets/src/Azure.Security.KeyVault.Secrets.csproj index 57602d5cbf645..f92411cf23242 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Secrets/src/Azure.Security.KeyVault.Secrets.csproj +++ b/sdk/keyvault/Azure.Security.KeyVault.Secrets/src/Azure.Security.KeyVault.Secrets.csproj @@ -26,6 +26,7 @@ + diff --git a/sdk/keyvault/Azure.Security.KeyVault.Secrets/src/Properties/AssemblyInfo.cs b/sdk/keyvault/Azure.Security.KeyVault.Secrets/src/Properties/AssemblyInfo.cs index 2e60f26ab1405..abdacc44c67fe 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Secrets/src/Properties/AssemblyInfo.cs +++ b/sdk/keyvault/Azure.Security.KeyVault.Secrets/src/Properties/AssemblyInfo.cs @@ -4,3 +4,4 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Azure.Security.KeyVault.Secrets.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d15ddcb29688295338af4b7686603fe614abd555e09efba8fb88ee09e1f7b1ccaeed2e8f823fa9eef3fdd60217fc012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593daa7b11b4")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.KeyVault")] \ No newline at end of file diff --git a/sdk/storage/Azure.Storage.Blobs.Batch/src/AssemblyInfo.cs b/sdk/storage/Azure.Storage.Blobs.Batch/src/AssemblyInfo.cs index da220a690e74d..9e9f9f15eba79 100644 --- a/sdk/storage/Azure.Storage.Blobs.Batch/src/AssemblyInfo.cs +++ b/sdk/storage/Azure.Storage.Blobs.Batch/src/AssemblyInfo.cs @@ -9,3 +9,4 @@ "012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265" + "e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593d" + "aa7b11b4")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.Storage")] \ No newline at end of file diff --git a/sdk/storage/Azure.Storage.Blobs.Batch/src/Azure.Storage.Blobs.Batch.csproj b/sdk/storage/Azure.Storage.Blobs.Batch/src/Azure.Storage.Blobs.Batch.csproj index cc82a2e14c176..004818789202c 100644 --- a/sdk/storage/Azure.Storage.Blobs.Batch/src/Azure.Storage.Blobs.Batch.csproj +++ b/sdk/storage/Azure.Storage.Blobs.Batch/src/Azure.Storage.Blobs.Batch.csproj @@ -22,6 +22,7 @@ + diff --git a/sdk/storage/Azure.Storage.Blobs/src/AssemblyInfo.cs b/sdk/storage/Azure.Storage.Blobs/src/AssemblyInfo.cs index 588a241a7f09c..014bf8d8af384 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/AssemblyInfo.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/AssemblyInfo.cs @@ -9,3 +9,4 @@ "e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593d" + "aa7b11b4")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.Storage")] \ No newline at end of file diff --git a/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj b/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj index de0f444bb4785..76e0b23d420ea 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj +++ b/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj @@ -20,6 +20,7 @@ + diff --git a/sdk/storage/Azure.Storage.Files.DataLake/src/AssemblyInfo.cs b/sdk/storage/Azure.Storage.Files.DataLake/src/AssemblyInfo.cs index ab700ce5bdf82..f0b556ac3a02c 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/src/AssemblyInfo.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/src/AssemblyInfo.cs @@ -10,3 +10,4 @@ "e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593d" + "aa7b11b4")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.DataLakeStore")] \ No newline at end of file diff --git a/sdk/storage/Azure.Storage.Files.DataLake/src/Azure.Storage.Files.DataLake.csproj b/sdk/storage/Azure.Storage.Files.DataLake/src/Azure.Storage.Files.DataLake.csproj index b628e5d1529e5..58ce9dfee2d87 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/src/Azure.Storage.Files.DataLake.csproj +++ b/sdk/storage/Azure.Storage.Files.DataLake/src/Azure.Storage.Files.DataLake.csproj @@ -26,6 +26,7 @@ + diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/AssemblyInfo.cs b/sdk/storage/Azure.Storage.Files.Shares/src/AssemblyInfo.cs index e63096c1f9d1d..f10621168ea56 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/AssemblyInfo.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/AssemblyInfo.cs @@ -10,3 +10,4 @@ "e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593d" + "aa7b11b4")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.Storage")] \ No newline at end of file diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj b/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj index 6aef9b1a41285..8038499575a52 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj @@ -24,6 +24,7 @@ + diff --git a/sdk/storage/Azure.Storage.Queues/src/AssemblyInfo.cs b/sdk/storage/Azure.Storage.Queues/src/AssemblyInfo.cs index 930058417359f..84457751c42bb 100644 --- a/sdk/storage/Azure.Storage.Queues/src/AssemblyInfo.cs +++ b/sdk/storage/Azure.Storage.Queues/src/AssemblyInfo.cs @@ -10,3 +10,4 @@ "e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593d" + "aa7b11b4")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.Storage")] \ No newline at end of file diff --git a/sdk/storage/Azure.Storage.Queues/src/Azure.Storage.Queues.csproj b/sdk/storage/Azure.Storage.Queues/src/Azure.Storage.Queues.csproj index 967d5556fcdab..c85b9dcef0a62 100644 --- a/sdk/storage/Azure.Storage.Queues/src/Azure.Storage.Queues.csproj +++ b/sdk/storage/Azure.Storage.Queues/src/Azure.Storage.Queues.csproj @@ -19,6 +19,7 @@ + diff --git a/sdk/textanalytics/Azure.AI.TextAnalytics/src/Azure.AI.TextAnalytics.csproj b/sdk/textanalytics/Azure.AI.TextAnalytics/src/Azure.AI.TextAnalytics.csproj index 366439e5ce558..70ed0813dda4d 100644 --- a/sdk/textanalytics/Azure.AI.TextAnalytics/src/Azure.AI.TextAnalytics.csproj +++ b/sdk/textanalytics/Azure.AI.TextAnalytics/src/Azure.AI.TextAnalytics.csproj @@ -21,6 +21,7 @@ + diff --git a/sdk/textanalytics/Azure.AI.TextAnalytics/src/Properties/AssemblyInfo.cs b/sdk/textanalytics/Azure.AI.TextAnalytics/src/Properties/AssemblyInfo.cs index 2933fbcb4521f..a5ec8d7cb5ab1 100644 --- a/sdk/textanalytics/Azure.AI.TextAnalytics/src/Properties/AssemblyInfo.cs +++ b/sdk/textanalytics/Azure.AI.TextAnalytics/src/Properties/AssemblyInfo.cs @@ -7,3 +7,4 @@ // See https://github.com/castleproject/Core/blob/master/src/Castle.Core/Core/Internal/InternalsVisible.cs for values [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.CognitiveServices")] \ No newline at end of file