Skip to content

Conversation

@oyiz-michael
Copy link
Contributor

Issue number: closes #6198

Summary

This PR implements support for multiple dimension sets in the Metrics utility, enabling users to create aggregated CloudWatch metrics across different dimension combinations. This aligns with the CloudWatch Embedded Metric Format (EMF) specification and brings Python implementation to feature parity with other Powertools runtimes (Java, TypeScript).

Changes

Core Implementation:

  • Added add_dimensions(dimensions: dict[str, str]) method to AmazonCloudWatchEMFProvider
  • Added dimension_sets: list[dict[str, str]] to track multiple dimension arrays
  • Updated serialize_metric_set() to output all dimension sets in the EMF Dimensions array
  • Modified clear_metrics() to properly clear dimension sets between invocations

API Surface:

  • Added add_dimensions() method to the Metrics class for easy access
  • Method accepts a dictionary of dimension name-value pairs
  • Default dimensions are automatically included in all dimension sets added after they're configured

Behavior:

  • When dimension keys overlap across sets, the last value wins in the EMF output root
  • All dimensions are validated (non-empty names/values, max 30 unique dimensions)
  • Empty dimension dictionaries trigger warnings but don't raise errors
  • Dimension values are automatically converted to strings

Testing:

  • Added 13 comprehensive functional tests covering:
    • Multiple dimension set creation and ordering
    • Default dimensions integration
    • Duplicate key handling
    • Input validation (empty, invalid, max dimensions)
    • Integration with existing Metrics features
    • High-resolution metrics compatibility

Quality:

  • All existing tests pass (141 passed, 1 skipped, 0 failures)
  • No regressions in existing functionality
  • Code passes ruff formatting and mypy type checking

User experience

Before:
Users could only create metrics with a single dimension set, limiting their ability to aggregate metrics across different dimension combinations. To achieve hierarchical aggregation, users had to:

  • Create multiple EphemeralMetrics instances (verbose, error-prone)
  • Manually create separate EMF logs (excessive CloudWatch costs)
  • Use CloudWatch Metric Math or SEARCH (complex, hard to maintain)
  • Use third-party libraries like aws-embedded-metrics-python (additional dependencies)
# Previous workaround - verbose and creates multiple EMF objects
metrics1 = EphemeralMetrics()
metrics1.add_dimension(name="environment", value="prod")
metrics1.add_dimension(name="region", value="us-east-1")
metrics1.add_metric(name="SuccessfulRequests", unit=MetricUnit.Count, value=100)

metrics2 = EphemeralMetrics()
metrics2.add_dimension(name="environment", value="prod")
metrics2.add_metric(name="SuccessfulRequests", unit=MetricUnit.Count, value=100)

metrics3 = EphemeralMetrics()
metrics3.add_dimension(name="region", value="us-east-1")
metrics3.add_metric(name="SuccessfulRequests", unit=MetricUnit.Count, value=100)

After:
Users can now easily create multiple dimension sets within a single Metrics instance, enabling CloudWatch to automatically aggregate metrics across different dimension combinations. This creates cleaner code and more efficient metric ingestion:

from aws_lambda_powertools import Metrics
from aws_lambda_powertools.metrics import MetricUnit

metrics = Metrics(namespace="ServerlessAirline", service="booking")

@metrics.log_metrics
def lambda_handler(event, context):
    # Create dimension sets for different aggregation levels
    metrics.add_dimensions({"environment": "prod", "region": "us-east-1"})
    metrics.add_dimensions({"environment": "prod"})
    metrics.add_dimensions({"region": "us-east-1"})
    
    # Single metric value published with all dimension sets
    metrics.add_metric(name="SuccessfulRequests", unit=MetricUnit.Count, value=100)

EMF Output:
{
  "_aws": {
    "CloudWatchMetrics": [{
      "Namespace": "ServerlessAirline",
      "Dimensions": [
        ["service"],
        ["environment", "region"],
        ["environment"],
        ["region"]
      ],
      "Metrics": [{"Name": "SuccessfulRequests", "Unit": "Count"}]
    }]
  },
  "service": "booking",
  "environment": "prod",
  "region": "us-east-1",
  "SuccessfulRequests": 100.0
}

<!-------
Before creating the pull request, please make sure you do the following:

- Read the Contributing Guidelines at https://github.com/aws-powertools/powertools-lambda-python/blob/main/CONTRIBUTING.md#sending-a-pull-request
- Check that there isn't already a PR that addresses the same issue. If you find a duplicate, please leave a comment under the existing PR so we can discuss how to move forward
- Check that the change meets the project's tenets https://docs.powertools.aws.dev/lambda/python/latest/#tenets
- Add a PR title that follows the conventional commit semantics - https://github.com/aws-powertools/powertools-lambda-python/blob/develop/.github/semantic.yml
- If relevant, add tests that prove that the change is effective and works
------->

---

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

**Disclaimer**: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

Implements add_dimensions() method to create multiple dimension sets in CloudWatch EMF output, enabling metric aggregation across different dimension combinations.

- Add dimension_sets list to track multiple dimension arrays
- Implement add_dimensions() in AmazonCloudWatchEMFProvider
- Update serialize_metric_set to output all dimension sets
- Add add_dimensions() to Metrics wrapper class
- Update clear_metrics to clear dimension_sets
- Add comprehensive test suite (13 tests)
- Handle dimension key conflicts (last value wins)
- Include default dimensions in all dimension sets

Resolves aws-powertools#6198
@oyiz-michael oyiz-michael requested a review from a team as a code owner December 20, 2025 21:34
@pull-request-size pull-request-size bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Dec 20, 2025
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

metrics size/L Denotes a PR that changes 100-499 lines, ignoring generated files. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: Add multiple dimensets to the same Metrics instance

1 participant