From d02ae25f1c3f88ac7be1b0be9935980e0ff95a3c Mon Sep 17 00:00:00 2001 From: Henrique <999396+hjgraca@users.noreply.github.com> Date: Tue, 25 Feb 2025 11:22:50 +0000 Subject: [PATCH 1/2] feat(metrics): add support for disabling metrics via environment variable --- docs/core/metrics-v2.md | 21 ++++----- .../Core/Constants.cs | 5 ++ .../Core/IPowertoolsConfigurations.cs | 9 +++- .../Core/PowertoolsConfigurations.cs | 3 ++ .../AWS.Lambda.Powertools.Metrics/Metrics.cs | 14 +++++- .../MetricsTests.cs | 46 +++++++++++++++++++ 6 files changed, 83 insertions(+), 15 deletions(-) diff --git a/docs/core/metrics-v2.md b/docs/core/metrics-v2.md index 5502edde..f070dcc5 100644 --- a/docs/core/metrics-v2.md +++ b/docs/core/metrics-v2.md @@ -52,12 +52,16 @@ Visit the AWS documentation for a complete explanation for [Amazon CloudWatch co **`Metrics`** is implemented as a Singleton to keep track of your aggregate metrics in memory and make them accessible anywhere in your code. To guarantee that metrics are flushed properly the **`MetricsAttribute`** must be added on the lambda handler. -Metrics has two global settings that will be used across all metrics emitted. Use your application or main service as the metric namespace to easily group all metrics: +Metrics has three global settings that will be used across all metrics emitted. Use your application or main service as the metric namespace to easily group all metrics: -Setting | Description | Environment variable | Constructor parameter -------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------- -**Service** | Optionally, sets **service** metric dimension across all metrics e.g. `payment` | `POWERTOOLS_SERVICE_NAME` | `Service` -**Metric namespace** | Logical container where all metrics will be placed e.g. `MyCompanyEcommerce` | `POWERTOOLS_METRICS_NAMESPACE` | `Namespace` + Setting | Description | Environment variable | Decorator parameter +-------------------------------|---------------------------------------------------------------------------------| ------------------------------------------------- |----------------------- + **Metric namespace** | Logical container where all metrics will be placed e.g. `MyCompanyEcommerce` | `POWERTOOLS_METRICS_NAMESPACE` | `Namespace` + **Service** | Optionally, sets **Service** metric dimension across all metrics e.g. `payment` | `POWERTOOLS_SERVICE_NAME` | `Service` +**Disable Powertools Metrics** | Optionally, disables all Powertools metrics |`POWERTOOLS_METRICS_DISABLED` | N/A | + +???+ info + `POWERTOOLS_METRICS_DISABLED` will not disable default metrics created by AWS services. !!! info "Autocomplete Metric Units" All parameters in **`Metrics Attribute`** are optional. Following rules apply: @@ -67,13 +71,6 @@ Setting | Description | Environment variable | Constructor parameter - **CaptureColdStart:** **`false`** by default. - **RaiseOnEmptyMetrics:** **`false`** by default. -### Full list of environment variables - -| Environment variable | Description | Default | -| ------------------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------- | -| **POWERTOOLS_SERVICE_NAME** | Sets service name used for tracing namespace, metrics dimension and structured logging | `"service_undefined"` | -| **POWERTOOLS_METRICS_NAMESPACE** | Sets namespace used for metrics | `None` | - ### Metrics object #### Attribute diff --git a/libraries/src/AWS.Lambda.Powertools.Common/Core/Constants.cs b/libraries/src/AWS.Lambda.Powertools.Common/Core/Constants.cs index 912196da..343faa68 100644 --- a/libraries/src/AWS.Lambda.Powertools.Common/Core/Constants.cs +++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/Constants.cs @@ -130,4 +130,9 @@ internal static class Constants /// Constant for POWERTOOLS_BATCH_THROW_ON_FULL_BATCH_FAILURE environment variable /// internal const string BatchThrowOnFullBatchFailureEnv = "POWERTOOLS_BATCH_THROW_ON_FULL_BATCH_FAILURE"; + + /// + /// Constant for POWERTOOLS_METRICS_DISABLED environment variable + /// + internal const string PowertoolsMetricsDisabledEnv = "POWERTOOLS_METRICS_DISABLED"; } \ 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 ff2c5664..58955a50 100644 --- a/libraries/src/AWS.Lambda.Powertools.Common/Core/IPowertoolsConfigurations.cs +++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/IPowertoolsConfigurations.cs @@ -155,11 +155,16 @@ public interface IPowertoolsConfigurations /// Gets the maximum degree of parallelism to apply during batch processing. /// /// Defaults to 1 (no parallelism). Specify -1 to automatically use the value of ProcessorCount. - int BatchProcessingMaxDegreeOfParallelism { get; } - + int BatchProcessingMaxDegreeOfParallelism { get; } + /// /// Gets a value indicating whether Batch processing will throw an exception on full batch failure. /// /// Defaults to true bool BatchThrowOnFullBatchFailureEnabled { get; } + + /// + /// Gets a value indicating whether Metrics are disabled. + /// + bool MetricsDisabled { get; } } \ 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 cf316389..bb12dbdc 100644 --- a/libraries/src/AWS.Lambda.Powertools.Common/Core/PowertoolsConfigurations.cs +++ b/libraries/src/AWS.Lambda.Powertools.Common/Core/PowertoolsConfigurations.cs @@ -219,4 +219,7 @@ public void SetExecutionEnvironment(T type) /// public bool BatchThrowOnFullBatchFailureEnabled => GetEnvironmentVariableOrDefault(Constants.BatchThrowOnFullBatchFailureEnv, true); + + /// + public bool MetricsDisabled => GetEnvironmentVariableOrDefault(Constants.PowertoolsMetricsDisabledEnv, false); } \ No newline at end of file diff --git a/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs b/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs index 5d403ad4..04936987 100644 --- a/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs +++ b/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs @@ -100,6 +100,11 @@ internal static IMetrics Instance /// private string _functionName; + /// + /// Gets a value indicating whether metrics are disabled. + /// + private bool _disabled; + /// /// Initializes a new instance of the class. /// @@ -156,6 +161,7 @@ internal Metrics(IPowertoolsConfigurations powertoolsConfigurations, string name _context = new MetricsContext(); _raiseOnEmptyMetrics = raiseOnEmptyMetrics; _captureColdStartEnabled = captureColdStartEnabled; + _disabled = _powertoolsConfigurations.MetricsDisabled; Instance = this; _powertoolsConfigurations.SetExecutionEnvironment(this); @@ -167,7 +173,7 @@ internal Metrics(IPowertoolsConfigurations powertoolsConfigurations, string name /// void IMetrics.AddMetric(string key, double value, MetricUnit unit, MetricResolution resolution) { - if (Instance != null) + if (Instance != null && !_disabled) { if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullException( @@ -261,6 +267,9 @@ void IMetrics.SetDefaultDimensions(Dictionary defaultDimensions) /// void IMetrics.Flush(bool metricsOverflow) { + if(_disabled) + return; + if (_context.GetMetrics().Count == 0 && _raiseOnEmptyMetrics) throw new SchemaValidationException(true); @@ -329,6 +338,9 @@ private Dictionary GetDefaultDimensions() void IMetrics.PushSingleMetric(string name, double value, MetricUnit unit, string nameSpace, string service, Dictionary defaultDimensions, MetricResolution resolution) { + if(_disabled) + return; + if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name), "'PushSingleMetric' method requires a valid metrics key. 'Null' or empty values are not allowed."); diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs index 120d1a72..f3c94c27 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/MetricsTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using Amazon.Lambda.Core; using Amazon.Lambda.TestUtilities; using AWS.Lambda.Powertools.Common; @@ -141,6 +142,51 @@ public void Before_When_RaiseOnEmptyMetricsNotSet_Should_Configure_Null() Assert.False(metrics.Options.RaiseOnEmptyMetrics); } + [Fact] + public void When_MetricsDisabled_Should_Not_AddMetric() + { + // Arrange + var conf = Substitute.For(); + conf.MetricsDisabled.Returns(true); + + IMetrics metrics = new Metrics(conf); + var stringWriter = new StringWriter(); + Console.SetOut(stringWriter); + + // Act + metrics.AddMetric("test", 1.0); + metrics.Flush(); + + // Assert + Assert.Empty(stringWriter.ToString()); + + // Cleanup + stringWriter.Dispose(); + Console.SetOut(new StreamWriter(Console.OpenStandardOutput())); + } + + [Fact] + public void When_MetricsDisabled_Should_Not_PushSingleMetric() + { + // Arrange + var conf = Substitute.For(); + conf.MetricsDisabled.Returns(true); + + IMetrics metrics = new Metrics(conf); + var stringWriter = new StringWriter(); + Console.SetOut(stringWriter); + + // Act + metrics.PushSingleMetric("test", 1.0, MetricUnit.Count); + + // Assert + Assert.Empty(stringWriter.ToString()); + + // Cleanup + stringWriter.Dispose(); + Console.SetOut(new StreamWriter(Console.OpenStandardOutput())); + } + // Helper method for the tests internal void TestMethod(ILambdaContext context) { From f2e94df9ab4bbb81711dfb20b6ce37c7c0e19818 Mon Sep 17 00:00:00 2001 From: Henrique <999396+hjgraca@users.noreply.github.com> Date: Thu, 27 Feb 2025 15:28:27 +0000 Subject: [PATCH 2/2] fix flaky test --- .../AWS.Lambda.Powertools.Common.Tests/ConsoleWrapperTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/tests/AWS.Lambda.Powertools.Common.Tests/ConsoleWrapperTests.cs b/libraries/tests/AWS.Lambda.Powertools.Common.Tests/ConsoleWrapperTests.cs index 6395f79a..4da57dc0 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Common.Tests/ConsoleWrapperTests.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Common.Tests/ConsoleWrapperTests.cs @@ -31,6 +31,7 @@ public void Error_Should_Write_To_Error_Console() // Act consoleWrapper.Error("error message"); + writer.Flush(); // Assert Assert.Equal($"error message{Environment.NewLine}", writer.ToString());