diff --git a/libraries/src/AWS.Lambda.Powertools.Common/Core/Constants.cs b/libraries/src/AWS.Lambda.Powertools.Common/Core/Constants.cs
index 99d38d07..72254726 100644
--- a/libraries/src/AWS.Lambda.Powertools.Common/Core/Constants.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/Constants.cs
@@ -80,4 +80,14 @@ internal static class Constants
/// Constant for LAMBDA_TASK_ROOT environment variable
///
internal const string LambdaTaskRoot = "LAMBDA_TASK_ROOT";
+
+ ///
+ /// Constant for AWS_EXECUTION_ENV environment variable
+ ///
+ internal const string AwsExecutionEnvironmentVariableName = "AWS_EXECUTION_ENV";
+
+ ///
+ /// Constant for Powertools feature identifier fo AWS_EXECUTION_ENV environment variable
+ ///
+ internal const string FeatureContextIdentifier = "PT";
}
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.Common/Core/IPowertoolsConfigurations.cs b/libraries/src/AWS.Lambda.Powertools.Common/Core/IPowertoolsConfigurations.cs
index d9dc90cb..a2e10cc7 100644
--- a/libraries/src/AWS.Lambda.Powertools.Common/Core/IPowertoolsConfigurations.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/IPowertoolsConfigurations.cs
@@ -120,4 +120,10 @@ public interface IPowertoolsConfigurations
/// if set to true [default value].
/// true if XXXX, false otherwise.
bool GetEnvironmentVariableOrDefault(string variable, bool defaultValue);
+
+ ///
+ /// Sets the execution Environment Variable (AWS_EXECUTION_ENV)
+ ///
+ ///
+ void SetExecutionEnvironment(T type);
}
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.Common/Core/IPowertoolsEnvironment.cs b/libraries/src/AWS.Lambda.Powertools.Common/Core/IPowertoolsEnvironment.cs
new file mode 100644
index 00000000..059cfb7e
--- /dev/null
+++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/IPowertoolsEnvironment.cs
@@ -0,0 +1,37 @@
+namespace AWS.Lambda.Powertools.Common;
+
+///
+/// Interface for PowertoolsEnvironment
+///
+public interface IPowertoolsEnvironment
+{
+ ///
+ /// Get environment variable by variable name
+ ///
+ ///
+ /// Environment variable
+ string GetEnvironmentVariable(string variableName);
+
+ ///
+ /// Set environment variable
+ ///
+ ///
+ /// Setting this to null will remove environment variable with that name
+ void SetEnvironmentVariable(string variableName, string value);
+
+ ///
+ /// Get the calling Type Assembly Name
+ ///
+ ///
+ ///
+ /// Assembly Name
+ string GetAssemblyName(T type);
+
+ ///
+ /// Get the calling Type Assembly Version
+ ///
+ ///
+ ///
+ /// Assembly Version in the Major.Minor.Build format
+ string GetAssemblyVersion(T type);
+}
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.Common/Core/ISystemWrapper.cs b/libraries/src/AWS.Lambda.Powertools.Common/Core/ISystemWrapper.cs
index 92ec9e3e..98abe1b5 100644
--- a/libraries/src/AWS.Lambda.Powertools.Common/Core/ISystemWrapper.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/ISystemWrapper.cs
@@ -44,4 +44,17 @@ public interface ISystemWrapper
///
/// System.Double.
double GetRandom();
+
+ ///
+ /// Sets the environment variable.
+ ///
+ /// The variable.
+ ///
+ void SetEnvironmentVariable(string variable, string value);
+
+ ///
+ /// Sets the execution Environment Variable (AWS_EXECUTION_ENV)
+ ///
+ ///
+ void SetExecutionEnvironment(T type);
}
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.Common/Core/PowertoolsConfigurations.cs b/libraries/src/AWS.Lambda.Powertools.Common/Core/PowertoolsConfigurations.cs
index f73631d6..1d099e4d 100644
--- a/libraries/src/AWS.Lambda.Powertools.Common/Core/PowertoolsConfigurations.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/PowertoolsConfigurations.cs
@@ -184,4 +184,10 @@ public bool GetEnvironmentVariableOrDefault(string variable, bool defaultValue)
/// true if [tracing is disabled]; otherwise, false.
public bool TracingDisabled =>
GetEnvironmentVariableOrDefault(Constants.TracingDisabledEnv, false);
+
+ ///
+ public void SetExecutionEnvironment(T type)
+ {
+ _systemWrapper.SetExecutionEnvironment(type);
+ }
}
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.Common/Core/PowertoolsEnvironment.cs b/libraries/src/AWS.Lambda.Powertools.Common/Core/PowertoolsEnvironment.cs
new file mode 100644
index 00000000..3ad5317c
--- /dev/null
+++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/PowertoolsEnvironment.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace AWS.Lambda.Powertools.Common;
+
+///
+public class PowertoolsEnvironment : IPowertoolsEnvironment
+{
+ ///
+ /// The instance
+ ///
+ private static IPowertoolsEnvironment _instance;
+
+ ///
+ /// Gets the instance.
+ ///
+ /// The instance.
+ public static IPowertoolsEnvironment Instance => _instance ??= new PowertoolsEnvironment();
+
+ ///
+ public string GetEnvironmentVariable(string variableName)
+ {
+ return Environment.GetEnvironmentVariable(variableName);
+ }
+
+ ///
+ public void SetEnvironmentVariable(string variableName, string value)
+ {
+ Environment.SetEnvironmentVariable(variableName, value);
+ }
+
+ ///
+ public string GetAssemblyName(T type)
+ {
+ return type.GetType().Assembly.GetName().Name;
+ }
+
+ ///
+ public string GetAssemblyVersion(T type)
+ {
+ var version = type.GetType().Assembly.GetName().Version;
+ return version != null ? $"{version.Major}.{version.Minor}.{version.Build}" : string.Empty;
+ }
+}
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.Common/Core/SystemWrapper.cs b/libraries/src/AWS.Lambda.Powertools.Common/Core/SystemWrapper.cs
index f6906a60..703a0865 100644
--- a/libraries/src/AWS.Lambda.Powertools.Common/Core/SystemWrapper.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/SystemWrapper.cs
@@ -14,6 +14,7 @@
*/
using System;
+using System.Text;
namespace AWS.Lambda.Powertools.Common;
@@ -24,6 +25,8 @@ namespace AWS.Lambda.Powertools.Common;
///
public class SystemWrapper : ISystemWrapper
{
+ private static IPowertoolsEnvironment _powertoolsEnvironment;
+
///
/// The instance
///
@@ -32,15 +35,17 @@ public class SystemWrapper : ISystemWrapper
///
/// Prevents a default instance of the class from being created.
///
- private SystemWrapper()
+ public SystemWrapper(IPowertoolsEnvironment powertoolsEnvironment)
{
+ _powertoolsEnvironment = powertoolsEnvironment;
+ _instance ??= this;
}
///
/// Gets the instance.
///
/// The instance.
- public static ISystemWrapper Instance => _instance ??= new SystemWrapper();
+ public static ISystemWrapper Instance => _instance ??= new SystemWrapper(PowertoolsEnvironment.Instance);
///
/// Gets the environment variable.
@@ -49,7 +54,7 @@ private SystemWrapper()
/// System.String.
public string GetEnvironmentVariable(string variable)
{
- return Environment.GetEnvironmentVariable(variable);
+ return _powertoolsEnvironment.GetEnvironmentVariable(variable);
}
///
@@ -78,4 +83,57 @@ public double GetRandom()
{
return new Random().NextDouble();
}
+
+ ///
+ public void SetEnvironmentVariable(string variable, string value)
+ {
+ _powertoolsEnvironment.SetEnvironmentVariable(variable, value);
+ }
+
+ ///
+ public void SetExecutionEnvironment(T type)
+ {
+ const string envName = Constants.AwsExecutionEnvironmentVariableName;
+ var envValue = new StringBuilder();
+ var currentEnvValue = GetEnvironmentVariable(envName);
+ var assemblyName = ParseAssemblyName(_powertoolsEnvironment.GetAssemblyName(type));
+
+ // If there is an existing execution environment variable add the annotations package as a suffix.
+ if(!string.IsNullOrEmpty(currentEnvValue))
+ {
+ // Avoid duplication - should not happen since the calling Instances are Singletons - defensive purposes
+ if (currentEnvValue.Contains(assemblyName))
+ {
+ return;
+ }
+
+ envValue.Append($"{currentEnvValue} ");
+ }
+
+ var assemblyVersion = _powertoolsEnvironment.GetAssemblyVersion(type);
+
+ envValue.Append($"{assemblyName}/{assemblyVersion}");
+
+ SetEnvironmentVariable(envName, envValue.ToString());
+ }
+
+ ///
+ /// Parsing the name to conform with the required naming convention for the UserAgent header (PTFeature/Name/Version)
+ /// Fallback to Assembly Name on exception
+ ///
+ ///
+ ///
+ private string ParseAssemblyName(string assemblyName)
+ {
+ try
+ {
+ var parsedName = assemblyName.Substring(assemblyName.LastIndexOf(".", StringComparison.Ordinal)+1);
+ return $"{Constants.FeatureContextIdentifier}/{parsedName}";
+ }
+ catch
+ {
+ //NOOP
+ }
+ return $"{Constants.FeatureContextIdentifier}/{assemblyName}";
+ }
}
\ No newline at end of file
diff --git a/libraries/src/AWS.Lambda.Powertools.Logging/Internal/PowertoolsLogger.cs b/libraries/src/AWS.Lambda.Powertools.Logging/Internal/PowertoolsLogger.cs
index c45a7515..281fbcc6 100644
--- a/libraries/src/AWS.Lambda.Powertools.Logging/Internal/PowertoolsLogger.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Logging/Internal/PowertoolsLogger.cs
@@ -76,6 +76,8 @@ public PowertoolsLogger(
{
(_name, _powertoolsConfigurations, _systemWrapper, _getCurrentConfig) = (name,
powertoolsConfigurations, systemWrapper, getCurrentConfig);
+
+ _powertoolsConfigurations.SetExecutionEnvironment(this);
}
///
diff --git a/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs b/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs
index 2bbc0fa2..24264e0e 100644
--- a/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs
@@ -71,6 +71,8 @@ internal Metrics(IPowertoolsConfigurations powertoolsConfigurations, string name
_raiseOnEmptyMetrics = raiseOnEmptyMetrics;
_captureColdStartEnabled = captureColdStartEnabled;
_context = InitializeContext(nameSpace, service, null);
+
+ _powertoolsConfigurations.SetExecutionEnvironment(this);
}
///
diff --git a/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/XRayRecorder.cs b/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/XRayRecorder.cs
index 89efe413..facfd39c 100644
--- a/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/XRayRecorder.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Tracing/Internal/XRayRecorder.cs
@@ -18,6 +18,7 @@
using Amazon.XRay.Recorder.Core.Internal.Emitters;
using Amazon.XRay.Recorder.Core.Internal.Entities;
using Amazon.XRay.Recorder.Core.Strategies;
+using AWS.Lambda.Powertools.Common;
namespace AWS.Lambda.Powertools.Tracing.Internal;
@@ -28,6 +29,9 @@ namespace AWS.Lambda.Powertools.Tracing.Internal;
///
internal class XRayRecorder : IXRayRecorder
{
+ private static IAWSXRayRecorder _awsxRayRecorder;
+ private static IPowertoolsConfigurations _powertoolsConfigurations;
+
///
/// The instance
///
@@ -37,25 +41,34 @@ internal class XRayRecorder : IXRayRecorder
/// Gets the instance.
///
/// The instance.
- public static IXRayRecorder Instance => _instance ??= new XRayRecorder();
+ public static IXRayRecorder Instance => _instance ??= new XRayRecorder(AWSXRayRecorder.Instance, PowertoolsConfigurations.Instance);
+
+ public XRayRecorder(IAWSXRayRecorder awsxRayRecorder, IPowertoolsConfigurations powertoolsConfigurations)
+ {
+ _instance = this;
+ _powertoolsConfigurations = powertoolsConfigurations;
+ _powertoolsConfigurations.SetExecutionEnvironment(this);
+ _isLambda = _powertoolsConfigurations.IsLambdaEnvironment;
+ _awsxRayRecorder = awsxRayRecorder;
+ }
///
/// Checks whether current execution is in AWS Lambda.
///
/// Returns true if current execution is in AWS Lambda.
- private static readonly bool _isLambda = AWSXRayRecorder.IsLambda();
+ private static bool _isLambda;
///
/// Gets the emitter.
///
/// The emitter.
- public ISegmentEmitter Emitter => _isLambda ? AWSXRayRecorder.Instance.Emitter : null;
+ public ISegmentEmitter Emitter => _isLambda ? _awsxRayRecorder.Emitter : null;
///
/// Gets the streaming strategy.
///
/// The streaming strategy.
- public IStreamingStrategy StreamingStrategy => _isLambda ? AWSXRayRecorder.Instance.StreamingStrategy : null;
+ public IStreamingStrategy StreamingStrategy => _isLambda ? _awsxRayRecorder.StreamingStrategy : null;
///
/// Begins the subsegment.
@@ -64,7 +77,7 @@ internal class XRayRecorder : IXRayRecorder
public void BeginSubsegment(string name)
{
if (_isLambda)
- AWSXRayRecorder.Instance.BeginSubsegment(name);
+ _awsxRayRecorder.BeginSubsegment(name);
}
///
@@ -74,7 +87,7 @@ public void BeginSubsegment(string name)
public void SetNamespace(string value)
{
if (_isLambda)
- AWSXRayRecorder.Instance.SetNamespace(value);
+ _awsxRayRecorder.SetNamespace(value);
}
///
@@ -85,7 +98,7 @@ public void SetNamespace(string value)
public void AddAnnotation(string key, object value)
{
if (_isLambda)
- AWSXRayRecorder.Instance.AddAnnotation(key, value);
+ _awsxRayRecorder.AddAnnotation(key, value);
}
///
@@ -97,7 +110,7 @@ public void AddAnnotation(string key, object value)
public void AddMetadata(string nameSpace, string key, object value)
{
if (_isLambda)
- AWSXRayRecorder.Instance.AddMetadata(nameSpace, key, value);
+ _awsxRayRecorder.AddMetadata(nameSpace, key, value);
}
///
@@ -106,7 +119,7 @@ public void AddMetadata(string nameSpace, string key, object value)
public void EndSubsegment()
{
if (_isLambda)
- AWSXRayRecorder.Instance.EndSubsegment();
+ _awsxRayRecorder.EndSubsegment();
}
///
@@ -116,7 +129,7 @@ public void EndSubsegment()
public Entity GetEntity()
{
return _isLambda
- ? AWSXRayRecorder.Instance.GetEntity()
+ ? _awsxRayRecorder.TraceContext.GetEntity()
: new Subsegment("Root");
}
@@ -127,7 +140,7 @@ public Entity GetEntity()
public void SetEntity(Entity entity)
{
if (_isLambda)
- AWSXRayRecorder.Instance.SetEntity(entity);
+ _awsxRayRecorder.TraceContext.SetEntity(entity);
}
///
@@ -137,7 +150,7 @@ public void SetEntity(Entity entity)
public void AddException(Exception exception)
{
if (_isLambda)
- AWSXRayRecorder.Instance.AddException(exception);
+ _awsxRayRecorder.AddException(exception);
}
///
@@ -148,6 +161,6 @@ public void AddException(Exception exception)
public void AddHttpInformation(string key, object value)
{
if (_isLambda)
- AWSXRayRecorder.Instance.AddHttpInformation(key, value);
+ _awsxRayRecorder.AddHttpInformation(key, value);
}
}
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.Common.Tests/Core/PowertoolsConfigurationsTest.cs b/libraries/tests/AWS.Lambda.Powertools.Common.Tests/Core/PowertoolsConfigurationsTest.cs
index 54b6b6c5..7ed9453b 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Common.Tests/Core/PowertoolsConfigurationsTest.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Common.Tests/Core/PowertoolsConfigurationsTest.cs
@@ -639,6 +639,30 @@ public void IsLambdaEnvironment_WhenEnvironmentHasValue_ReturnsTrue()
Assert.True(result);
}
+ [Fact]
+ public void Set_Lambda_Execution_Context()
+ {
+ // Arrange
+ var systemWrapper = new Mock();
+
+ // systemWrapper.Setup(c =>
+ // c.SetExecutionEnvironment(GetType())
+ // );
+
+ var configurations = new PowertoolsConfigurations(systemWrapper.Object);
+
+ // Act
+ configurations.SetExecutionEnvironment(typeof(PowertoolsConfigurations));
+
+ // Assert
+ // method with correct type was called
+ systemWrapper.Verify(v =>
+ v.SetExecutionEnvironment(
+ It.Is(i => i == typeof(PowertoolsConfigurations))
+ ), Times.Once);
+
+ }
+
#endregion
}
}
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.Common.Tests/Core/PowertoolsEnvironmentTest.cs b/libraries/tests/AWS.Lambda.Powertools.Common.Tests/Core/PowertoolsEnvironmentTest.cs
new file mode 100644
index 00000000..8bad4d41
--- /dev/null
+++ b/libraries/tests/AWS.Lambda.Powertools.Common.Tests/Core/PowertoolsEnvironmentTest.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Moq;
+using Xunit;
+
+namespace AWS.Lambda.Powertools.Common.Tests;
+
+public class PowertoolsEnvironmentTest : IDisposable
+{
+ [Fact]
+ public void Set_Execution_Environment()
+ {
+ // Arrange
+ var systemWrapper = new SystemWrapper(new MockEnvironment());
+
+ // Act
+ systemWrapper.SetExecutionEnvironment(this);
+
+ // Assert
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/Fake/1.0.0", systemWrapper.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
+ }
+
+ [Fact]
+ public void Set_Execution_Environment_WhenEnvironmentHasValue()
+ {
+ // Arrange
+ var systemWrapper = new SystemWrapper(new MockEnvironment());
+
+ systemWrapper.SetEnvironmentVariable("AWS_EXECUTION_ENV", "ExistingValuesInUserAgent");
+
+ // Act
+ systemWrapper.SetExecutionEnvironment(this);
+
+ // Assert
+ Assert.Equal($"ExistingValuesInUserAgent {Constants.FeatureContextIdentifier}/Fake/1.0.0", systemWrapper.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
+ }
+
+ [Fact]
+ public void Set_Multiple_Execution_Environment()
+ {
+ // Arrange
+ var systemWrapper = new SystemWrapper(new MockEnvironment());
+
+ // Act
+ systemWrapper.SetExecutionEnvironment(this);
+
+ // Assert
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/Fake/1.0.0", systemWrapper.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
+ }
+
+ [Fact]
+ public void Set_Execution_Real_Environment()
+ {
+ // Arrange
+ var systemWrapper = new SystemWrapper(new PowertoolsEnvironment());
+
+ // Act
+ systemWrapper.SetExecutionEnvironment(this);
+
+ // Assert
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/Tests/1.0.0", systemWrapper.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
+ }
+
+ [Fact]
+ public void Set_Execution_Real_Environment_Multiple()
+ {
+ // Arrange
+ var systemWrapper = new SystemWrapper(new PowertoolsEnvironment());
+
+ // Act
+ systemWrapper.SetExecutionEnvironment(this);
+ systemWrapper.SetExecutionEnvironment(systemWrapper);
+
+ // Assert
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/Tests/1.0.0 {Constants.FeatureContextIdentifier}/Common/0.0.1", systemWrapper.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
+ }
+
+ [Fact]
+ public void Set_Execution_Real_Environment_Multiple_Avoid_Duplicate()
+ {
+ // Arrange
+ var systemWrapper = new SystemWrapper(new PowertoolsEnvironment());
+
+ // Act
+ systemWrapper.SetExecutionEnvironment(this);
+ systemWrapper.SetExecutionEnvironment(this);
+
+ // Assert
+ Assert.Equal($"{Constants.FeatureContextIdentifier}/Tests/1.0.0", systemWrapper.GetEnvironmentVariable("AWS_EXECUTION_ENV"));
+ }
+
+ public void Dispose()
+ {
+ //Do cleanup actions here
+
+ Environment.SetEnvironmentVariable("AWS_EXECUTION_ENV", null);
+ }
+}
+
+///
+/// Fake Environment for testing
+///
+class MockEnvironment : IPowertoolsEnvironment
+{
+ private readonly Dictionary _mockEnvironment = new();
+
+ public string GetEnvironmentVariable(string variableName)
+ {
+ return _mockEnvironment.TryGetValue(variableName, out var value) ? value : null;
+ }
+
+ public void SetEnvironmentVariable(string variableName, string value)
+ {
+ // Check for entry not existing and add to dictionary
+ _mockEnvironment[variableName] = value;
+ }
+
+ public string GetAssemblyName(T type)
+ {
+ return "AWS.Lambda.Powertools.Fake";
+ }
+
+ public string GetAssemblyVersion(T type)
+ {
+ return "1.0.0";
+ }
+}
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/PowertoolsLoggerTest.cs b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/PowertoolsLoggerTest.cs
index d962ba2f..f0ec6d01 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/PowertoolsLoggerTest.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/PowertoolsLoggerTest.cs
@@ -1220,5 +1220,42 @@ public void Log_WhenMemoryStream_LogsBase64String_UnsafeRelaxedJsonEscaping()
)
), Times.Once);
}
+
+ [Fact]
+ public void Log_Set_Execution_Environment_Context()
+ {
+ // Arrange
+ var loggerName = Guid.NewGuid().ToString();
+ var assemblyName = "AWS.Lambda.Powertools.Logger";
+ var assemblyVersion = "1.0.0";
+
+ var env = new Mock();
+ env.Setup(x => x.GetAssemblyName(It.IsAny())).Returns(assemblyName);
+ env.Setup(x => x.GetAssemblyVersion(It.IsAny())).Returns(assemblyVersion);
+
+ // Act
+
+ var wrapper = new SystemWrapper(env.Object);
+ var conf = new PowertoolsConfigurations(wrapper);
+
+ var logger = new PowertoolsLogger(loggerName,conf, wrapper, () =>
+ new LoggerConfiguration
+ {
+ Service = null,
+ MinimumLevel = null
+ });
+ logger.LogInformation("Test");
+
+ // Assert
+ env.Verify(v =>
+ v.SetEnvironmentVariable(
+ "AWS_EXECUTION_ENV", $"{Constants.FeatureContextIdentifier}/Logger/{assemblyVersion}"
+ ), Times.Once);
+
+ env.Verify(v =>
+ v.GetEnvironmentVariable(
+ "AWS_EXECUTION_ENV"
+ ), Times.Once);
+ }
}
}
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs
new file mode 100644
index 00000000..531b1716
--- /dev/null
+++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs
@@ -0,0 +1,36 @@
+using AWS.Lambda.Powertools.Common;
+using Moq;
+using Xunit;
+
+namespace AWS.Lambda.Powertools.Metrics.Tests;
+
+[Collection("Sequential")]
+public class MetricsTests
+{
+ [Fact]
+ public void Metrics_Set_Execution_Environment_Context()
+ {
+ // Arrange
+ var assemblyName = "AWS.Lambda.Powertools.Metrics";
+ var assemblyVersion = "1.0.0";
+
+ var env = new Mock();
+ env.Setup(x => x.GetAssemblyName(It.IsAny())).Returns(assemblyName);
+ env.Setup(x => x.GetAssemblyVersion(It.IsAny())).Returns(assemblyVersion);
+
+ var conf = new PowertoolsConfigurations(new SystemWrapper(env.Object));
+
+ var metrics = new Metrics(conf);
+
+ // Assert
+ env.Verify(v =>
+ v.SetEnvironmentVariable(
+ "AWS_EXECUTION_ENV", $"{Constants.FeatureContextIdentifier}/Metrics/{assemblyVersion}"
+ ), Times.Once);
+
+ env.Verify(v =>
+ v.GetEnvironmentVariable(
+ "AWS_EXECUTION_ENV"
+ ), Times.Once);
+ }
+}
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/XRayRecorderTests.cs b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/XRayRecorderTests.cs
new file mode 100644
index 00000000..4d45c2c1
--- /dev/null
+++ b/libraries/tests/AWS.Lambda.Powertools.Tracing.Tests/XRayRecorderTests.cs
@@ -0,0 +1,306 @@
+using System;
+using Amazon.XRay.Recorder.Core;
+using Amazon.XRay.Recorder.Core.Internal.Entities;
+using AWS.Lambda.Powertools.Common;
+using AWS.Lambda.Powertools.Tracing.Internal;
+using Moq;
+using Xunit;
+
+namespace AWS.Lambda.Powertools.Tracing.Tests;
+
+public class XRayRecorderTests
+{
+ [Fact]
+ public void Tracing_Set_Execution_Environment_Context()
+ {
+ // Arrange
+ var assemblyName = "AWS.Lambda.Powertools.Tracing";
+ var assemblyVersion = "1.0.0";
+
+ var env = new Mock();
+ env.Setup(x => x.GetAssemblyName(It.IsAny())).Returns(assemblyName);
+ env.Setup(x => x.GetAssemblyVersion(It.IsAny())).Returns(assemblyVersion);
+
+ var conf = new PowertoolsConfigurations(new SystemWrapper(env.Object));
+ var awsXray = new Mock();
+
+ // Act
+ var xRayRecorder = new XRayRecorder(awsXray.Object, conf);
+
+ // Assert
+ env.Verify(v =>
+ v.SetEnvironmentVariable(
+ "AWS_EXECUTION_ENV", $"{Constants.FeatureContextIdentifier}/Tracing/{assemblyVersion}"
+ ), Times.Once);
+
+ env.Verify(v =>
+ v.GetEnvironmentVariable(
+ "AWS_EXECUTION_ENV"
+ ), Times.Once);
+
+ Assert.NotNull(xRayRecorder);
+ }
+
+ [Fact]
+ public void Tracing_Instance()
+ {
+ // Arrange
+ var conf = new Mock();
+ var awsXray = new Mock();
+
+ // Act
+
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ // Assert
+ Assert.Equal(tracing, XRayRecorder.Instance);
+ }
+
+ [Fact]
+ public void Tracing_Being_Subsegment()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(true);
+
+ var awsXray = new Mock();
+
+ // Act
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ tracing.BeginSubsegment("test");
+
+ // Assert
+ awsXray.Verify(v =>
+ v.BeginSubsegment("test", null
+ ), Times.Once);
+ }
+
+ [Fact]
+ public void Tracing_Set_Namespace()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(true);
+
+ var awsXray = new Mock();
+
+ // Act
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ tracing.SetNamespace("test");
+
+ // Assert
+ awsXray.Verify(v =>
+ v.SetNamespace("test"
+ ), Times.Once);
+ }
+
+ [Fact]
+ public void Tracing_Add_Annotation()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(true);
+
+ var awsXray = new Mock();
+
+ // Act
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ tracing.AddAnnotation("key", "value");
+
+ // Assert
+ awsXray.Verify(v =>
+ v.AddAnnotation("key", "value"
+ ), Times.Once);
+ }
+
+ [Fact]
+ public void Tracing_Add_Metadata()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(true);
+
+ var awsXray = new Mock();
+
+ // Act
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ tracing.AddMetadata("nameSpace","key", "value");
+
+ // Assert
+ awsXray.Verify(v =>
+ v.AddMetadata("nameSpace","key", "value"
+ ), Times.Once);
+ }
+
+ [Fact]
+ public void Tracing_End_Subsegment()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(true);
+
+ var awsXray = new Mock();
+
+ // Act
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ tracing.EndSubsegment();
+
+ // Assert
+ awsXray.Verify(v =>
+ v.EndSubsegment(null), Times.Once);
+ }
+
+ [Fact]
+ public void Tracing_Get_Entity_In_Lambda_Environment()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(true);
+
+ var awsXray = new Mock();
+ awsXray.Setup(x => x.TraceContext.GetEntity()).Returns(new Subsegment("root"));
+
+ // Act
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ tracing.GetEntity();
+
+ // Assert
+ awsXray.Verify(v =>
+ v.TraceContext.GetEntity(), Times.Once);
+ }
+
+ [Fact]
+ public void Tracing_Get_Entity_Outside_Lambda_Environment()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(false);
+
+ var awsXray = new Mock();
+
+ // Act
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ var entity = tracing.GetEntity();
+
+ // Assert
+ Assert.Equivalent("Root",entity.Name);
+ }
+
+ [Fact]
+ public void Tracing_Set_Entity()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(true);
+
+ var segment = new Segment("test");
+
+ var awsXray = new Mock();
+ awsXray.Setup(x => x.TraceContext.SetEntity(segment));
+
+ // Act
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ tracing.SetEntity(segment);
+
+ // Assert
+ awsXray.Verify(v =>
+ v.TraceContext.SetEntity(segment), Times.Once);
+ }
+
+ [Fact]
+ public void Tracing_Add_Exception()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(true);
+
+ var ex = new ArgumentException("test");
+
+ var awsXray = new Mock();
+ awsXray.Setup(x => x.AddException(ex));
+
+ // Act
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ tracing.AddException(ex);
+
+ // Assert
+ awsXray.Verify(v =>
+ v.AddException(ex), Times.Once);
+ }
+
+ [Fact]
+ public void Tracing_Add_Http_Information()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(true);
+
+ var key = "key";
+ var value = "value";
+
+ var awsXray = new Mock();
+ awsXray.Setup(x => x.AddHttpInformation(key,value));
+
+ // Act
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ tracing.AddHttpInformation(key,value);
+
+ // Assert
+ awsXray.Verify(v =>
+ v.AddHttpInformation(key,value), Times.Once);
+ }
+
+ [Fact]
+ public void Tracing_All_When_Outside_Lambda()
+ {
+ // Arrange
+ var conf = new Mock();
+ conf.Setup(c => c.IsLambdaEnvironment).Returns(false);
+
+ var awsXray = new Mock();
+ var tracing = new XRayRecorder(awsXray.Object, conf.Object);
+
+ // Act
+
+ tracing.AddHttpInformation(It.IsAny(),It.IsAny());
+ tracing.AddException(It.IsAny());
+ tracing.SetEntity(It.IsAny());
+ tracing.EndSubsegment();
+ tracing.AddMetadata(It.IsAny(),It.IsAny(), It.IsAny());
+ tracing.AddAnnotation(It.IsAny(),It.IsAny());
+ tracing.SetNamespace(It.IsAny());
+ tracing.BeginSubsegment(It.IsAny());
+
+ // Assert
+ awsXray.Verify(v =>
+ v.AddHttpInformation(It.IsAny(),It.IsAny()), Times.Never);
+ awsXray.Verify(v =>
+ v.AddException(It.IsAny()), Times.Never);
+ awsXray.Verify(v =>
+ v.TraceContext.SetEntity(It.IsAny()), Times.Never);
+ awsXray.Verify(v =>
+ v.EndSubsegment(null), Times.Never);
+ awsXray.Verify(v =>
+ v.AddMetadata(It.IsAny(),It.IsAny(), It.IsAny()
+ ), Times.Never);
+ awsXray.Verify(v =>
+ v.AddAnnotation(It.IsAny(),It.IsAny()
+ ), Times.Never);
+ awsXray.Verify(v =>
+ v.SetNamespace(It.IsAny()
+ ), Times.Never);
+ awsXray.Verify(v =>
+ v.BeginSubsegment(It.IsAny(), null
+ ), Times.Never);
+ }
+}
\ No newline at end of file