diff --git a/sdk/core/Azure.Core/src/ClientOptions.cs b/sdk/core/Azure.Core/src/ClientOptions.cs index ed471549dd38..875bd41c2758 100644 --- a/sdk/core/Azure.Core/src/ClientOptions.cs +++ b/sdk/core/Azure.Core/src/ClientOptions.cs @@ -99,6 +99,8 @@ public void AddPolicy(HttpPipelinePolicy policy, HttpPipelinePosition position) internal List<(HttpPipelinePosition Position, HttpPipelinePolicy Policy)>? Policies { get; private set; } + internal ClientDiagnostics? ClientDiagnostics { get; set; } + /// [EditorBrowsable(EditorBrowsableState.Never)] public override bool Equals(object? obj) => base.Equals(obj); diff --git a/sdk/core/Azure.Core/src/DefaultClientOptions.cs b/sdk/core/Azure.Core/src/DefaultClientOptions.cs index 5b7f6458338b..a23ec18c0771 100644 --- a/sdk/core/Azure.Core/src/DefaultClientOptions.cs +++ b/sdk/core/Azure.Core/src/DefaultClientOptions.cs @@ -11,6 +11,7 @@ internal class DefaultClientOptions: ClientOptions public DefaultClientOptions(): base(null) { Transport = GetDefaultTransport(); + Transport.ClientDiagnostics = base.ClientDiagnostics; Diagnostics.IsTelemetryEnabled = !EnvironmentVariableToBool(Environment.GetEnvironmentVariable("AZURE_TELEMETRY_DISABLED")) ?? true; Diagnostics.IsDistributedTracingEnabled = !EnvironmentVariableToBool(Environment.GetEnvironmentVariable("AZURE_TRACING_DISABLED")) ?? true; } @@ -45,4 +46,4 @@ private static HttpPipelineTransport GetDefaultTransport() return HttpClientTransport.Shared; } } -} \ No newline at end of file +} diff --git a/sdk/core/Azure.Core/src/Pipeline/HttpClientTransport.cs b/sdk/core/Azure.Core/src/Pipeline/HttpClientTransport.cs index e51dd0eb5132..322bddc0a793 100644 --- a/sdk/core/Azure.Core/src/Pipeline/HttpClientTransport.cs +++ b/sdk/core/Azure.Core/src/Pipeline/HttpClientTransport.cs @@ -129,7 +129,7 @@ private async ValueTask ProcessAsync(HttpMessage message, bool async) throw new RequestFailedException(e.Message, e); } - message.Response = new PipelineResponse(message.Request.ClientRequestId, responseMessage, contentStream); + message.Response = new PipelineResponse(message.Request.ClientRequestId, responseMessage, contentStream, this.ClientDiagnostics!); } private static HttpClient CreateDefaultClient() @@ -500,12 +500,13 @@ private sealed class PipelineResponse : Response private Stream? _contentStream; #pragma warning restore CA2213 - public PipelineResponse(string requestId, HttpResponseMessage responseMessage, Stream? contentStream) + public PipelineResponse(string requestId, HttpResponseMessage responseMessage, Stream? contentStream, ClientDiagnostics diagnostics) { ClientRequestId = requestId ?? throw new ArgumentNullException(nameof(requestId)); _responseMessage = responseMessage ?? throw new ArgumentNullException(nameof(responseMessage)); _contentStream = contentStream; _responseContent = _responseMessage.Content; + ClientDiagnostics = diagnostics; } public override int Status => (int)_responseMessage.StatusCode; diff --git a/sdk/core/Azure.Core/src/Pipeline/HttpPipelineBuilder.cs b/sdk/core/Azure.Core/src/Pipeline/HttpPipelineBuilder.cs index c434652c3aee..ae821ad1f829 100644 --- a/sdk/core/Azure.Core/src/Pipeline/HttpPipelineBuilder.cs +++ b/sdk/core/Azure.Core/src/Pipeline/HttpPipelineBuilder.cs @@ -104,6 +104,7 @@ void AddCustomerPolicies(HttpPipelinePosition position) policies.RemoveAll(static policy => policy == null); + options.Transport.ClientDiagnostics = options.ClientDiagnostics; return new HttpPipeline(options.Transport, policies.ToArray(), responseClassifier); diff --git a/sdk/core/Azure.Core/src/Pipeline/HttpPipelineTransport.cs b/sdk/core/Azure.Core/src/Pipeline/HttpPipelineTransport.cs index 42c9c8af5bfa..8fbf929cfeec 100644 --- a/sdk/core/Azure.Core/src/Pipeline/HttpPipelineTransport.cs +++ b/sdk/core/Azure.Core/src/Pipeline/HttpPipelineTransport.cs @@ -28,5 +28,7 @@ public abstract class HttpPipelineTransport /// /// public abstract Request CreateRequest(); + + internal ClientDiagnostics? ClientDiagnostics { get; set; } } } diff --git a/sdk/core/Azure.Core/src/Pipeline/HttpWebRequestTransport.cs b/sdk/core/Azure.Core/src/Pipeline/HttpWebRequestTransport.cs index d932c4bd050f..e388950dbcef 100644 --- a/sdk/core/Azure.Core/src/Pipeline/HttpWebRequestTransport.cs +++ b/sdk/core/Azure.Core/src/Pipeline/HttpWebRequestTransport.cs @@ -90,7 +90,7 @@ private async ValueTask ProcessInternal(HttpMessage message, bool async) webResponse = exception.Response; } - message.Response = new HttpWebResponseImplementation(message.Request.ClientRequestId, (HttpWebResponse)webResponse); + message.Response = new HttpWebResponseImplementation(message.Request.ClientRequestId, (HttpWebResponse)webResponse, this.ClientDiagnostics!); } // ObjectDisposedException might be thrown if the request is aborted during the content upload via SSL catch (ObjectDisposedException) when (message.CancellationToken.IsCancellationRequested) @@ -245,12 +245,13 @@ private sealed class HttpWebResponseImplementation : Response private Stream? _contentStream; private Stream? _originalContentStream; - public HttpWebResponseImplementation(string clientRequestId, HttpWebResponse webResponse) + public HttpWebResponseImplementation(string clientRequestId, HttpWebResponse webResponse, ClientDiagnostics clientDiagnostics) { _webResponse = webResponse; _originalContentStream = _webResponse.GetResponseStream(); _contentStream = _originalContentStream; ClientRequestId = clientRequestId; + ClientDiagnostics = clientDiagnostics; } public override int Status => (int)_webResponse.StatusCode; diff --git a/sdk/core/Azure.Core/src/Response.cs b/sdk/core/Azure.Core/src/Response.cs index af2c3596a955..055ab9ba577f 100644 --- a/sdk/core/Azure.Core/src/Response.cs +++ b/sdk/core/Azure.Core/src/Response.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using Azure.Core; +using Azure.Core.Pipeline; namespace Azure { @@ -36,6 +37,8 @@ public abstract class Response : IDisposable /// public abstract string ClientRequestId { get; set; } + internal ClientDiagnostics? ClientDiagnostics { get; set; } + /// /// Get the HTTP response headers. /// @@ -132,6 +135,14 @@ public override string ToString() return $"Status: {Status}, ReasonPhrase: {ReasonPhrase}"; } + /// + /// + public RequestFailedException GetRequestFailedException() + { + throw new NotImplementedException(); + //return this.ClientDiagnostics?.CreateRequestFailedException(this); + } + internal void DisposeContentStreamIfNotBuffered() { // We want to keep the ContentStream readable diff --git a/sdk/core/Azure.Core/src/Shared/ClientDiagnostics.cs b/sdk/core/Azure.Core/src/Shared/ClientDiagnostics.cs index a7dac8c8e88f..6c353f0accbc 100644 --- a/sdk/core/Azure.Core/src/Shared/ClientDiagnostics.cs +++ b/sdk/core/Azure.Core/src/Shared/ClientDiagnostics.cs @@ -31,6 +31,8 @@ public ClientDiagnostics(ClientOptions options) : base( _sanitizer = new HttpMessageSanitizer( options.Diagnostics.LoggedQueryParameters.ToArray(), options.Diagnostics.LoggedHeaderNames.ToArray()); + + options.ClientDiagnostics = this; } /// diff --git a/sdk/synapse/Azure.Analytics.Synapse.AccessControl/src/Models/SynapseRoleAssignment.cs b/sdk/synapse/Azure.Analytics.Synapse.AccessControl/src/Models/SynapseRoleAssignment.cs index d83b721e7b72..eb6d640bb367 100644 --- a/sdk/synapse/Azure.Analytics.Synapse.AccessControl/src/Models/SynapseRoleAssignment.cs +++ b/sdk/synapse/Azure.Analytics.Synapse.AccessControl/src/Models/SynapseRoleAssignment.cs @@ -19,6 +19,7 @@ public SynapseRoleAssignment(Guid roleId, Guid principalId, string scope, Synaps // TODO: Why aren't name and type available? (Where they are available in ARM + KV APIs) //Name = name; //Type = type; + // TODO: Doesn't the principal already have a type? What if we specify the wrong type for principalType? } internal SynapseRoleAssignment(Guid roleId, Guid principalId, Guid roleDefinitionId, string scope, SynapsePrincipalType? principalType = null) @@ -41,5 +42,16 @@ public static implicit operator RequestContent(SynapseRoleAssignment value) => R Id = value.Id, Properties = value.Properties }); + + public static implicit operator SynapseRoleAssignment(Response response) + { + switch (response.Status) + { + case 200: + return response.Content.ToObjectFromJson(); + default: + throw response.GetRequestFailedException(); + } + } } } diff --git a/sdk/synapse/Azure.Analytics.Synapse.AccessControl/src/SynapseAccessControlClient.cs b/sdk/synapse/Azure.Analytics.Synapse.AccessControl/src/SynapseAccessControlClient.cs index f40585942fc1..3468a98704c3 100644 --- a/sdk/synapse/Azure.Analytics.Synapse.AccessControl/src/SynapseAccessControlClient.cs +++ b/sdk/synapse/Azure.Analytics.Synapse.AccessControl/src/SynapseAccessControlClient.cs @@ -90,45 +90,6 @@ public virtual async Task> CreateRoleAssignmentA } } -#pragma warning disable AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken. - public virtual Response CreateRoleAssignment(string roleAssignmentId, SynapseRoleAssignment roleAssignment) -#pragma warning restore AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken. - { - Argument.AssertNotNullOrEmpty(roleAssignmentId, nameof(roleAssignmentId)); - Argument.AssertNotNull(roleAssignment, nameof(roleAssignment)); - Argument.AssertNotNull(roleAssignment.Properties.Scope, nameof(roleAssignment.Properties.Scope)); - - using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(SynapseAccessControlClient)}.{nameof(CreateRoleAssignment)}"); - scope.Start(); - try - { - Response createRoleAssignmentResponse = CreateRoleAssignment( - roleAssignmentId, - RequestContent.Create( - new - { - RoleId = roleAssignment.Properties.RoleDefinitionId, - PrincipalId = roleAssignment.Properties.PrincipalId, - Scope = roleAssignment.Properties.Scope.ToString() - })); - - JsonDocument responseJson = JsonDocument.Parse(createRoleAssignmentResponse.Content.ToMemory()); - - return Response.FromValue(new SynapseRoleAssignment( - new Guid(responseJson.RootElement.GetProperty("id").ToString()), - new Guid(responseJson.RootElement.GetProperty("principalId").ToString()), - new Guid(responseJson.RootElement.GetProperty("roleDefinitionId").ToString()), - responseJson.RootElement.GetProperty("scope").ToString(), - responseJson.RootElement.GetProperty("principalType").ToString()), - createRoleAssignmentResponse); - } - catch (Exception ex) - { - scope.Failed(ex); - throw; - } - } - #pragma warning disable AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken. public virtual Response DeleteRoleAssignment(SynapseRoleScope roleScope, string roleAssignmentName) #pragma warning restore AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken. diff --git a/sdk/synapse/Azure.Analytics.Synapse.sln b/sdk/synapse/Azure.Analytics.Synapse.sln index 8be378f54fee..e7035754fa81 100644 --- a/sdk/synapse/Azure.Analytics.Synapse.sln +++ b/sdk/synapse/Azure.Analytics.Synapse.sln @@ -29,6 +29,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Analytics.Synapse.Mon EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Analytics.Synapse.Monitoring.Tests", "Azure.Analytics.Synapse.Monitoring\tests\Azure.Analytics.Synapse.Monitoring.Tests.csproj", "{729E92B7-E47B-442C-836F-27B8A7806D2F}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core", "..\core\Azure.Core\src\Azure.Core.csproj", "{AD109C43-32F7-4FAB-A867-5CEECE4242F9}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution Azure.Analytics.Synapse.Shared\tests\Azure.Analytics.Synapse.Shared.Tests.projitems*{1afa2644-a1d9-419f-b87d-9b519b673f24}*SharedItemsImports = 13 @@ -93,6 +95,10 @@ Global {729E92B7-E47B-442C-836F-27B8A7806D2F}.Debug|Any CPU.Build.0 = Debug|Any CPU {729E92B7-E47B-442C-836F-27B8A7806D2F}.Release|Any CPU.ActiveCfg = Release|Any CPU {729E92B7-E47B-442C-836F-27B8A7806D2F}.Release|Any CPU.Build.0 = Release|Any CPU + {AD109C43-32F7-4FAB-A867-5CEECE4242F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD109C43-32F7-4FAB-A867-5CEECE4242F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD109C43-32F7-4FAB-A867-5CEECE4242F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD109C43-32F7-4FAB-A867-5CEECE4242F9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE