diff --git a/docs/core/metrics.md b/docs/core/metrics.md index 787d5ce8..bc7af983 100644 --- a/docs/core/metrics.md +++ b/docs/core/metrics.md @@ -174,7 +174,7 @@ You can use the Builder or Configure patterns in your Lambda class constructor t ``` ### Adding dimensions -You can add dimensions to your metrics using **`AddDimension`** method. +You can add a dimension to your metrics using the **`AddDimension`** method. === "Function.cs" @@ -185,32 +185,76 @@ You can add dimensions to your metrics using **`AddDimension`** method. ```json hl_lines="11 24" { - "SuccessfulBooking": 1.0, + "SuccessfulBooking": 1, "_aws": { "Timestamp": 1592234975665, "CloudWatchMetrics": [ { - "Namespace": "ExampleApplication", - "Dimensions": [ - [ - "service", - "Environment" - ] - ], - "Metrics": [ + "Namespace": "ExampleApplication", + "Dimensions": [ + [ + "Service", + "Environment" + ] + ], + "Metrics": [ + { + "Name": "SuccessfulBooking", + "Unit": "Count" + } + ] + } + ] + }, + "Service": "Booking", + "Environment": "Prod" + } + ``` + +You can also add multiple dimensions at once using the **`AddDimensions`** method. + +=== "Function.cs" + + ```csharp hl_lines="8-11" + --8<-- "docs/snippets/metrics/AddingMultipleDimensions.cs:adding_multiple_dimensions" + ``` +=== "Example CloudWatch Logs excerpt" + + ```json hl_lines="11 12 25 26" + { + "SuccessfulBooking": 1, + "_aws": { + "Timestamp": 1592234975665, + "CloudWatchMetrics": [ { - "Name": "SuccessfulBooking", - "Unit": "Count" + "Namespace": "ExampleApplication", + "Dimensions": [ + [ + "Service", + "Environment", + "Region" + ] + ], + "Metrics": [ + { + "Name": "SuccessfulBooking", + "Unit": "Count" + } + ] } - ] - } - ] - }, - "service": "ExampleService", - "Environment": "Prod" + ] + }, + "Service": "Booking", + "Environment": "Prod", + "Region": "eu-west-1" } ``` +!!! info "Both methods produce the same result" + `AddDimension` and `AddDimensions` both merge dimensions into the same dimension set in the EMF output. The only difference is ergonomics - multiple individual `AddDimension` calls vs. a single `AddDimensions` call with tuples. + + The resulting CloudWatch metric is aggregated with all dimensions combined - default dimensions plus any dimensions added via either method. + ### Flushing metrics With **`MetricsAttribute`** all your metrics are validated, serialized and flushed to standard output when lambda handler completes execution or when you had the 100th metric to memory. diff --git a/docs/snippets/metrics/AddingDimensions.cs b/docs/snippets/metrics/AddingDimensions.cs index 0e65e8a1..21725797 100644 --- a/docs/snippets/metrics/AddingDimensions.cs +++ b/docs/snippets/metrics/AddingDimensions.cs @@ -13,6 +13,7 @@ public async Task FunctionHandler(APIGatewayProxyReques { Metrics.AddDimension("Environment","Prod"); Metrics.AddMetric("SuccessfulBooking", 1, MetricUnit.Count); + ... } } // --8<-- [end:adding_dimensions] diff --git a/docs/snippets/metrics/AddingMultipleDimensions.cs b/docs/snippets/metrics/AddingMultipleDimensions.cs new file mode 100644 index 00000000..8be1d97d --- /dev/null +++ b/docs/snippets/metrics/AddingMultipleDimensions.cs @@ -0,0 +1,22 @@ +// This file is referenced by docs/core/metrics.md +// via pymdownx.snippets (mkdocs). + +namespace AWS.Lambda.Powertools.Docs.Snippets.Metrics; + +// --8<-- [start:adding_multiple_dimensions] +using AWS.Lambda.Powertools.Metrics; + +public class Function { + + [Metrics(Namespace = "ExampleApplication", Service = "Booking")] + public async Task FunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) + { + Metrics.AddDimensions( + ("Environment", "Prod"), + ("Region", "eu-west-1") + ); + Metrics.AddMetric("SuccessfulBooking", 1, MetricUnit.Count); + ... + } +} +// --8<-- [end:adding_multiple_dimensions] diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs index fb7ce07a..bb201e0e 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs @@ -464,6 +464,25 @@ public void AddDimensions_IncludesDefaultDimensions() Assert.Contains("\"dimension2\":\"2\"", result); } + [Trait("Category", "MetricsImplementation")] + [Fact] + public void AddDimension_And_AddDimensions_ProduceSingleDimensionSet() + { + // Act - use both AddDimension (singular) and AddDimensions (plural) together + _handler.AddDimensionAndAddDimensionsTogether(); + + var result = _consoleOut.ToString(); + + // Assert - single dimension set with all keys + Assert.Contains("\"Dimensions\":[[\"Service\",\"Region\",\"AZ\",\"Environment\"]]", result); + + // Assert - check key properties without caring about dimension order + Assert.Contains("\"Service\":\"testService\"", result); + Assert.Contains("\"Environment\":\"prod\"", result); + Assert.Contains("\"Region\":\"eu-west-1\"", result); + Assert.Contains("\"AZ\":\"eu-west-1a\"", result); + } + [Trait("Category", "MetricsImplementation")] [Fact] public void AddDefaultDimensionsAtRuntime_OnlyAppliedToNewDimensionSets() diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs index da949a78..2d3890f9 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs @@ -359,4 +359,22 @@ public void AddDefaultDimensionsAtRuntime() Metrics.Flush(); } + + public void AddDimensionAndAddDimensionsTogether() + { + Metrics.SetNamespace("dotnet-powertools-test"); + Metrics.SetService("testService"); + + // Use AddDimension (singular) - merges into existing dimension set + Metrics.AddDimension("Environment", "prod"); + + // Use AddDimensions (plural) - also merges into existing dimension set + Metrics.AddDimensions( + ("Region", "eu-west-1"), + ("AZ", "eu-west-1a") + ); + + Metrics.AddMetric("TestMetric", 1.0, MetricUnit.Count); + Metrics.Flush(); + } } \ No newline at end of file