diff --git a/CHANGELOG.md b/CHANGELOG.md index 6997ef0..2f4bfdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change log +## 2.2.0 (2024-10-10) + - Create traces using the SDK observability APIs for the S3 Encryption Encryption and Decryption pipeline handlers. + ## 2.1.2 (2024-09-03) - Fixed issue with AmazonS3EncryptionClientV2 and uploading multipart objects triggering a "HashStream does not support base streams that are not capable of reading or writing" error. diff --git a/src/Amazon.Extensions.S3.Encryption.csproj b/src/Amazon.Extensions.S3.Encryption.csproj index 2687e7a..06a2d06 100644 --- a/src/Amazon.Extensions.S3.Encryption.csproj +++ b/src/Amazon.Extensions.S3.Encryption.csproj @@ -2,7 +2,7 @@ net35;net45;netstandard2.0;netcoreapp3.1 - 2.1.2 + 2.2.0 true Amazon.Extensions.S3.Encryption Amazon S3 Encryption Client for .NET @@ -15,8 +15,8 @@ icon.png https://github.com/aws/amazon-s3-encryption-client-dotnet/ Amazon Web Services - 2.1.2 - 2.1.2 + 2.2.0 + 2.2.0 true ..\public.snk @@ -41,9 +41,9 @@ - - - + + + diff --git a/src/Internal/SetupDecryptionHandler.cs b/src/Internal/SetupDecryptionHandler.cs index 3ec9559..653358a 100644 --- a/src/Internal/SetupDecryptionHandler.cs +++ b/src/Internal/SetupDecryptionHandler.cs @@ -6,6 +6,7 @@ using Amazon.Runtime.Internal; using Amazon.S3; using GetObjectResponse = Amazon.S3.Model.GetObjectResponse; +using Amazon.Extensions.S3.Encryption.Util; namespace Amazon.Extensions.S3.Encryption.Internal { @@ -50,41 +51,44 @@ public override void InvokeSync(IExecutionContext executionContext) /// protected void PostInvoke(IExecutionContext executionContext) { - byte[] encryptedKMSEnvelopeKey; - Dictionary encryptionContext; - byte[] decryptedEnvelopeKeyKMS = null; - - if (KMSEnvelopeKeyIsPresent(executionContext, out encryptedKMSEnvelopeKey, out encryptionContext)) + using (TelemetryUtilities.CreateSpan(EncryptionClient, Constants.SetupDecryptionHandlerSpanName, null, Amazon.Runtime.Telemetry.Tracing.SpanKind.CLIENT)) { + byte[] encryptedKMSEnvelopeKey; + Dictionary encryptionContext; + byte[] decryptedEnvelopeKeyKMS = null; + + if (KMSEnvelopeKeyIsPresent(executionContext, out encryptedKMSEnvelopeKey, out encryptionContext)) + { #if BCL decryptedEnvelopeKeyKMS = DecryptedEnvelopeKeyKms(encryptedKMSEnvelopeKey, encryptionContext); #else - decryptedEnvelopeKeyKMS = DecryptedEnvelopeKeyKmsAsync(encryptedKMSEnvelopeKey, encryptionContext).GetAwaiter().GetResult(); + decryptedEnvelopeKeyKMS = DecryptedEnvelopeKeyKmsAsync(encryptedKMSEnvelopeKey, encryptionContext).GetAwaiter().GetResult(); #endif - } + } - var getObjectResponse = executionContext.ResponseContext.Response as GetObjectResponse; - if (getObjectResponse != null) - { + var getObjectResponse = executionContext.ResponseContext.Response as GetObjectResponse; + if (getObjectResponse != null) + { #if BCL DecryptObject(decryptedEnvelopeKeyKMS, getObjectResponse); #else - DecryptObjectAsync(decryptedEnvelopeKeyKMS, getObjectResponse).GetAwaiter().GetResult(); + DecryptObjectAsync(decryptedEnvelopeKeyKMS, getObjectResponse).GetAwaiter().GetResult(); #endif - } + } - var completeMultiPartUploadRequest = executionContext.RequestContext.Request.OriginalRequest as CompleteMultipartUploadRequest; - var completeMultipartUploadResponse = executionContext.ResponseContext.Response as CompleteMultipartUploadResponse; - if (completeMultipartUploadResponse != null) - { + var completeMultiPartUploadRequest = executionContext.RequestContext.Request.OriginalRequest as CompleteMultipartUploadRequest; + var completeMultipartUploadResponse = executionContext.ResponseContext.Response as CompleteMultipartUploadResponse; + if (completeMultipartUploadResponse != null) + { #if BCL CompleteMultipartUpload(completeMultiPartUploadRequest); #else - CompleteMultipartUploadAsync(completeMultiPartUploadRequest).GetAwaiter().GetResult(); + CompleteMultipartUploadAsync(completeMultiPartUploadRequest).GetAwaiter().GetResult(); #endif - } + } - PostInvokeSynchronous(executionContext, decryptedEnvelopeKeyKMS); + PostInvokeSynchronous(executionContext, decryptedEnvelopeKeyKMS); + } } #if BCL @@ -130,29 +134,32 @@ public override async System.Threading.Tasks.Task InvokeAsync(IExecutionCo /// The execution context, it contains the request and response context. protected async System.Threading.Tasks.Task PostInvokeAsync(IExecutionContext executionContext) { - byte[] encryptedKMSEnvelopeKey; - Dictionary encryptionContext; - byte[] decryptedEnvelopeKeyKMS = null; - - if (KMSEnvelopeKeyIsPresent(executionContext, out encryptedKMSEnvelopeKey, out encryptionContext)) + using (TelemetryUtilities.CreateSpan(EncryptionClient, Constants.SetupDecryptionHandlerSpanName, null, Amazon.Runtime.Telemetry.Tracing.SpanKind.CLIENT)) { - decryptedEnvelopeKeyKMS = await DecryptedEnvelopeKeyKmsAsync(encryptedKMSEnvelopeKey, encryptionContext).ConfigureAwait(false); - } + byte[] encryptedKMSEnvelopeKey; + Dictionary encryptionContext; + byte[] decryptedEnvelopeKeyKMS = null; - var getObjectResponse = executionContext.ResponseContext.Response as GetObjectResponse; - if (getObjectResponse != null) - { - await DecryptObjectAsync(decryptedEnvelopeKeyKMS, getObjectResponse).ConfigureAwait(false); - } + if (KMSEnvelopeKeyIsPresent(executionContext, out encryptedKMSEnvelopeKey, out encryptionContext)) + { + decryptedEnvelopeKeyKMS = await DecryptedEnvelopeKeyKmsAsync(encryptedKMSEnvelopeKey, encryptionContext).ConfigureAwait(false); + } - var completeMultiPartUploadRequest = executionContext.RequestContext.Request.OriginalRequest as CompleteMultipartUploadRequest; - var completeMultipartUploadResponse = executionContext.ResponseContext.Response as CompleteMultipartUploadResponse; - if (completeMultipartUploadResponse != null) - { - await CompleteMultipartUploadAsync(completeMultiPartUploadRequest).ConfigureAwait(false); - } + var getObjectResponse = executionContext.ResponseContext.Response as GetObjectResponse; + if (getObjectResponse != null) + { + await DecryptObjectAsync(decryptedEnvelopeKeyKMS, getObjectResponse).ConfigureAwait(false); + } - PostInvokeSynchronous(executionContext, decryptedEnvelopeKeyKMS); + var completeMultiPartUploadRequest = executionContext.RequestContext.Request.OriginalRequest as CompleteMultipartUploadRequest; + var completeMultipartUploadResponse = executionContext.ResponseContext.Response as CompleteMultipartUploadResponse; + if (completeMultipartUploadResponse != null) + { + await CompleteMultipartUploadAsync(completeMultiPartUploadRequest).ConfigureAwait(false); + } + + PostInvokeSynchronous(executionContext, decryptedEnvelopeKeyKMS); + } } /// diff --git a/src/Internal/SetupEncryptionHandler.cs b/src/Internal/SetupEncryptionHandler.cs index a230527..97b8181 100644 --- a/src/Internal/SetupEncryptionHandler.cs +++ b/src/Internal/SetupEncryptionHandler.cs @@ -3,6 +3,7 @@ using Amazon.Runtime; using Amazon.S3.Model; using Amazon.Runtime.Internal; +using Amazon.Extensions.S3.Encryption.Util; namespace Amazon.Extensions.S3.Encryption.Internal { @@ -49,19 +50,22 @@ protected void PreInvoke(IExecutionContext executionContext) { ThrowIfRangeGet(executionContext); - var instructions = GenerateInstructions(executionContext); - - var putObjectRequest = executionContext.RequestContext.OriginalRequest as PutObjectRequest; - if (putObjectRequest != null) + using (TelemetryUtilities.CreateSpan(EncryptionClient, Constants.SetupEncryptionHandlerSpanName, null, Amazon.Runtime.Telemetry.Tracing.SpanKind.CLIENT)) { + var instructions = GenerateInstructions(executionContext); + + var putObjectRequest = executionContext.RequestContext.OriginalRequest as PutObjectRequest; + if (putObjectRequest != null) + { #if BCL - EncryptObject(instructions, putObjectRequest); + EncryptObject(instructions, putObjectRequest); #else - EncryptObjectAsync(instructions, putObjectRequest).GetAwaiter().GetResult(); + EncryptObjectAsync(instructions, putObjectRequest).GetAwaiter().GetResult(); #endif - } + } - PreInvokeSynchronous(executionContext, instructions); + PreInvokeSynchronous(executionContext, instructions); + } } #if BCL @@ -125,18 +129,20 @@ public override async System.Threading.Tasks.Task InvokeAsync(IExecutionCo protected async System.Threading.Tasks.Task PreInvokeAsync(IExecutionContext executionContext) { ThrowIfRangeGet(executionContext); + using (TelemetryUtilities.CreateSpan(EncryptionClient, Constants.SetupEncryptionHandlerSpanName, null, Amazon.Runtime.Telemetry.Tracing.SpanKind.CLIENT)) + { + EncryptionInstructions instructions = await GenerateInstructionsAsync(executionContext).ConfigureAwait(false); - EncryptionInstructions instructions = await GenerateInstructionsAsync(executionContext).ConfigureAwait(false); + var request = executionContext.RequestContext.OriginalRequest; - var request = executionContext.RequestContext.OriginalRequest; + var putObjectRequest = request as PutObjectRequest; + if (putObjectRequest != null) + { + await EncryptObjectAsync(instructions, putObjectRequest).ConfigureAwait(false); + } - var putObjectRequest = request as PutObjectRequest; - if (putObjectRequest != null) - { - await EncryptObjectAsync(instructions, putObjectRequest).ConfigureAwait(false); + PreInvokeSynchronous(executionContext, instructions); } - - PreInvokeSynchronous(executionContext, instructions); } private async System.Threading.Tasks.Task EncryptObjectAsync(EncryptionInstructions instructions, PutObjectRequest putObjectRequest) diff --git a/src/Util/Constants.cs b/src/Util/Constants.cs index 1e031fc..e3c5fa8 100644 --- a/src/Util/Constants.cs +++ b/src/Util/Constants.cs @@ -17,5 +17,10 @@ namespace Amazon.Extensions.S3.Encryption.Util internal class Constants { internal const string S3CryptoStreamRequestState = "S3-Crypto-Stream"; + + + internal const string S3TransferTracerScope = "S3.Encryption"; + internal const string SetupEncryptionHandlerSpanName = "EncryptionHandler"; + internal const string SetupDecryptionHandlerSpanName = "DecryptionHandler"; } } diff --git a/src/Util/TelemetryUtilities.cs b/src/Util/TelemetryUtilities.cs new file mode 100644 index 0000000..88dadf7 --- /dev/null +++ b/src/Util/TelemetryUtilities.cs @@ -0,0 +1,43 @@ +using Amazon.S3.Transfer; +using Amazon.Runtime.Telemetry.Tracing; +using Amazon.Runtime.Telemetry; +using Attributes = Amazon.Runtime.Telemetry.Attributes; +using Amazon.S3; + +namespace Amazon.Extensions.S3.Encryption.Util +{ + internal static class TelemetryUtilities + { + /// + /// Creates a new span with the required attributes. + /// + /// The name of the operation from which to create the span name. + /// Optional initial set of attributes for the span. + /// Optional type of span to create. + /// Optional parent context for the span. + /// A instance representing the created span. + internal static TraceSpan CreateSpan( + AmazonS3Client client, + string operationName, + Attributes initialAttributes = null, + SpanKind spanKind = SpanKind.INTERNAL, + SpanContext parentContext = null) + { + if (initialAttributes == null) + initialAttributes = new Attributes(); + + initialAttributes.Set(TelemetryConstants.MethodAttributeKey, operationName); + + initialAttributes.Set(TelemetryConstants.SystemAttributeKey, TelemetryConstants.SystemAttributeValue); + initialAttributes.Set(TelemetryConstants.ServiceAttributeKey, Constants.S3TransferTracerScope); + + var spanName = $"{nameof(TransferUtility)}.{operationName}"; + + var tracerProvider = client.Config.TelemetryProvider.TracerProvider; + + var tracer = tracerProvider.GetTracer($"{TelemetryConstants.TelemetryScopePrefix}.{Constants.S3TransferTracerScope}"); + + return tracer.CreateSpan(spanName, initialAttributes, spanKind, parentContext); + } + } +}