Skip to content

Commit 051305c

Browse files
committed
Update RecordHanderResult to avoid cirular instantiation on static property, this was breaking LitJson parser on X-Ray SDK with Max allowed object depth reached.
Tracing now takes into account the CaptureMode set for each method XRayRecorder now captures the exceptions from EndSubsegment call and does not surface exception to the client Update nuget packages for X-Ray SDK
1 parent 2ed95ef commit 051305c

File tree

7 files changed

+167
-43
lines changed

7 files changed

+167
-43
lines changed

libraries/src/AWS.Lambda.Powertools.BatchProcessing/RecordHandlerResult.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class RecordHandlerResult
2323
/// <summary>
2424
/// Returns an empty <see cref="RecordHandlerResult"/> value.
2525
/// </summary>
26-
public static readonly RecordHandlerResult None = new();
26+
public static RecordHandlerResult None { get; } = null!;
2727

2828
/// <summary>
2929
/// Convenience method for the creation of a <see cref="RecordHandlerResult"/>.

libraries/src/AWS.Lambda.Powertools.Tracing/Internal/TracingAspect.cs

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
using System;
1717
using System.Linq;
18-
using System.Reflection;
1918
using System.Runtime.ExceptionServices;
2019
using System.Text;
2120
using AspectInjector.Broker;
@@ -39,7 +38,7 @@ public class TracingAspect
3938
/// X-Ray Recorder
4039
/// </summary>
4140
private readonly IXRayRecorder _xRayRecorder;
42-
41+
4342
/// <summary>
4443
/// If true, then is cold start
4544
/// </summary>
@@ -49,17 +48,17 @@ public class TracingAspect
4948
/// If true, capture annotations
5049
/// </summary>
5150
private static bool _captureAnnotations = true;
52-
51+
5352
/// <summary>
5453
/// If true, annotations have been captured
5554
/// </summary>
5655
private bool _isAnnotationsCaptured;
57-
56+
5857
/// <summary>
5958
/// Tracing namespace
6059
/// </summary>
6160
private string _namespace;
62-
61+
6362
/// <summary>
6463
/// The capture mode
6564
/// </summary>
@@ -73,18 +72,14 @@ public TracingAspect()
7372
_xRayRecorder = XRayRecorder.Instance;
7473
_powertoolsConfigurations = PowertoolsConfigurations.Instance;
7574
}
76-
75+
7776
/// <summary>
7877
/// the code is executed instead of the target method.
7978
/// The call to original method is wrapped around the following code
8079
/// the original code is called with var result = target(args);
8180
/// </summary>
82-
/// <param name="instance"></param>
8381
/// <param name="name"></param>
8482
/// <param name="args"></param>
85-
/// <param name="hostType"></param>
86-
/// <param name="method"></param>
87-
/// <param name="returnType"></param>
8883
/// <param name="target"></param>
8984
/// <param name="triggers"></param>
9085
/// <returns></returns>
@@ -97,38 +92,39 @@ public object Around(
9792
{
9893
// Before running Function
9994

95+
var trigger = triggers.OfType<TracingAttribute>().First();
10096
try
10197
{
102-
var trigger = triggers.OfType<TracingAttribute>().First();
103-
104-
if(TracingDisabled())
98+
if (TracingDisabled())
10599
return target(args);
106100

107101
_namespace = trigger.Namespace;
108-
_captureMode = trigger.CaptureMode;
109-
102+
110103
var segmentName = !string.IsNullOrWhiteSpace(trigger.SegmentName) ? trigger.SegmentName : $"## {name}";
111104
var nameSpace = GetNamespace();
112105

113106
_xRayRecorder.BeginSubsegment(segmentName);
114107
_xRayRecorder.SetNamespace(nameSpace);
115108

116-
if (_captureAnnotations)
109+
if (_captureAnnotations)
117110
{
118111
_xRayRecorder.AddAnnotation("ColdStart", _isColdStart);
119-
112+
120113
_captureAnnotations = false;
121114
_isAnnotationsCaptured = true;
122115

123116
if (_powertoolsConfigurations.IsServiceDefined)
124117
_xRayRecorder.AddAnnotation("Service", _powertoolsConfigurations.Service);
125118
}
126-
119+
127120
_isColdStart = false;
128-
121+
129122
// return of the handler
130123
var result = target(args);
131-
124+
125+
// must get capture after all subsegments run
126+
_captureMode = trigger.CaptureMode;
127+
132128
if (CaptureResponse())
133129
{
134130
_xRayRecorder.AddMetadata
@@ -138,12 +134,13 @@ public object Around(
138134
result
139135
);
140136
}
141-
137+
142138
// after
143139
return result;
144140
}
145141
catch (Exception e)
146142
{
143+
_captureMode = trigger.CaptureMode;
147144
HandleException(e, name);
148145
throw;
149146
}
@@ -153,16 +150,17 @@ public object Around(
153150
/// the code is injected after the method ends.
154151
/// </summary>
155152
[Advice(Kind.After)]
156-
public void OnExit() {
157-
if(TracingDisabled())
153+
public void OnExit()
154+
{
155+
if (TracingDisabled())
158156
return;
159157

160158
if (_isAnnotationsCaptured)
161159
_captureAnnotations = true;
162160

163161
_xRayRecorder.EndSubsegment();
164162
}
165-
163+
166164
/// <summary>
167165
/// Code that handles when exceptions occur in the client method
168166
/// </summary>
@@ -173,7 +171,7 @@ private void HandleException(Exception exception, string name)
173171
if (CaptureError())
174172
{
175173
var nameSpace = GetNamespace();
176-
174+
177175
var sb = new StringBuilder();
178176
sb.AppendLine($"Exception type: {exception.GetType()}");
179177
sb.AppendLine($"Exception message: {exception.Message}");
@@ -187,7 +185,7 @@ private void HandleException(Exception exception, string name)
187185
sb.AppendLine($"Stack trace: {exception.InnerException.StackTrace}");
188186
sb.AppendLine("---END Inner Exception");
189187
}
190-
188+
191189
_xRayRecorder.AddMetadata
192190
(
193191
nameSpace,
@@ -209,7 +207,7 @@ private string GetNamespace()
209207
{
210208
return !string.IsNullOrWhiteSpace(_namespace) ? _namespace : _powertoolsConfigurations.Service;
211209
}
212-
210+
213211
/// <summary>
214212
/// Method that checks if tracing is disabled
215213
/// </summary>
@@ -230,7 +228,7 @@ private bool TracingDisabled()
230228

231229
return false;
232230
}
233-
231+
234232
/// <summary>
235233
/// Captures the response.
236234
/// </summary>
@@ -250,16 +248,16 @@ private bool CaptureResponse()
250248
return false;
251249
}
252250
}
253-
251+
254252
/// <summary>
255253
/// Captures the error.
256254
/// </summary>
257255
/// <returns><c>true</c> if tracing should capture errors, <c>false</c> otherwise.</returns>
258256
private bool CaptureError()
259257
{
260-
if(TracingDisabled())
258+
if (TracingDisabled())
261259
return false;
262-
260+
263261
switch (_captureMode)
264262
{
265263
case TracingCaptureMode.EnvironmentVariable:
@@ -273,7 +271,7 @@ private bool CaptureError()
273271
return false;
274272
}
275273
}
276-
274+
277275
/// <summary>
278276
/// Resets static variables for test.
279277
/// </summary>

libraries/src/AWS.Lambda.Powertools.Tracing/Internal/XRayRecorder.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/*
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3-
*
3+
*
44
* Licensed under the Apache License, Version 2.0 (the "License").
55
* You may not use this file except in compliance with the License.
66
* A copy of the License is located at
7-
*
7+
*
88
* http://aws.amazon.com/apache2.0
9-
*
9+
*
1010
* or in the "license" file accompanying this file. This file is distributed
1111
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
1212
* express or implied. See the License for the specific language governing
@@ -41,7 +41,8 @@ internal class XRayRecorder : IXRayRecorder
4141
/// Gets the instance.
4242
/// </summary>
4343
/// <value>The instance.</value>
44-
public static IXRayRecorder Instance => _instance ??= new XRayRecorder(AWSXRayRecorder.Instance, PowertoolsConfigurations.Instance);
44+
public static IXRayRecorder Instance =>
45+
_instance ??= new XRayRecorder(AWSXRayRecorder.Instance, PowertoolsConfigurations.Instance);
4546

4647
public XRayRecorder(IAWSXRayRecorder awsxRayRecorder, IPowertoolsConfigurations powertoolsConfigurations)
4748
{
@@ -56,7 +57,7 @@ public XRayRecorder(IAWSXRayRecorder awsxRayRecorder, IPowertoolsConfigurations
5657
/// Checks whether current execution is in AWS Lambda.
5758
/// </summary>
5859
/// <returns>Returns true if current execution is in AWS Lambda.</returns>
59-
private static bool _isLambda;
60+
private static bool _isLambda;
6061

6162
/// <summary>
6263
/// Gets the emitter.
@@ -119,7 +120,19 @@ public void AddMetadata(string nameSpace, string key, object value)
119120
public void EndSubsegment()
120121
{
121122
if (_isLambda)
122-
_awsxRayRecorder.EndSubsegment();
123+
{
124+
try
125+
{
126+
_awsxRayRecorder.EndSubsegment();
127+
}
128+
catch (Exception e)
129+
{
130+
_awsxRayRecorder.AddException(e);
131+
_awsxRayRecorder.MarkFault();
132+
_awsxRayRecorder.MarkError();
133+
_awsxRayRecorder.EndSubsegment();
134+
}
135+
}
123136
}
124137

125138
/// <summary>

libraries/src/Directory.Packages.props

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
<PackageVersion Include="AWSSDK.AppConfig" Version="3.7.301" />
1010
<PackageVersion Include="AWSSDK.AppConfigData" Version="3.7.301.15" />
1111
<PackageVersion Include="AWSSDK.DynamoDBv2" Version="3.7.301.18" />
12-
<PackageVersion Include="AWSXRayRecorder.Handlers.AwsSdk" Version="2.12.0" />
12+
<PackageVersion Include="AWSXRayRecorder.Handlers.AwsSdk" Version="2.13.0" />
1313
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
1414
<PackageVersion Include="AWSSDK.SecretsManager" Version="3.7.302.29" />
1515
<PackageVersion Include="AWSSDK.SimpleSystemsManagement" Version="3.7.303.2" />
1616
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
17-
<PackageVersion Include="AWSSDK.XRay" Version="3.7.300.54" />
18-
<PackageVersion Include="AWSXRayRecorder.Core" Version="2.14.0" />
17+
<PackageVersion Include="AWSSDK.XRay" Version="3.7.400.8" />
18+
<PackageVersion Include="AWSXRayRecorder.Core" Version="2.15.0" />
1919
<PackageVersion Include="Amazon.Lambda.DynamoDBEvents" Version="3.1.0" />
2020
<PackageVersion Include="Amazon.Lambda.KinesisEvents" Version="2.2.0" />
2121
<PackageVersion Include="Amazon.Lambda.SQSEvents" Version="2.2.0" />

libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/Handlers.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,24 @@ public string[] HandleWithCaptureModeDisabled(bool exception = false)
8383
throw new Exception("Failed");
8484
return new[] { "A", "B" };
8585
}
86+
87+
[Tracing(CaptureMode = TracingCaptureMode.ResponseAndError)]
88+
public string DecoratedHandlerCaptureResponse()
89+
{
90+
DecoratedMethodCaptureDisabled();
91+
return "Hello World";
92+
}
93+
94+
[Tracing(CaptureMode = TracingCaptureMode.Disabled)]
95+
public string DecoratedMethodCaptureDisabled()
96+
{
97+
DecoratedMethodCaptureEnabled();
98+
return "DecoratedMethod Disabled";
99+
}
100+
101+
[Tracing(CaptureMode = TracingCaptureMode.ResponseAndError)]
102+
private string DecoratedMethodCaptureEnabled()
103+
{
104+
return "DecoratedMethod Enabled";
105+
}
86106
}

libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/TracingAttributeTest.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,69 @@ public void OnSuccess_WhenTracerCaptureModeIsDisabled_DoesNotCaptureResponse()
429429
Assert.Single(segment.Subsegments);
430430
Assert.False(subSegment.IsMetadataAdded); // does not add metadata
431431
}
432+
433+
[Fact]
434+
public void OnSuccess_WhenTracerCaptureResponseEnvironmentVariableIsFalse_ButDecoratorCapturesResponse()
435+
{
436+
// Arrange
437+
Environment.SetEnvironmentVariable("LAMBDA_TASK_ROOT", "AWS");
438+
Environment.SetEnvironmentVariable("POWERTOOLS_SERVICE_NAME", "POWERTOOLS");
439+
Environment.SetEnvironmentVariable("POWERTOOLS_TRACER_CAPTURE_RESPONSE", "false");
440+
441+
// Act
442+
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
443+
_handler.DecoratedHandlerCaptureResponse();
444+
var subSegment = segment.Subsegments[0];
445+
446+
// Assert
447+
Assert.True(segment.IsSubsegmentsAdded);
448+
Assert.Single(segment.Subsegments);
449+
Assert.True(subSegment.IsMetadataAdded);
450+
Assert.True(subSegment.Metadata.ContainsKey("POWERTOOLS"));
451+
452+
var metadata = subSegment.Metadata["POWERTOOLS"];
453+
Assert.Equal("DecoratedHandlerCaptureResponse response", metadata.Keys.Cast<string>().First());
454+
var handlerResponse = metadata.Values.Cast<string>().First();
455+
Assert.Equal("Hello World", handlerResponse);
456+
457+
var decoratedMethodSegmentDisabled = subSegment.Subsegments[0];
458+
Assert.False(decoratedMethodSegmentDisabled.IsMetadataAdded);
459+
Assert.Equal("## DecoratedMethodCaptureDisabled", decoratedMethodSegmentDisabled.Name);
460+
461+
var decoratedMethodSegmentEnabled = decoratedMethodSegmentDisabled.Subsegments[0];
462+
Assert.True(decoratedMethodSegmentEnabled.IsMetadataAdded);
463+
464+
var decoratedMethodSegmentEnabledMetadata = decoratedMethodSegmentEnabled.Metadata["POWERTOOLS"];
465+
var decoratedMethodSegmentEnabledResponse = decoratedMethodSegmentEnabledMetadata.Values.Cast<string>().First();
466+
Assert.Equal("DecoratedMethod Enabled", decoratedMethodSegmentEnabledResponse);
467+
Assert.Equal("## DecoratedMethodCaptureEnabled", decoratedMethodSegmentEnabled.Name);
468+
}
469+
470+
[Fact]
471+
public void OnSuccess_WhenTracerCaptureResponseEnvironmentVariableIsTrue_ButDecoratorCapturesResponseDisabled()
472+
{
473+
// Arrange
474+
Environment.SetEnvironmentVariable("LAMBDA_TASK_ROOT", "AWS");
475+
Environment.SetEnvironmentVariable("POWERTOOLS_SERVICE_NAME", "POWERTOOLS");
476+
Environment.SetEnvironmentVariable("POWERTOOLS_TRACER_CAPTURE_RESPONSE", "true");
477+
478+
// Act
479+
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
480+
_handler.DecoratedMethodCaptureDisabled();
481+
var subSegment = segment.Subsegments[0];
482+
483+
// Assert
484+
Assert.True(segment.IsSubsegmentsAdded);
485+
Assert.Single(segment.Subsegments);
486+
Assert.False(subSegment.IsMetadataAdded);
487+
488+
var decoratedMethodSegmentEnabled = subSegment.Subsegments[0];
489+
var metadata = decoratedMethodSegmentEnabled.Metadata["POWERTOOLS"];
490+
Assert.True(decoratedMethodSegmentEnabled.IsMetadataAdded);
491+
var decoratedMethodSegmentEnabledResponse = metadata.Values.Cast<string>().First();
492+
Assert.Equal("DecoratedMethod Enabled", decoratedMethodSegmentEnabledResponse);
493+
Assert.Equal("## DecoratedMethodCaptureEnabled", decoratedMethodSegmentEnabled.Name);
494+
}
432495

433496
#endregion
434497

0 commit comments

Comments
 (0)