From 0ebb61f00a13933c7f5d3d1d961aa088522e0ba8 Mon Sep 17 00:00:00 2001 From: Amir Khairalomoum Date: Wed, 16 Mar 2022 09:16:25 +0000 Subject: [PATCH 1/7] Add LoggingBuilder extensions to support dependency injection for logger --- .../AWS.Lambda.Powertools.Logging.csproj | 1 + .../Internal/LoggerProvider.cs | 4 +- .../LoggingBuilderExtensions.cs | 65 +++++++++++++++ ...AWS.Lambda.Powertools.Logging.Tests.csproj | 1 + .../LoggingBuilderTest.cs | 61 ++++++++++++++ .../EMFValidationTests.cs | 82 +++++++++---------- 6 files changed, 171 insertions(+), 43 deletions(-) create mode 100644 libraries/src/AWS.Lambda.Powertools.Logging/LoggingBuilderExtensions.cs create mode 100644 libraries/tests/AWS.Lambda.Powertools.Logging.Tests/LoggingBuilderTest.cs diff --git a/libraries/src/AWS.Lambda.Powertools.Logging/AWS.Lambda.Powertools.Logging.csproj b/libraries/src/AWS.Lambda.Powertools.Logging/AWS.Lambda.Powertools.Logging.csproj index a6f5c5b3..62a79d4a 100644 --- a/libraries/src/AWS.Lambda.Powertools.Logging/AWS.Lambda.Powertools.Logging.csproj +++ b/libraries/src/AWS.Lambda.Powertools.Logging/AWS.Lambda.Powertools.Logging.csproj @@ -34,6 +34,7 @@ + diff --git a/libraries/src/AWS.Lambda.Powertools.Logging/Internal/LoggerProvider.cs b/libraries/src/AWS.Lambda.Powertools.Logging/Internal/LoggerProvider.cs index 15ec1e66..2b6d7af6 100644 --- a/libraries/src/AWS.Lambda.Powertools.Logging/Internal/LoggerProvider.cs +++ b/libraries/src/AWS.Lambda.Powertools.Logging/Internal/LoggerProvider.cs @@ -25,7 +25,7 @@ namespace AWS.Lambda.Powertools.Logging.Internal; /// Implements the /// /// -internal sealed class LoggerProvider : ILoggerProvider +public sealed class LoggerProvider : ILoggerProvider { /// /// The loggers @@ -42,7 +42,7 @@ internal sealed class LoggerProvider : ILoggerProvider /// Initializes a new instance of the class. /// /// The configuration. - internal LoggerProvider(IOptions config) + public LoggerProvider(IOptions config) { _currentConfig = config?.Value; } diff --git a/libraries/src/AWS.Lambda.Powertools.Logging/LoggingBuilderExtensions.cs b/libraries/src/AWS.Lambda.Powertools.Logging/LoggingBuilderExtensions.cs new file mode 100644 index 00000000..e81ba9a5 --- /dev/null +++ b/libraries/src/AWS.Lambda.Powertools.Logging/LoggingBuilderExtensions.cs @@ -0,0 +1,65 @@ +/* + * 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.Logging.Internal; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Configuration; + +namespace AWS.Lambda.Powertools.Logging; + +/// +/// Class LoggingBuilderExtensions. +/// +public static class LoggingBuilderExtensions +{ + /// + /// Adds Powertools logger to the factory. + /// + /// The to use. + public static ILoggingBuilder AddPowertoolsLogger( + this ILoggingBuilder builder) + { + builder.AddConfiguration(); + + builder.Services.TryAddEnumerable( + ServiceDescriptor.Singleton()); + + LoggerProviderOptions.RegisterProviderOptions + (builder.Services); + + return builder; + } + + /// + /// Adds Powertools logger to the factory. + /// + /// The to use. + /// A delegate to configure the . + public static ILoggingBuilder AddPowertoolsLogger( + this ILoggingBuilder builder, + Action configure) + { + if (configure == null) + throw new ArgumentNullException(nameof(configure)); + + builder.AddPowertoolsLogger(); + builder.Services.Configure(configure); + + return builder; + } +} \ No newline at end of file diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj index 4eeca484..7682059e 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj +++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj @@ -10,6 +10,7 @@ + diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/LoggingBuilderTest.cs b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/LoggingBuilderTest.cs new file mode 100644 index 00000000..475aa89b --- /dev/null +++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/LoggingBuilderTest.cs @@ -0,0 +1,61 @@ +/* + * 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 System.IO; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace AWS.Lambda.Powertools.Logging.Tests; + +public class LoggingBuilderTest +{ + [Fact] + public void LoggingBuilder_WhenAddPowertoolsLogger_RegistersLoggingService() + { + // Arrange + var service = Guid.NewGuid().ToString(); + var message = Guid.NewGuid().ToString(); + var logLevel = LogLevel.Information; + var loggerOutputCase = LoggerOutputCase.SnakeCase; + + var consoleOut = new StringWriter(); + Console.SetOut(consoleOut); + + using var host = Host.CreateDefaultBuilder() + .ConfigureLogging(builder => + builder.ClearProviders() + .AddPowertoolsLogger(configuration => + { + configuration.Service = service; + configuration.MinimumLevel = logLevel; + configuration.LoggerOutputCase = loggerOutputCase; + })) + .Build(); + + var logger = host.Services.GetRequiredService>(); + + // Act + logger.LogInformation(message); + var logEntry = consoleOut.ToString(); + + // Assert + Assert.Contains($"\"service\":\"{service}\"", logEntry); + Assert.Contains($"\"level\":\"{logLevel}\"", logEntry); + Assert.Contains($"\"message\":\"{message}\"", logEntry); + } +} \ No newline at end of file diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs index a9b98da8..ac89ef71 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs @@ -38,7 +38,7 @@ public void WhenCaptureColdStart_CreateSeparateBlob() var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -53,13 +53,13 @@ public void WhenCaptureColdStart_CreateSeparateBlob() // Act handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); + Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); handler.OnExit(eventArgs); var metricsOutput = consoleOut.ToString(); // Assert - var metricBlobs = AllIndexesOf(metricsOutput.ToString(), "_aws"); + var metricBlobs = AllIndexesOf(metricsOutput, "_aws"); Assert.Equal(2, metricBlobs.Count); @@ -78,7 +78,7 @@ public void WhenCaptureColdStartEnabled_ValidateExists() var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -93,7 +93,7 @@ public void WhenCaptureColdStartEnabled_ValidateExists() // Act handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); + Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); handler.OnExit(eventArgs); var result = consoleOut.ToString(); @@ -116,7 +116,7 @@ public void When100MetricsAreAdded_FlushAutomatically() var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -132,9 +132,9 @@ public void When100MetricsAreAdded_FlushAutomatically() // Act handler.OnEntry(eventArgs); - for (int i = 0; i <= 100; i++) + for (var i = 0; i <= 100; i++) { - Powertools.Metrics.Metrics.AddMetric($"Metric Name {i + 1}", i, MetricUnit.Count); + Metrics.AddMetric($"Metric Name {i + 1}", i, MetricUnit.Count); } handler.OnExit(eventArgs); @@ -158,7 +158,7 @@ public void WhenMoreThan9DimensionsAdded_ThrowArgumentOutOfRangeException() var methodName = Guid.NewGuid().ToString(); var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -174,11 +174,11 @@ public void WhenMoreThan9DimensionsAdded_ThrowArgumentOutOfRangeException() // Act handler.OnEntry(eventArgs); - Action act = () => + var act = () => { for (var i = 0; i <= 9; i++) { - Powertools.Metrics.Metrics.AddDimension($"Dimension Name {i + 1}", $"Dimension Value {i + 1}"); + Metrics.AddDimension($"Dimension Name {i + 1}", $"Dimension Value {i + 1}"); } }; @@ -199,7 +199,7 @@ public void WhenNamespaceNotDefined_ThrowSchemaValidationException() var methodName = Guid.NewGuid().ToString(); var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object ); @@ -211,10 +211,10 @@ public void WhenNamespaceNotDefined_ThrowSchemaValidationException() var eventArgs = new AspectEventArgs { Name = methodName }; // Act - Action act = () => + var act = () => { handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); + Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); handler.OnExit(eventArgs); }; @@ -237,7 +237,7 @@ public void WhenDimensionsAreAdded_MustExistAsMembers() var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -252,8 +252,8 @@ public void WhenDimensionsAreAdded_MustExistAsMembers() // Act handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.AddDimension("functionVersion", "$LATEST"); - Powertools.Metrics.Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); + Metrics.AddDimension("functionVersion", "$LATEST"); + Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); handler.OnExit(eventArgs); var result = consoleOut.ToString(); @@ -275,7 +275,7 @@ public void WhenNamespaceIsDefined_AbleToRetrieveNamespace() // Arrange var methodName = Guid.NewGuid().ToString(); var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics(configurations.Object); + var logger = new Metrics(configurations.Object); var handler = new MetricsAspectHandler( logger, @@ -286,9 +286,9 @@ public void WhenNamespaceIsDefined_AbleToRetrieveNamespace() // Act handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.SetNamespace("dotnet-powertools-test"); + Metrics.SetNamespace("dotnet-powertools-test"); - var result = Powertools.Metrics.Metrics.GetNamespace(); + var result = Metrics.GetNamespace(); // Assert Assert.Equal("dotnet-powertools-test", result); @@ -307,7 +307,7 @@ public void WhenMetricsDefined_AbleToAddMetadata() Console.SetOut(consoleOut); var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -322,7 +322,7 @@ public void WhenMetricsDefined_AbleToAddMetadata() // Act handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.AddMetadata("test_metadata", "test_value"); + Metrics.AddMetadata("test_metadata", "test_value"); handler.OnExit(eventArgs); var result = consoleOut.ToString(); @@ -346,7 +346,7 @@ public void WhenDefaultDimensionsSet_ValidInitialization() var defaultDimensions = new Dictionary { { "CustomDefaultDimension", "CustomDefaultDimensionValue" } }; var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -361,8 +361,8 @@ public void WhenDefaultDimensionsSet_ValidInitialization() // Act handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.SetDefaultDimensions(defaultDimensions); - Powertools.Metrics.Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); + Metrics.SetDefaultDimensions(defaultDimensions); + Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); handler.OnExit(eventArgs); var result = consoleOut.ToString(); @@ -383,7 +383,7 @@ public void WhenMetricIsNegativeValue_ThrowException() var methodName = Guid.NewGuid().ToString(); var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -397,11 +397,11 @@ public void WhenMetricIsNegativeValue_ThrowException() var eventArgs = new AspectEventArgs { Name = methodName }; // Act - Action act = () => + var act = () => { - int metricValue = -1; + const int metricValue = -1; handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.AddMetric("TestMetric", metricValue, MetricUnit.Count); + Metrics.AddMetric("TestMetric", metricValue, MetricUnit.Count); handler.OnExit(eventArgs); }; @@ -424,7 +424,7 @@ public void WhenDefaultDimensionSet_IgnoreDuplicates() var configurations = new Mock(); var defaultDimensions = new Dictionary { { "CustomDefaultDimension", "CustomDefaultDimensionValue" } }; - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -439,9 +439,9 @@ public void WhenDefaultDimensionSet_IgnoreDuplicates() // Act handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.SetDefaultDimensions(defaultDimensions); - Powertools.Metrics.Metrics.SetDefaultDimensions(defaultDimensions); - Powertools.Metrics.Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); + Metrics.SetDefaultDimensions(defaultDimensions); + Metrics.SetDefaultDimensions(defaultDimensions); + Metrics.AddMetric("TestMetric", 1, MetricUnit.Count); handler.OnExit(eventArgs); var result = consoleOut.ToString(); @@ -463,7 +463,7 @@ public void WhenMetricsAndMetadataAdded_ValidateOutput() Console.SetOut(consoleOut); var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -478,9 +478,9 @@ public void WhenMetricsAndMetadataAdded_ValidateOutput() // Act handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.AddDimension("functionVersion", "$LATEST"); - Powertools.Metrics.Metrics.AddMetric("Time", 100.7, MetricUnit.Milliseconds); - Powertools.Metrics.Metrics.AddMetadata("env", "dev"); + Metrics.AddDimension("functionVersion", "$LATEST"); + Metrics.AddMetric("Time", 100.7, MetricUnit.Milliseconds); + Metrics.AddMetadata("env", "dev"); handler.OnExit(eventArgs); var result = consoleOut.ToString(); @@ -504,7 +504,7 @@ public void WhenMetricsWithSameNameAdded_ValidateMetricArray() var configurations = new Mock(); - var logger = new Powertools.Metrics.Metrics( + var logger = new Metrics( configurations.Object, nameSpace: "dotnet-powertools-test", service: "testService" @@ -519,9 +519,9 @@ public void WhenMetricsWithSameNameAdded_ValidateMetricArray() // Act handler.OnEntry(eventArgs); - Powertools.Metrics.Metrics.AddDimension("functionVersion", "$LATEST"); - Powertools.Metrics.Metrics.AddMetric("Time", 100.5, MetricUnit.Milliseconds); - Powertools.Metrics.Metrics.AddMetric("Time", 200, MetricUnit.Milliseconds); + Metrics.AddDimension("functionVersion", "$LATEST"); + Metrics.AddMetric("Time", 100.5, MetricUnit.Milliseconds); + Metrics.AddMetric("Time", 200, MetricUnit.Milliseconds); handler.OnExit(eventArgs); var result = consoleOut.ToString(); From c464047f697024c50c0f901644c92c0be20aa51c Mon Sep 17 00:00:00 2001 From: Amir Khairalomoum Date: Mon, 28 Mar 2022 18:09:35 +0100 Subject: [PATCH 2/7] Remove LoggingBuilder extensions to support dependency injection for logger --- .../LoggingBuilderExtensions.cs | 65 ------------------- ...AWS.Lambda.Powertools.Logging.Tests.csproj | 16 ++--- .../LoggingBuilderTest.cs | 61 ----------------- 3 files changed, 8 insertions(+), 134 deletions(-) delete mode 100644 libraries/src/AWS.Lambda.Powertools.Logging/LoggingBuilderExtensions.cs delete mode 100644 libraries/tests/AWS.Lambda.Powertools.Logging.Tests/LoggingBuilderTest.cs diff --git a/libraries/src/AWS.Lambda.Powertools.Logging/LoggingBuilderExtensions.cs b/libraries/src/AWS.Lambda.Powertools.Logging/LoggingBuilderExtensions.cs deleted file mode 100644 index e81ba9a5..00000000 --- a/libraries/src/AWS.Lambda.Powertools.Logging/LoggingBuilderExtensions.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.Logging.Internal; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Configuration; - -namespace AWS.Lambda.Powertools.Logging; - -/// -/// Class LoggingBuilderExtensions. -/// -public static class LoggingBuilderExtensions -{ - /// - /// Adds Powertools logger to the factory. - /// - /// The to use. - public static ILoggingBuilder AddPowertoolsLogger( - this ILoggingBuilder builder) - { - builder.AddConfiguration(); - - builder.Services.TryAddEnumerable( - ServiceDescriptor.Singleton()); - - LoggerProviderOptions.RegisterProviderOptions - (builder.Services); - - return builder; - } - - /// - /// Adds Powertools logger to the factory. - /// - /// The to use. - /// A delegate to configure the . - public static ILoggingBuilder AddPowertoolsLogger( - this ILoggingBuilder builder, - Action configure) - { - if (configure == null) - throw new ArgumentNullException(nameof(configure)); - - builder.AddPowertoolsLogger(); - builder.Services.Configure(configure); - - return builder; - } -} \ No newline at end of file diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj index 7682059e..90a37f77 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj +++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj @@ -8,12 +8,12 @@ - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -21,8 +21,8 @@ - - + + diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/LoggingBuilderTest.cs b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/LoggingBuilderTest.cs deleted file mode 100644 index 475aa89b..00000000 --- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/LoggingBuilderTest.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 System.IO; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Xunit; - -namespace AWS.Lambda.Powertools.Logging.Tests; - -public class LoggingBuilderTest -{ - [Fact] - public void LoggingBuilder_WhenAddPowertoolsLogger_RegistersLoggingService() - { - // Arrange - var service = Guid.NewGuid().ToString(); - var message = Guid.NewGuid().ToString(); - var logLevel = LogLevel.Information; - var loggerOutputCase = LoggerOutputCase.SnakeCase; - - var consoleOut = new StringWriter(); - Console.SetOut(consoleOut); - - using var host = Host.CreateDefaultBuilder() - .ConfigureLogging(builder => - builder.ClearProviders() - .AddPowertoolsLogger(configuration => - { - configuration.Service = service; - configuration.MinimumLevel = logLevel; - configuration.LoggerOutputCase = loggerOutputCase; - })) - .Build(); - - var logger = host.Services.GetRequiredService>(); - - // Act - logger.LogInformation(message); - var logEntry = consoleOut.ToString(); - - // Assert - Assert.Contains($"\"service\":\"{service}\"", logEntry); - Assert.Contains($"\"level\":\"{logLevel}\"", logEntry); - Assert.Contains($"\"message\":\"{message}\"", logEntry); - } -} \ No newline at end of file From cc89699c96ff6f52f93995d6fabe04bb8eb01473 Mon Sep 17 00:00:00 2001 From: Amir Khairalomoum Date: Mon, 28 Mar 2022 18:12:03 +0100 Subject: [PATCH 3/7] Remove extra dependency --- .../AWS.Lambda.Powertools.Logging.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/src/AWS.Lambda.Powertools.Logging/AWS.Lambda.Powertools.Logging.csproj b/libraries/src/AWS.Lambda.Powertools.Logging/AWS.Lambda.Powertools.Logging.csproj index 62a79d4a..a6f5c5b3 100644 --- a/libraries/src/AWS.Lambda.Powertools.Logging/AWS.Lambda.Powertools.Logging.csproj +++ b/libraries/src/AWS.Lambda.Powertools.Logging/AWS.Lambda.Powertools.Logging.csproj @@ -34,7 +34,6 @@ - From 24e69117ecf3afa27417a008452f842a322ee5f3 Mon Sep 17 00:00:00 2001 From: Amir Khairalomoum Date: Mon, 28 Mar 2022 18:14:46 +0100 Subject: [PATCH 4/7] Remove extra dependency --- .../AWS.Lambda.Powertools.Logging.Tests.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj index 90a37f77..c167fa1e 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj +++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj @@ -10,7 +10,6 @@ - From c3aa2f840a4a3dac83eaa4be5c8f66da5e25bb4b Mon Sep 17 00:00:00 2001 From: Amir Khairalomoum Date: Mon, 28 Mar 2022 20:20:27 +0100 Subject: [PATCH 5/7] add logging attribute class documentation --- .../LoggingAttribute.cs | 33 +++++++++++++++++-- ...AWS.Lambda.Powertools.Logging.Tests.csproj | 14 ++++---- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs b/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs index 0e2031a8..57e5b0bf 100644 --- a/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs +++ b/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs @@ -21,10 +21,37 @@ namespace AWS.Lambda.Powertools.Logging; /// -/// Class LoggingAttribute. -/// Implements the +/// Creates and setups a logger to format statements in JSON. +/// +/// Includes service name and any additional key=value into logs +/// It also accepts both service name or level explicitly via env vars +/// +/// Environment variables +/// --------------------- +/// POWERTOOLS_SERVICE_NAME : string +/// service name +/// POWERTOOLS_LOG_LEVEL: string +/// logging level (e.g. Information, Debug, and Trace) +/// POWERTOOLS_LOGGER_CASE: string +/// logger output case (e.g. CamelCase, PascalCase, and SnakeCase) +/// POWERTOOLS_LOGGER_SAMPLE_RATE: double +/// sampling rate ranging from 0 to 1, 1 being 100% sampling +/// +/// Parameters +/// ---------- +/// Service : string, optional +/// service name to be appended in logs, by default "service_undefined" +/// LogLevel : enum, optional +/// logging level (e.g. Information, Debug, and Trace), by default Information +/// LoggerOutputCase : enum, optional +/// logger output case (e.g. CamelCase, PascalCase, and SnakeCase) +/// SamplingRate: double, optional +/// sample rate for debug calls within execution context defaults to 0.0 +/// CorrelationIdPath: string, optional +/// pointer path to extract correlation id from input parameter. +/// ClearState: bool, optional +/// clear all custom keys on each request, by default false /// -/// [AttributeUsage(AttributeTargets.Method)] public class LoggingAttribute : MethodAspectAttribute { diff --git a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj index c167fa1e..4eeca484 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj +++ b/libraries/tests/AWS.Lambda.Powertools.Logging.Tests/AWS.Lambda.Powertools.Logging.Tests.csproj @@ -8,11 +8,11 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -20,8 +20,8 @@ - - + + From 1e4eac961dd0e0b4dbf185c9f346c4262c9fdcf9 Mon Sep 17 00:00:00 2001 From: Amir Khairalomoum Date: Mon, 28 Mar 2022 21:56:17 +0100 Subject: [PATCH 6/7] add logging attribute class documentation --- .../LoggingAttribute.cs | 110 +++++++++++++----- 1 file changed, 80 insertions(+), 30 deletions(-) diff --git a/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs b/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs index 57e5b0bf..f45e861f 100644 --- a/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs +++ b/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs @@ -21,37 +21,87 @@ namespace AWS.Lambda.Powertools.Logging; /// -/// Creates and setups a logger to format statements in JSON. -/// -/// Includes service name and any additional key=value into logs -/// It also accepts both service name or level explicitly via env vars -/// -/// Environment variables -/// --------------------- -/// POWERTOOLS_SERVICE_NAME : string -/// service name -/// POWERTOOLS_LOG_LEVEL: string -/// logging level (e.g. Information, Debug, and Trace) -/// POWERTOOLS_LOGGER_CASE: string -/// logger output case (e.g. CamelCase, PascalCase, and SnakeCase) -/// POWERTOOLS_LOGGER_SAMPLE_RATE: double -/// sampling rate ranging from 0 to 1, 1 being 100% sampling -/// -/// Parameters -/// ---------- -/// Service : string, optional -/// service name to be appended in logs, by default "service_undefined" -/// LogLevel : enum, optional -/// logging level (e.g. Information, Debug, and Trace), by default Information -/// LoggerOutputCase : enum, optional -/// logger output case (e.g. CamelCase, PascalCase, and SnakeCase) -/// SamplingRate: double, optional -/// sample rate for debug calls within execution context defaults to 0.0 -/// CorrelationIdPath: string, optional -/// pointer path to extract correlation id from input parameter. -/// ClearState: bool, optional -/// clear all custom keys on each request, by default false +/// Creates and setups a logger to format statements in JSON.
+///
+/// Includes service name and any additional parameter logs.
+/// It also accepts both service name or lo level explicitly via Environment variables.
+///
+/// Environment variables
+/// ---------------------
+/// +/// +/// Variable name +/// Description +/// +/// +/// POWERTOOLS_SERVICE_NAME +/// string, service name +/// +/// +/// POWERTOOLS_LOG_LEVEL +/// string, logging level (e.g. Information, Debug, and Trace) +/// +/// +/// POWERTOOLS_LOGGER_CASE +/// string, logger output case (e.g. CamelCase, PascalCase, and SnakeCase) +/// +/// +/// POWERTOOLS_LOGGER_SAMPLE_RATE +/// double, sampling rate ranging from 0 to 1, 1 being 100% sampling +/// +/// +///
+/// Parameters
+/// -----------
+/// +/// +/// Parameter name +/// Description +/// +/// +/// Service +/// string, service name to be appended in logs, by default "service_undefined" +/// +/// +/// LogLevel +/// enum, logging level (e.g. Information, Debug, and Trace), by default Information +/// +/// +/// LoggerOutputCase +/// enum, logger output case (e.g. CamelCase, PascalCase, and SnakeCase) +/// +/// +/// SamplingRate +/// double, sample rate for debug calls within execution context defaults to 0.0 +/// +/// +/// CorrelationIdPath +/// string, pointer path to extract correlation id from input parameter +/// +/// +/// ClearState +/// bool, clear all custom keys on each request, by default false +/// +/// ///
+/// +/// +/// [Logging( +/// Service = "example", +/// LogEvent = true, +/// ClearState = true, +/// LogLevel = LogLevel.Debug, +/// LoggerOutputCase = LoggerOutputCase.SnakeCase, +/// CorrelationIdPath = "/headers/my_request_id_header") +/// ] +/// public async Task<APIGatewayProxyResponse> FunctionHandler +/// (APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) +/// { +/// ... +/// } +/// +/// + [AttributeUsage(AttributeTargets.Method)] public class LoggingAttribute : MethodAspectAttribute { From 20309e1f6e9a65f43b21ef1d3c2835bca4a7e87f Mon Sep 17 00:00:00 2001 From: Amir Khairalomoum Date: Tue, 29 Mar 2022 12:05:15 +0100 Subject: [PATCH 7/7] add attribute class documentations --- .../LoggingAttribute.cs | 25 ++++-- .../MetricsAttribute.cs | 79 +++++++++++++++- .../TracingAttribute.cs | 90 ++++++++++++++++++- 3 files changed, 181 insertions(+), 13 deletions(-) diff --git a/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs b/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs index f45e861f..d60ee045 100644 --- a/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs +++ b/libraries/src/AWS.Lambda.Powertools.Logging/LoggingAttribute.cs @@ -21,11 +21,25 @@ namespace AWS.Lambda.Powertools.Logging; /// -/// Creates and setups a logger to format statements in JSON.
-///
-/// Includes service name and any additional parameter logs.
-/// It also accepts both service name or lo level explicitly via Environment variables.
+/// Provides a Lambda optimized logger with output structured as JSON.
///
+/// Key features
+/// ---------------------
+/// +/// +/// Capture key fields from Lambda context and cold start +/// +/// +/// Log Lambda event when instructed (disabled by default) +/// +/// +/// Log sampling enables DEBUG log level for a percentage of requests (disabled by default) +/// +/// +/// Append additional keys to structured log at any point in time +/// +/// +///
/// Environment variables
/// ---------------------
/// @@ -87,7 +101,7 @@ namespace AWS.Lambda.Powertools.Logging; /// /// /// [Logging( -/// Service = "example", +/// Service = "Example", /// LogEvent = true, /// ClearState = true, /// LogLevel = LogLevel.Debug, @@ -101,7 +115,6 @@ namespace AWS.Lambda.Powertools.Logging; /// } /// /// - [AttributeUsage(AttributeTargets.Method)] public class LoggingAttribute : MethodAspectAttribute { diff --git a/libraries/src/AWS.Lambda.Powertools.Metrics/MetricsAttribute.cs b/libraries/src/AWS.Lambda.Powertools.Metrics/MetricsAttribute.cs index ce0bde4d..d669c70b 100644 --- a/libraries/src/AWS.Lambda.Powertools.Metrics/MetricsAttribute.cs +++ b/libraries/src/AWS.Lambda.Powertools.Metrics/MetricsAttribute.cs @@ -19,10 +19,83 @@ namespace AWS.Lambda.Powertools.Metrics; /// -/// Class MetricsAttribute. -/// Implements the +/// Creates custom metrics asynchronously by logging metrics to +/// standard output following Amazon CloudWatch Embedded Metric Format (EMF).
+///
+/// Key features
+/// ---------------------
+/// +/// +/// Aggregate up to 100 metrics using a single CloudWatch EMF object (large JSON blob) +/// +/// +/// Validate against common metric definitions mistakes (metric unit, values, max dimensions, max metrics, etc) +/// +/// +/// Metrics are created asynchronously by CloudWatch service, no custom stacks needed +/// +/// +/// Context manager to create a one off metric with a different dimension +/// +/// +///
+/// Environment variables
+/// ---------------------
+/// +/// +/// Variable name +/// Description +/// +/// +/// POWERTOOLS_SERVICE_NAME +/// string, service name +/// +/// +/// POWERTOOLS_METRICS_NAMESPACE +/// string, metric namespace +/// +/// +///
+/// Parameters
+/// -----------
+/// +/// +/// Parameter name +/// Description +/// +/// +/// Service +/// string, service name is used for metric dimension across all metrics, by default service_undefined +/// +/// +/// Namespace +/// string, logical container where all metrics will be placed +/// +/// +/// CaptureColdStart +/// bool, captures cold start during Lambda execution, by default false +/// +/// +/// RaiseOnEmptyMetrics +/// bool, instructs metrics validation to throw exception if no metrics are provided, by default false +/// +/// ///
-/// +/// +/// +/// [Metrics( +/// Service = "Example", +/// Namespace = "ExampleNamespace", +/// CaptureColdStart = true, +/// RaiseOnEmptyMetrics = true) +/// ] +/// public async Task<APIGatewayProxyResponse> FunctionHandler +/// (APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) +/// { +/// ... +/// } +/// +/// [AttributeUsage(AttributeTargets.Method)] public class MetricsAttribute : MethodAspectAttribute { diff --git a/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs b/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs index b2aec39b..0d9d6727 100644 --- a/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs +++ b/libraries/src/AWS.Lambda.Powertools.Tracing/TracingAttribute.cs @@ -19,10 +19,92 @@ namespace AWS.Lambda.Powertools.Tracing; /// -/// Class TracingAttribute. -/// Implements the +/// Creates an opinionated thin wrapper for AWS X-Ray .NET SDK which provides functionality to reduce the overhead of performing common tracing tasks.
+///
+/// Key features
+/// ---------------------
+/// +/// +/// Helper methods to improve the developer experience for creating custom AWS X-Ray subsegments +/// +/// +/// Capture cold start as annotation +/// +/// +/// Capture function responses and full exceptions as metadata +/// +/// +/// Better experience when developing with multiple threads +/// +/// +/// Auto-patch supported modules by AWS X-Ray +/// +/// +///
+/// Environment variables
+/// ---------------------
+/// +/// +/// Variable name +/// Description +/// +/// +/// POWERTOOLS_SERVICE_NAME +/// string, service name +/// +/// +/// POWERTOOLS_TRACER_CAPTURE_RESPONSE +/// bool, disable auto-capture response as metadata (e.g. true, false) +/// +/// +/// POWERTOOLS_TRACER_CAPTURE_ERROR +/// bool, disable auto-capture error as metadata (e.g. true, false) +/// +/// +/// POWERTOOLS_TRACE_DISABLED +/// bool, disable auto-capture error or response as metadata (e.g. true, false) +/// +/// +///
+/// Parameters
+/// -----------
+/// +/// +/// Parameter name +/// Description +/// +/// +/// Service +/// string, service name that will be appended in all tracing metadata +/// +/// +/// SegmentName +/// string, custom segment name for the operation, by default '## {MethodName}' +/// +/// +/// Namespace +/// string, namespace to current subsegment +/// +/// +/// CaptureMode +/// enum, capture mode to record method responses and errors (e.g. EnvironmentVariable, Response, and Error), by default EnvironmentVariable +/// +/// ///
-/// +/// +/// +/// [Tracing( +/// SegmentName = "ExampleSegment", +/// Namespace = "ExampleNamespace", +/// CaptureMode = TracingCaptureMode.ResponseAndError) +/// ] +/// public async Task<APIGatewayProxyResponse> FunctionHandler +/// (APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) +/// { +/// ... +/// } +/// +/// public class TracingAttribute : MethodAspectAttribute { /// @@ -40,7 +122,7 @@ public class TracingAttribute : MethodAspectAttribute public string Namespace { get; set; } = ""; /// - /// Set capture mode to record method responses and exceptions. + /// Set capture mode to record method responses and errors. /// The defaults are the environment variables POWERTOOLS_TRACER_CAPTURE_RESPONSE and /// POWERTOOLS_TRACER_CAPTURE_ERROR. ///