diff --git a/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/Helpers.cs b/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/Helpers.cs
new file mode 100644
index 000000000..f124852dd
--- /dev/null
+++ b/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/Helpers.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace AWS.Lambda.Powertools.Tracing.Internal;
+
+///
+/// Helper class
+///
+public static class Helpers
+{
+ ///
+ /// Sanitize a string by removing any characters that are not alphanumeric, whitespace, or one of the following: _ . : / % & # = + - @
+ ///
+ ///
+ ///
+ public static string SanitizeString(string input)
+ {
+ // Define a regular expression pattern to match allowed characters
+ var pattern = @"[^a-zA-Z0-9\s_\.\:/%=+\-@]";
+
+ // Replace any character that does not match the pattern with an empty string, with a timeout
+ return Regex.Replace(input, pattern, string.Empty, RegexOptions.None, TimeSpan.FromMilliseconds(100));
+ }
+}
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/XRayRecorder.cs b/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/XRayRecorder.cs
index e192036ee..53bface31 100644
--- a/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/XRayRecorder.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/XRayRecorder.cs
@@ -78,7 +78,9 @@ public XRayRecorder(IAWSXRayRecorder awsxRayRecorder, IPowertoolsConfigurations
public void BeginSubsegment(string name)
{
if (_isLambda)
- _awsxRayRecorder.BeginSubsegment(name);
+ {
+ _awsxRayRecorder.BeginSubsegment(Helpers.SanitizeString(name));
+ }
}
///
diff --git a/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs b/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs
index 1946fb9c2..c144d0387 100644
--- a/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs
@@ -15,7 +15,6 @@
using System;
using AspectInjector.Broker;
-using AWS.Lambda.Powertools.Common;
using AWS.Lambda.Powertools.Tracing.Internal;
namespace AWS.Lambda.Powertools.Tracing;
@@ -114,8 +113,10 @@ public class TracingAttribute : Attribute
///
/// Set custom segment name for the operation.
/// The default is '## {MethodName}'.
+ ///
+ /// The logical name of the service that handled the request, up to 200 characters.
+ /// Names can contain Unicode letters, numbers, and whitespace, and the following symbols: \_, ., :, /, %, &, #, =, +, \\, -, @
///
- /// The name of the segment.
public string SegmentName { get; set; } = "";
///
diff --git a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/Handlers.cs b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/Handlers.cs
index 385ce96c1..38210ac92 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/Handlers.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/Handlers/Handlers.cs
@@ -31,6 +31,18 @@ public void HandleWithSegmentName()
}
+ [Tracing(SegmentName = "## <$>g__Handler|0_0")]
+ public void HandleWithInvalidSegmentName()
+ {
+ MethodWithInvalidSegmentName();
+ }
+
+ [Tracing(SegmentName = "Inval$#id | ")]
+ private void MethodWithInvalidSegmentName()
+ {
+
+ }
+
[Tracing(Namespace = "Namespace Defined")]
public void HandleWithNamespace()
{
diff --git a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/TracingAttributeTest.cs b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/TracingAttributeTest.cs
index 58252d67c..f02619c1f 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/TracingAttributeTest.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/TracingAttributeTest.cs
@@ -256,6 +256,28 @@ public void OnEntry_WhenSegmentNameHasValue_BeginSubsegmentWithValue()
Assert.Single(segment.Subsegments);
Assert.Equal("SegmentName", subSegment.Name);
}
+
+ [Fact]
+ public void OnEntry_WhenSegmentName_Is_Unsupported()
+ {
+ // Arrange
+ Environment.SetEnvironmentVariable("LAMBDA_TASK_ROOT", "AWS");
+ Environment.SetEnvironmentVariable("POWERTOOLS_SERVICE_NAME", "POWERTOOLS");
+
+ // Act
+ var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
+ _handler.HandleWithInvalidSegmentName();
+ var subSegment = segment.Subsegments[0];
+ var childSegment = subSegment.Subsegments[0];
+
+ // Assert
+ Assert.True(segment.IsSubsegmentsAdded);
+ Assert.True(subSegment.IsSubsegmentsAdded);
+ Assert.Single(segment.Subsegments);
+ Assert.Single(subSegment.Subsegments);
+ Assert.Equal("## Maing__Handler0_0", subSegment.Name);
+ Assert.Equal("Inval#id Segment", childSegment.Name);
+ }
[Fact]
public void OnEntry_WhenNamespaceIsNull_SetNamespaceWithService()