From 5f13f6ec7985554a97cd903e7e89f8c64d696510 Mon Sep 17 00:00:00 2001
From: Henrique <999396+hjgraca@users.noreply.github.com>
Date: Fri, 4 Oct 2024 09:03:10 +0100
Subject: [PATCH 1/3] revert removing IMethodAspectHandler. This is needed for
async method parsing because aspect injector does not support it by default
---
...acingAspect.cs => TracingAspectHandler.cs} | 251 +++++++++---------
.../TracingAttribute.cs | 21 +-
.../Handlers/FullExampleHandler.cs | 6 +-
.../Handlers/HandlerTests.cs | 5 +-
.../TracingAttributeTest.cs | 6 +-
5 files changed, 156 insertions(+), 133 deletions(-)
rename libraries/src/AWS.Lambda.Powertools.Tracing/Internal/{TracingAspect.cs => TracingAspectHandler.cs} (57%)
diff --git a/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspect.cs b/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspectHandler.cs
similarity index 57%
rename from libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspect.cs
rename to libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspectHandler.cs
index 46062d0d..7e80ab86 100644
--- a/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspect.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspectHandler.cs
@@ -1,12 +1,12 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
- *
+ *
* http://aws.amazon.com/apache2.0
- *
+ *
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
@@ -14,20 +14,18 @@
*/
using System;
-using System.Linq;
using System.Runtime.ExceptionServices;
using System.Text;
-using AspectInjector.Broker;
using AWS.Lambda.Powertools.Common;
namespace AWS.Lambda.Powertools.Tracing.Internal;
///
-/// This aspect will automatically trace all function handlers.
-/// Scope.Global is singleton
+/// Class TracingAspectHandler.
+/// Implements the
///
-[Aspect(Scope.Global)]
-public class TracingAspect
+///
+internal class TracingAspectHandler : IMethodAspectHandler
{
///
/// The Powertools for AWS Lambda (.NET) configurations
@@ -48,130 +46,120 @@ public class TracingAspect
/// If true, capture annotations
///
private static bool _captureAnnotations = true;
-
+
///
/// If true, annotations have been captured
///
private bool _isAnnotationsCaptured;
-
+
///
/// Tracing namespace
///
private string _namespace;
-
+
///
/// The capture mode
///
private TracingCaptureMode _captureMode;
+
+ ///
+ /// The segment name
+ ///
+ private readonly string _segmentName;
///
- /// Initializes a new instance
+ /// Initializes a new instance of the class.
///
- public TracingAspect()
+ /// Name of the segment.
+ /// The namespace.
+ /// The capture mode.
+ /// The Powertools for AWS Lambda (.NET) configurations.
+ /// The X-Ray recorder.
+ internal TracingAspectHandler
+ (
+ string segmentName,
+ string nameSpace,
+ TracingCaptureMode captureMode,
+ IPowertoolsConfigurations powertoolsConfigurations,
+ IXRayRecorder xRayRecorder
+ )
{
- _xRayRecorder = XRayRecorder.Instance;
- _powertoolsConfigurations = PowertoolsConfigurations.Instance;
+ _segmentName = segmentName;
+ _namespace = nameSpace;
+ _captureMode = captureMode;
+ _powertoolsConfigurations = powertoolsConfigurations;
+ _xRayRecorder = xRayRecorder;
}
///
- /// the code is executed instead of the target method.
- /// The call to original method is wrapped around the following code
- /// the original code is called with var result = target(args);
+ /// Handles the event.
///
- ///
- ///
- ///
- ///
- ///
- [Advice(Kind.Around)]
- public object Around(
- [Argument(Source.Name)] string name,
- [Argument(Source.Arguments)] object[] args,
- [Argument(Source.Target)] Func target,
- [Argument(Source.Triggers)] Attribute[] triggers)
+ ///
+ /// The instance containing the
+ /// event data.
+ ///
+ public void OnEntry(AspectEventArgs eventArgs)
{
- // Before running Function
-
- var trigger = triggers.OfType().First();
- try
- {
- if (TracingDisabled())
- return target(args);
-
- _namespace = trigger.Namespace;
-
- var segmentName = !string.IsNullOrWhiteSpace(trigger.SegmentName) ? trigger.SegmentName : $"## {name}";
- var nameSpace = GetNamespace();
-
- _xRayRecorder.BeginSubsegment(segmentName);
- _xRayRecorder.SetNamespace(nameSpace);
-
- if (_captureAnnotations)
- {
- _xRayRecorder.AddAnnotation("ColdStart", _isColdStart);
-
- _captureAnnotations = false;
- _isAnnotationsCaptured = true;
-
- if (_powertoolsConfigurations.IsServiceDefined)
- _xRayRecorder.AddAnnotation("Service", _powertoolsConfigurations.Service);
- }
-
- _isColdStart = false;
+ if(TracingDisabled())
+ return;
- // return of the handler
- var result = target(args);
+ var segmentName = !string.IsNullOrWhiteSpace(_segmentName) ? _segmentName : $"## {eventArgs.Name}";
+ var nameSpace = GetNamespace();
- // must get capture after all subsegments run
- _captureMode = trigger.CaptureMode;
+ _xRayRecorder.BeginSubsegment(segmentName);
+ _xRayRecorder.SetNamespace(nameSpace);
- if (CaptureResponse())
- {
- _xRayRecorder.AddMetadata
- (
- nameSpace,
- $"{name} response",
- result
- );
- }
-
- // after
- return result;
- }
- catch (Exception e)
+ if (_captureAnnotations)
{
- _captureMode = trigger.CaptureMode;
- HandleException(e, name);
- throw;
+ _xRayRecorder.AddAnnotation("ColdStart", _isColdStart);
+
+ _captureAnnotations = false;
+ _isAnnotationsCaptured = true;
+
+ if (_powertoolsConfigurations.IsServiceDefined)
+ _xRayRecorder.AddAnnotation("Service", _powertoolsConfigurations.Service);
}
+
+ _isColdStart = false;
}
///
- /// the code is injected after the method ends.
+ /// Called when [success].
///
- [Advice(Kind.After)]
- public void OnExit()
+ ///
+ /// The instance containing the
+ /// event data.
+ ///
+ /// The result.
+ public void OnSuccess(AspectEventArgs eventArgs, object result)
{
- if (TracingDisabled())
- return;
-
- if (_isAnnotationsCaptured)
- _captureAnnotations = true;
-
- _xRayRecorder.EndSubsegment();
+ if (CaptureResponse())
+ {
+ var nameSpace = GetNamespace();
+
+ _xRayRecorder.AddMetadata
+ (
+ nameSpace,
+ $"{eventArgs.Name} response",
+ result
+ );
+ }
}
///
- /// Code that handles when exceptions occur in the client method
+ /// Called when [exception].
///
- ///
- ///
- private void HandleException(Exception exception, string name)
+ ///
+ /// The instance containing the
+ /// event data.
+ ///
+ /// The exception.
+ public void OnException(AspectEventArgs eventArgs, Exception exception)
{
if (CaptureError())
{
var nameSpace = GetNamespace();
-
+
var sb = new StringBuilder();
sb.AppendLine($"Exception type: {exception.GetType()}");
sb.AppendLine($"Exception message: {exception.Message}");
@@ -185,48 +173,45 @@ private void HandleException(Exception exception, string name)
sb.AppendLine($"Stack trace: {exception.InnerException.StackTrace}");
sb.AppendLine("---END Inner Exception");
}
-
+
_xRayRecorder.AddMetadata
(
nameSpace,
- $"{name} error",
+ $"{eventArgs.Name} error",
sb.ToString()
);
}
- // // The purpose of ExceptionDispatchInfo.Capture is to capture a potentially mutating exception's StackTrace at a point in time:
- // // https://learn.microsoft.com/en-us/dotnet/standard/exceptions/best-practices-for-exceptions#capture-exceptions-to-rethrow-later
+ // The purpose of ExceptionDispatchInfo.Capture is to capture a potentially mutating exception's StackTrace at a point in time:
+ // https://learn.microsoft.com/en-us/dotnet/standard/exceptions/best-practices-for-exceptions#capture-exceptions-to-rethrow-later
ExceptionDispatchInfo.Capture(exception).Throw();
}
///
- /// Gets the namespace.
+ /// Handles the event.
///
- /// System.String.
- private string GetNamespace()
+ ///
+ /// The instance containing the
+ /// event data.
+ ///
+ public void OnExit(AspectEventArgs eventArgs)
{
- return !string.IsNullOrWhiteSpace(_namespace) ? _namespace : _powertoolsConfigurations.Service;
+ if(TracingDisabled())
+ return;
+
+ if (_isAnnotationsCaptured)
+ _captureAnnotations = true;
+
+ _xRayRecorder.EndSubsegment();
}
///
- /// Method that checks if tracing is disabled
+ /// Gets the namespace.
///
- ///
- private bool TracingDisabled()
+ /// System.String.
+ private string GetNamespace()
{
- if (_powertoolsConfigurations.TracingDisabled)
- {
- Console.WriteLine("Tracing has been disabled via env var POWERTOOLS_TRACE_DISABLED");
- return true;
- }
-
- if (!_powertoolsConfigurations.IsLambdaEnvironment)
- {
- Console.WriteLine("Running outside Lambda environment; disabling Tracing");
- return true;
- }
-
- return false;
+ return !string.IsNullOrWhiteSpace(_namespace) ? _namespace : _powertoolsConfigurations.Service;
}
///
@@ -235,6 +220,9 @@ private bool TracingDisabled()
/// true if tracing should capture responses, false otherwise.
private bool CaptureResponse()
{
+ if(TracingDisabled())
+ return false;
+
switch (_captureMode)
{
case TracingCaptureMode.EnvironmentVariable:
@@ -255,9 +243,9 @@ private bool CaptureResponse()
/// true if tracing should capture errors, false otherwise.
private bool CaptureError()
{
- if (TracingDisabled())
+ if(TracingDisabled())
return false;
-
+
switch (_captureMode)
{
case TracingCaptureMode.EnvironmentVariable:
@@ -271,7 +259,28 @@ private bool CaptureError()
return false;
}
}
+
+ ///
+ /// Tracing disabled.
+ ///
+ /// true if tracing is disabled, false otherwise.
+ private bool TracingDisabled()
+ {
+ if (_powertoolsConfigurations.TracingDisabled)
+ {
+ Console.WriteLine("Tracing has been disabled via env var POWERTOOLS_TRACE_DISABLED");
+ return true;
+ }
+
+ if (!_powertoolsConfigurations.IsLambdaEnvironment)
+ {
+ Console.WriteLine("Running outside Lambda environment; disabling Tracing");
+ return true;
+ }
+ return false;
+ }
+
///
/// Resets static variables for test.
///
@@ -280,4 +289,4 @@ internal static void ResetForTest()
_isColdStart = true;
_captureAnnotations = true;
}
-}
\ No newline at end of file
+}
diff --git a/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs b/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs
index 4ac0db2d..0d9d6727 100644
--- a/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs
@@ -13,8 +13,6 @@
* permissions and limitations under the License.
*/
-using System;
-using AspectInjector.Broker;
using AWS.Lambda.Powertools.Common;
using AWS.Lambda.Powertools.Tracing.Internal;
@@ -107,8 +105,7 @@ namespace AWS.Lambda.Powertools.Tracing;
/// }
///
///
-[Injection(typeof(TracingAspect))]
-public class TracingAttribute : Attribute
+public class TracingAttribute : MethodAspectAttribute
{
///
/// Set custom segment name for the operation.
@@ -131,4 +128,20 @@ public class TracingAttribute : Attribute
///
/// The capture mode.
public TracingCaptureMode CaptureMode { get; set; } = TracingCaptureMode.EnvironmentVariable;
+
+ ///
+ /// Creates the handler.
+ ///
+ /// IMethodAspectHandler.
+ protected override IMethodAspectHandler CreateHandler()
+ {
+ return new TracingAspectHandler
+ (
+ SegmentName,
+ Namespace,
+ CaptureMode,
+ PowertoolsConfigurations.Instance,
+ XRayRecorder.Instance
+ );
+ }
}
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/FullExampleHandler.cs b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/FullExampleHandler.cs
index 5d1e78e5..68808be3 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/FullExampleHandler.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/FullExampleHandler.cs
@@ -21,12 +21,12 @@ namespace AWS.Lambda.Powertools.Tracing.Tests.Handlers;
public class FullExampleHandler
{
[Tracing(Namespace = "ns", CaptureMode = TracingCaptureMode.ResponseAndError)]
- public Task Handle(string text, ILambdaContext context)
+ public async Task Handle(string text, ILambdaContext context)
{
Tracing.AddAnnotation("annotation", "value");
- BusinessLogic1().GetAwaiter().GetResult();
+ await BusinessLogic1();
- return Task.FromResult(text.ToUpper());
+ return await Task.FromResult(text.ToUpper());
}
[Tracing(SegmentName = "First Call")]
diff --git a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/HandlerTests.cs b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/HandlerTests.cs
index 29f444cb..80a419b1 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/HandlerTests.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/HandlerTests.cs
@@ -60,8 +60,9 @@ public async Task Full_Example()
};
// Act
+ var facadeSegment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
await handler.Handle("Hello World", context);
- var handleSegment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
+ var handleSegment = facadeSegment.Subsegments[0];
// Assert
Assert.True(handleSegment.IsAnnotationsAdded);
@@ -106,6 +107,6 @@ public void Dispose()
Environment.SetEnvironmentVariable("LAMBDA_TASK_ROOT", "");
Environment.SetEnvironmentVariable("POWERTOOLS_SERVICE_NAME", "");
Environment.SetEnvironmentVariable("POWERTOOLS_TRACE_DISABLED", "");
- TracingAspect.ResetForTest();
+ TracingAspectHandler.ResetForTest();
}
}
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/TracingAttributeTest.cs b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/TracingAttributeTest.cs
index 507ded2d..d9ff9a54 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/TracingAttributeTest.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/TracingAttributeTest.cs
@@ -115,7 +115,7 @@ public void Dispose()
Environment.SetEnvironmentVariable("POWERTOOLS_TRACER_CAPTURE_RESPONSE", "");
Environment.SetEnvironmentVariable("POWERTOOLS_TRACER_CAPTURE_ERROR", "");
Environment.SetEnvironmentVariable("POWERTOOLS_TRACE_DISABLED", "");
- TracingAspect.ResetForTest();
+ TracingAspectHandler.ResetForTest();
}
}
@@ -171,7 +171,7 @@ private static void ClearEnvironment()
Environment.SetEnvironmentVariable("POWERTOOLS_TRACER_CAPTURE_RESPONSE", "");
Environment.SetEnvironmentVariable("POWERTOOLS_TRACER_CAPTURE_ERROR", "");
Environment.SetEnvironmentVariable("POWERTOOLS_TRACE_DISABLED", "");
- TracingAspect.ResetForTest();
+ TracingAspectHandler.ResetForTest();
}
}
@@ -757,7 +757,7 @@ public void Dispose()
Environment.SetEnvironmentVariable("POWERTOOLS_TRACER_CAPTURE_RESPONSE", "");
Environment.SetEnvironmentVariable("POWERTOOLS_TRACER_CAPTURE_ERROR", "");
Environment.SetEnvironmentVariable("POWERTOOLS_TRACE_DISABLED", "");
- TracingAspect.ResetForTest();
+ TracingAspectHandler.ResetForTest();
}
}
}
\ No newline at end of file
From 43b2aab2459be8166c37a288ce8cd46a457901d8 Mon Sep 17 00:00:00 2001
From: Henrique <999396+hjgraca@users.noreply.github.com>
Date: Fri, 4 Oct 2024 09:17:54 +0100
Subject: [PATCH 2/3] fix sonar
---
.../Internal/TracingAspectHandler.cs | 4 ++--
.../src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs | 8 +++++---
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspectHandler.cs b/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspectHandler.cs
index 7e80ab86..c2863fce 100644
--- a/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspectHandler.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspectHandler.cs
@@ -55,12 +55,12 @@ internal class TracingAspectHandler : IMethodAspectHandler
///
/// Tracing namespace
///
- private string _namespace;
+ private readonly string _namespace;
///
/// The capture mode
///
- private TracingCaptureMode _captureMode;
+ private readonly TracingCaptureMode _captureMode;
///
/// The segment name
diff --git a/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs b/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs
index 0d9d6727..c3a3a5c6 100644
--- a/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs
@@ -1,18 +1,19 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
- *
+ *
* http://aws.amazon.com/apache2.0
- *
+ *
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
+using System;
using AWS.Lambda.Powertools.Common;
using AWS.Lambda.Powertools.Tracing.Internal;
@@ -105,6 +106,7 @@ namespace AWS.Lambda.Powertools.Tracing;
/// }
///
///
+[AttributeUsage(AttributeTargets.Method)]
public class TracingAttribute : MethodAspectAttribute
{
///
From ba92787d46a376c054e0509c513f9d0a0b1af7de Mon Sep 17 00:00:00 2001
From: Henrique Graca <999396+hjgraca@users.noreply.github.com>
Date: Fri, 4 Oct 2024 10:40:34 +0100
Subject: [PATCH 3/3] Update version for tracing
---
version.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/version.json b/version.json
index 1a74e63c..ffcfa3f8 100644
--- a/version.json
+++ b/version.json
@@ -2,7 +2,7 @@
"Core": {
"Logging": "1.6.1",
"Metrics": "1.7.1",
- "Tracing": "1.5.1"
+ "Tracing": "1.5.2"
},
"Utilities": {
"Parameters": "1.3.0",