From 947fe6f02262ccbd61a94feb3bbbb151400ec62a Mon Sep 17 00:00:00 2001 From: Henrique <999396+hjgraca@users.noreply.github.com> Date: Thu, 23 Jan 2025 17:04:02 +0000 Subject: [PATCH] Create a new Logging provider when the Aspect (decorator) is called. Add tests --- .../Internal/LoggingAspect.cs | 2 +- .../Attributes/LoggingAttributeTest.cs | 62 +++++++++++++++++ .../Handlers/TestHandlers.cs | 69 +++++++++++++------ .../PowertoolsLoggerTest.cs | 5 +- .../TestSetup.cs | 17 ++++- .../test/Function.Tests/FunctionTests.cs | 2 +- 6 files changed, 132 insertions(+), 25 deletions(-) diff --git a/libraries/src/AWS.Lambda.Powertools.Logging/Internal/LoggingAspect.cs b/libraries/src/AWS.Lambda.Powertools.Logging/Internal/LoggingAspect.cs index 5a107831e..c92566e27 100644 --- a/libraries/src/AWS.Lambda.Powertools.Logging/Internal/LoggingAspect.cs +++ b/libraries/src/AWS.Lambda.Powertools.Logging/Internal/LoggingAspect.cs @@ -138,7 +138,7 @@ public void OnEntry( _correlationIdPath = trigger.CorrelationIdPath; _clearState = trigger.ClearState; - Logger.LoggerProvider ??= new LoggerProvider(_config, _powertoolsConfigurations, _systemWrapper); + Logger.LoggerProvider = new LoggerProvider(_config, _powertoolsConfigurations, _systemWrapper); if (!_initializeContext) return; diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/Attributes/LoggingAttributeTest.cs b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/Attributes/LoggingAttributeTest.cs index 760067136..892a2bafe 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/Attributes/LoggingAttributeTest.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/Attributes/LoggingAttributeTest.cs @@ -471,10 +471,72 @@ public void Should_Log_When_Not_Using_Decorator() Arg.Is(i => i.Contains("\"level\":\"Information\",\"service\":\"service_undefined\",\"name\":\"AWS.Lambda.Powertools.Logging.Logger\",\"message\":\"test\"}")) ); } + + public void Dispose() + { + Environment.SetEnvironmentVariable("POWERTOOLS_LOGGER_CASE", ""); + Environment.SetEnvironmentVariable("POWERTOOLS_SERVICE_NAME", ""); + LoggingAspect.ResetForTest(); + PowertoolsLoggingSerializer.ClearOptions(); + } + } + + [Collection("A Sequential")] + public class ServiceTests : IDisposable + { + private readonly TestServiceHandler _testHandler; + + public ServiceTests() + { + _testHandler = new TestServiceHandler(); + } + + [Fact] + public void When_Setting_Service_Should_Override_Env() + { + // Arrange + var consoleOut = Substitute.For(); + SystemWrapper.Instance.SetOut(consoleOut); + + // Act + _testHandler.LogWithEnv(); + _testHandler.Handler(); + + // Assert + + consoleOut.Received(1).WriteLine( + Arg.Is(i => i.Contains("\"level\":\"Information\",\"service\":\"Environment Service\",\"name\":\"AWS.Lambda.Powertools.Logging.Logger\",\"message\":\"Service: Environment Service\"")) + ); + consoleOut.Received(1).WriteLine( + Arg.Is(i => i.Contains("\"level\":\"Information\",\"service\":\"Attribute Service\",\"name\":\"AWS.Lambda.Powertools.Logging.Logger\",\"message\":\"Service: Attribute Service\"")) + ); + } + + [Fact] + public void When_Setting_Service_Should_Override_Env_And_Empty() + { + // Arrange + var consoleOut = Substitute.For(); + SystemWrapper.Instance.SetOut(consoleOut); + + // Act + _testHandler.LogWithAndWithoutEnv(); + _testHandler.Handler(); + + // Assert + + consoleOut.Received(2).WriteLine( + Arg.Is(i => i.Contains("\"level\":\"Information\",\"service\":\"service_undefined\",\"name\":\"AWS.Lambda.Powertools.Logging.Logger\",\"message\":\"Service: service_undefined\"")) + ); + consoleOut.Received(1).WriteLine( + Arg.Is(i => i.Contains("\"level\":\"Information\",\"service\":\"Attribute Service\",\"name\":\"AWS.Lambda.Powertools.Logging.Logger\",\"message\":\"Service: Attribute Service\"")) + ); + } public void Dispose() { Environment.SetEnvironmentVariable("POWERTOOLS_LOGGER_CASE", ""); + Environment.SetEnvironmentVariable("POWERTOOLS_SERVICE_NAME", ""); LoggingAspect.ResetForTest(); PowertoolsLoggingSerializer.ClearOptions(); } diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/Handlers/TestHandlers.cs b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/Handlers/TestHandlers.cs index d22a2eb1f..08fe54d47 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/Handlers/TestHandlers.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/Handlers/TestHandlers.cs @@ -13,6 +13,7 @@ * permissions and limitations under the License. */ +using System; using System.Text.Json.Serialization; using Amazon.Lambda.APIGatewayEvents; using Amazon.Lambda.ApplicationLoadBalancerEvents; @@ -40,12 +41,13 @@ public void TestMethodDebug() public void LogEventNoArgs() { } - - [Logging(LogEvent = true, LoggerOutputCase = LoggerOutputCase.PascalCase, CorrelationIdPath = "/Headers/MyRequestIdHeader")] + + [Logging(LogEvent = true, LoggerOutputCase = LoggerOutputCase.PascalCase, + CorrelationIdPath = "/Headers/MyRequestIdHeader")] public void LogEvent(TestObject testObject, ILambdaContext context) { } - + [Logging(LogEvent = false)] public void LogEventFalse(ILambdaContext context) { @@ -81,99 +83,99 @@ public void CorrelationCloudWatchEvent(CloudWatchEvent cwEvent) public void CorrelationIdFromString(TestObject testObject) { } - + [Logging(CorrelationIdPath = "/headers/my_request_id_header")] public void CorrelationIdFromStringSnake(TestObject testObject) { } - + [Logging(CorrelationIdPath = "/Headers/MyRequestIdHeader", LoggerOutputCase = LoggerOutputCase.PascalCase)] public void CorrelationIdFromStringPascal(TestObject testObject) { } - + [Logging(CorrelationIdPath = "/headers/myRequestIdHeader", LoggerOutputCase = LoggerOutputCase.CamelCase)] public void CorrelationIdFromStringCamel(TestObject testObject) { } - + [Logging(CorrelationIdPath = "/headers/my_request_id_header")] public void CorrelationIdFromStringSnakeEnv(TestObject testObject) { } - + [Logging(CorrelationIdPath = "/Headers/MyRequestIdHeader")] public void CorrelationIdFromStringPascalEnv(TestObject testObject) { } - + [Logging(CorrelationIdPath = "/headers/myRequestIdHeader")] public void CorrelationIdFromStringCamelEnv(TestObject testObject) { } - + [Logging(Service = "test", LoggerOutputCase = LoggerOutputCase.CamelCase)] public void HandlerService() { Logger.LogInformation("test"); } - + [Logging(SamplingRate = 0.5, LoggerOutputCase = LoggerOutputCase.CamelCase, LogLevel = LogLevel.Information)] public void HandlerSamplingRate() { Logger.LogInformation("test"); } - + [Logging(LogLevel = LogLevel.Critical)] public void TestLogLevelCritical() { Logger.LogCritical("test"); } - + [Logging(LogLevel = LogLevel.Critical, LogEvent = true)] public void TestLogLevelCriticalLogEvent(ILambdaContext context) { } - + [Logging(LogLevel = LogLevel.Debug, LogEvent = true)] public void TestLogEventWithoutContext() { } - + [Logging(LogEvent = true, SamplingRate = 0.2, Service = "my_service")] public void TestCustomFormatterWithDecorator(string input, ILambdaContext context) { } - + [Logging(LogEvent = true, SamplingRate = 0.2, Service = "my_service")] public void TestCustomFormatterWithDecoratorNoContext(string input) { } - + public void TestCustomFormatterNoDecorator(string input, ILambdaContext context) { Logger.LogInformation(input); } - + public void TestLogNoDecorator() { Logger.LogInformation("test"); } - + [Logging(Service = "test", LoggerOutputCase = LoggerOutputCase.SnakeCase)] public void TestEnums(string input, ILambdaContext context) { Logger.LogInformation(Pet.Dog); Logger.LogInformation(Thing.Five); } - + public enum Thing { One = 1, Three = 3, Five = 5 } - + [JsonConverter(typeof(JsonStringEnumConverter))] public enum Pet { @@ -181,4 +183,29 @@ public enum Pet Dog = 3, Lizard = 5 } +} + +public class TestServiceHandler +{ + public void LogWithEnv() + { + Environment.SetEnvironmentVariable("POWERTOOLS_SERVICE_NAME", "Environment Service"); + + Logger.LogInformation("Service: Environment Service"); + } + + public void LogWithAndWithoutEnv() + { + Logger.LogInformation("Service: service_undefined"); + + Environment.SetEnvironmentVariable("POWERTOOLS_SERVICE_NAME", "Environment Service"); + + Logger.LogInformation("Service: service_undefined"); + } + + [Logging(Service = "Attribute Service")] + public void Handler() + { + Logger.LogInformation("Service: Attribute Service"); + } } \ 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 b8ab659b8..e034ce33b 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/PowertoolsLoggerTest.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/PowertoolsLoggerTest.cs @@ -29,7 +29,7 @@ namespace AWS.Lambda.Powertools.Logging.Tests { - [Collection("Sequential")] + [Collection("X Sequential")] public class PowertoolsLoggerTest : IDisposable { public PowertoolsLoggerTest() @@ -1337,6 +1337,8 @@ public void Log_WhenMemoryStream_LogsBase64String_UnsafeRelaxedJsonEscaping() [Fact] public void Log_Set_Execution_Environment_Context() { + var _originalValue = Environment.GetEnvironmentVariable("POWERTOOLS_SERVICE_NAME"); + // Arrange var loggerName = Guid.NewGuid().ToString(); var assemblyName = "AWS.Lambda.Powertools.Logger"; @@ -1707,6 +1709,7 @@ public void Log_Should_Use_Powertools_Log_Level_When_Set(bool willLog, LogLevel public void Dispose() { PowertoolsLoggingSerializer.ClearOptions(); + LoggingAspect.ResetForTest(); } } } \ No newline at end of file diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/TestSetup.cs b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/TestSetup.cs index 26f0e2135..708c63c23 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/TestSetup.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/TestSetup.cs @@ -13,6 +13,21 @@ * permissions and limitations under the License. */ +using System.Collections.Generic; +using System.Linq; using Xunit; +using Xunit.Abstractions; -[assembly: CollectionBehavior(DisableTestParallelization = true)] \ No newline at end of file +[assembly: TestCollectionOrderer("AWS.Lambda.Powertools.Logging.Tests.DisplayNameOrderer", "AWS.Lambda.Powertools.Logging.Tests")] +[assembly: CollectionBehavior(DisableTestParallelization = true)] + + +namespace AWS.Lambda.Powertools.Logging.Tests; + +public class DisplayNameOrderer : ITestCollectionOrderer +{ + public IEnumerable OrderTestCollections(IEnumerable testCollections) + { + return testCollections.OrderBy(collection => collection.DisplayName); + } +} diff --git a/libraries/tests/e2e/functions/core/logging/Function/test/Function.Tests/FunctionTests.cs b/libraries/tests/e2e/functions/core/logging/Function/test/Function.Tests/FunctionTests.cs index 8678d68ec..587cc27f5 100644 --- a/libraries/tests/e2e/functions/core/logging/Function/test/Function.Tests/FunctionTests.cs +++ b/libraries/tests/e2e/functions/core/logging/Function/test/Function.Tests/FunctionTests.cs @@ -23,7 +23,7 @@ public FunctionTests(ITestOutputHelper testOutputHelper) [Trait("Category", "AOT")] [Theory] [InlineData("E2ETestLambda_X64_AOT_NET8_logging")] - // [InlineData("E2ETestLambda_ARM_AOT_NET8_metrics")] + [InlineData("E2ETestLambda_ARM_AOT_NET8_logging")] public async Task AotFunctionTest(string functionName) { await TestFunction(functionName);