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);
+ }
+ }
+}