diff --git a/libraries/src/AWS.Lambda.Powertools.Metrics/IMetrics.cs b/libraries/src/AWS.Lambda.Powertools.Metrics/IMetrics.cs
index 5d33f484..6f0b868a 100644
--- a/libraries/src/AWS.Lambda.Powertools.Metrics/IMetrics.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Metrics/IMetrics.cs
@@ -23,7 +23,7 @@ namespace AWS.Lambda.Powertools.Metrics;
/// Implements the
///
///
-public interface IMetrics : IDisposable
+public interface IMetrics
{
///
/// Adds metric
diff --git a/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs b/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs
index 9d55b06a..af72bd89 100644
--- a/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs
+++ b/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs
@@ -25,13 +25,13 @@ namespace AWS.Lambda.Powertools.Metrics;
/// Implements the
///
///
-public class Metrics : IMetrics
+public class Metrics : IMetrics, IDisposable
{
///
/// The instance
///
private static IMetrics _instance;
-
+
///
/// The context
///
@@ -65,15 +65,15 @@ public class Metrics : IMetrics
internal Metrics(IPowertoolsConfigurations powertoolsConfigurations, string nameSpace = null, string service = null,
bool raiseOnEmptyMetrics = false, bool captureColdStartEnabled = false)
{
- if (_instance != null) return;
+ _instance ??= this;
- _instance = this;
_powertoolsConfigurations = powertoolsConfigurations;
_raiseOnEmptyMetrics = raiseOnEmptyMetrics;
_captureColdStartEnabled = captureColdStartEnabled;
_context = InitializeContext(nameSpace, service, null);
_powertoolsConfigurations.SetExecutionEnvironment(this);
+
}
///
@@ -91,11 +91,11 @@ void IMetrics.AddMetric(string key, double value, MetricUnit unit, MetricResolut
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(
- $"'AddMetric' method requires a valid metrics key. 'Null' or empty values are not allowed.");
+ nameof(key), "'AddMetric' method requires a valid metrics key. 'Null' or empty values are not allowed.");
if (value < 0) {
throw new ArgumentException(
- "'AddMetric' method requires a valid metrics value. Value must be >= 0.");
+ "'AddMetric' method requires a valid metrics value. Value must be >= 0.", nameof(value));
}
var metrics = _context.GetMetrics();
@@ -150,8 +150,8 @@ string IMetrics.GetService()
void IMetrics.AddDimension(string key, string value)
{
if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(
- $"'AddDimension' method requires a valid dimension key. 'Null' or empty values are not allowed.");
+ throw new ArgumentNullException(nameof(key),
+ "'AddDimension' method requires a valid dimension key. 'Null' or empty values are not allowed.");
_context.AddDimension(key, value);
}
@@ -168,8 +168,8 @@ void IMetrics.AddDimension(string key, string value)
void IMetrics.AddMetadata(string key, object value)
{
if (string.IsNullOrWhiteSpace(key))
- throw new ArgumentNullException(
- $"'AddMetadata' method requires a valid metadata key. 'Null' or empty values are not allowed.");
+ throw new ArgumentNullException(nameof(key),
+ "'AddMetadata' method requires a valid metadata key. 'Null' or empty values are not allowed.");
_context.AddMetadata(key, value);
}
@@ -177,19 +177,19 @@ void IMetrics.AddMetadata(string key, object value)
///
/// Implements interface that sets default dimension list
///
- /// Default Dimension List
+ /// Default Dimension List
///
/// 'SetDefaultDimensions' method requires a valid key pair. 'Null' or empty
/// values are not allowed.
///
- void IMetrics.SetDefaultDimensions(Dictionary defaultDimensions)
+ void IMetrics.SetDefaultDimensions(Dictionary defaultDimension)
{
- foreach (var item in defaultDimensions)
+ foreach (var item in defaultDimension)
if (string.IsNullOrWhiteSpace(item.Key) || string.IsNullOrWhiteSpace(item.Value))
- throw new ArgumentNullException(
- $"'SetDefaultDimensions' method requires a valid key pair. 'Null' or empty values are not allowed.");
+ throw new ArgumentNullException(nameof(item.Key),
+ "'SetDefaultDimensions' method requires a valid key pair. 'Null' or empty values are not allowed.");
- _context.SetDefaultDimensions(DictionaryToList(defaultDimensions));
+ _context.SetDefaultDimensions(DictionaryToList(defaultDimension));
}
///
@@ -258,8 +258,8 @@ void IMetrics.PushSingleMetric(string metricName, double value, MetricUnit unit,
Dictionary defaultDimensions, MetricResolution metricResolution)
{
if (string.IsNullOrWhiteSpace(metricName))
- throw new ArgumentNullException(
- $"'PushSingleMetric' method requires a valid metrics key. 'Null' or empty values are not allowed.");
+ throw new ArgumentNullException(nameof(metricName),
+ "'PushSingleMetric' method requires a valid metrics key. 'Null' or empty values are not allowed.");
using var context = InitializeContext(nameSpace, service, defaultDimensions);
context.AddMetric(metricName, value, unit, metricResolution);
@@ -272,7 +272,21 @@ void IMetrics.PushSingleMetric(string metricName, double value, MetricUnit unit,
///
public void Dispose()
{
- _instance.Flush();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ // Cleanup
+ if (disposing)
+ {
+ _instance.Flush();
+ }
}
///
diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs
index 4072a1d7..d08b598d 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs
@@ -467,7 +467,7 @@ public void WhenMetricIsNegativeValue_ThrowException()
// Assert
var exception = Assert.Throws(act);
- Assert.Equal("'AddMetric' method requires a valid metrics value. Value must be >= 0.", exception.Message);
+ Assert.Equal("'AddMetric' method requires a valid metrics value. Value must be >= 0. (Parameter 'value')", exception.Message);
// RESET
handler.ResetForTest();
diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/ExceptionFunctionHandler.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/ExceptionFunctionHandler.cs
index 61ba60c8..8a9e9204 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/ExceptionFunctionHandler.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/ExceptionFunctionHandler.cs
@@ -7,17 +7,49 @@ namespace AWS.Lambda.Powertools.Metrics.Tests.Handlers;
public class ExceptionFunctionHandler
{
[Metrics(Namespace = "ns", Service = "svc")]
- public async Task Handle(string input)
+ public Task Handle(string input)
{
ThisThrows();
+ return Task.FromResult(input.ToUpper(CultureInfo.InvariantCulture));
+ }
+
+ [Metrics(Namespace = "ns", Service = "svc")]
+ public Task HandleDecoratorOutsideHandler(string input)
+ {
+ MethodDecorated();
+
+ Metrics.AddMetric($"Metric Name", 1, MetricUnit.Count);
- await Task.Delay(1);
+ return Task.FromResult(input.ToUpper(CultureInfo.InvariantCulture));
+ }
+
+ [Metrics(Namespace = "ns", Service = "svc")]
+ public Task HandleDecoratorOutsideHandlerException(string input)
+ {
+ MethodDecorated();
+
+ Metrics.AddMetric($"Metric Name", 1, MetricUnit.Count);
+
+ ThisThrowsDecorated();
+
+ return Task.FromResult(input.ToUpper(CultureInfo.InvariantCulture));
+ }
- return input.ToUpper(CultureInfo.InvariantCulture);
+ [Metrics(Namespace = "ns", Service = "svc")]
+ private void MethodDecorated()
+ {
+ Metrics.AddMetric($"Metric Name", 1, MetricUnit.Count);
+ Metrics.AddMetric($"Metric Name Decorated", 1, MetricUnit.Count);
}
private void ThisThrows()
{
throw new NullReferenceException();
}
+
+ [Metrics(Namespace = "ns", Service = "svc")]
+ private void ThisThrowsDecorated()
+ {
+ throw new NullReferenceException();
+ }
}
\ No newline at end of file
diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/ExceptionFunctionHandlerTests.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/ExceptionFunctionHandlerTests.cs
index 011cd1e5..0a1aad17 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/ExceptionFunctionHandlerTests.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/ExceptionFunctionHandlerTests.cs
@@ -20,6 +20,35 @@ public async Task Stack_Trace_Included_When_Decorator_Present()
// Assert
var tracedException = await Assert.ThrowsAsync(Handle);
Assert.StartsWith("at AWS.Lambda.Powertools.Metrics.Tests.Handlers.ExceptionFunctionHandler.ThisThrows()", tracedException.StackTrace?.TrimStart());
+ }
+
+ [Fact]
+ public async Task Stack_Trace_Included_When_Decorator_Present_In_Method()
+ {
+ // Arrange
+ Metrics.ResetForTest();
+ var handler = new ExceptionFunctionHandler();
+
+ // Act
+ Task Handle() => handler.HandleDecoratorOutsideHandlerException("whatever");
+
+ // Assert
+ var tracedException = await Assert.ThrowsAsync(Handle);
+ Assert.StartsWith("at AWS.Lambda.Powertools.Metrics.Tests.Handlers.ExceptionFunctionHandler.__a$_around_ThisThrows", tracedException.StackTrace?.TrimStart());
+ }
+
+ [Fact]
+ public async Task Decorator_In_Non_Handler_Method_Does_Not_Throw_Exception()
+ {
+ // Arrange
+ Metrics.ResetForTest();
+ var handler = new ExceptionFunctionHandler();
+ // Act
+ Task Handle() => handler.HandleDecoratorOutsideHandler("whatever");
+
+ // Assert
+ var tracedException = await Record.ExceptionAsync(Handle);
+ Assert.Null(tracedException);
}
}
\ No newline at end of file