Skip to content

Bug: addDimensions() should create a set #3777

Open
@dreamorosi

Description

@dreamorosi

Expected Behavior

When calling the metrics.addDimensions() method of the Metrics utility, the dimensions should create a new dimension set rather than concatenating the dimensions into the existing set.

Basically this:

const metrics = new Metrics({
  namespace: 'serverlessAirline',
  serviceName: 'orders',
});

export const handler = async () => {
  metrics.addDimension('environment', 'prod');

  metrics.addDimensions({
    dimension1: "1",
    dimension2: "2"
  });

  // continue emitting & flushing metrics as today
  metrics.addMetric('foo', MetricUnit.Count, 1);
  metrics.publishStoredMetrics();
};

should generate this:

{
   "_aws":{
      "CloudWatchMetrics":[
         {
            "Namespace":"A",
            "Dimensions":[
               ["dimension1"],
               ["dimension1", "dimension2"],
            ],
            "Metrics":[
               {
                  "Name":"foo",
                  "Unit":"Bytes"
               }
            ]
         }
      ]
   },
   "dimension1":"1",
   "dimension2":"2",
   "foo":[1.0]
}

Current Behavior

Currently this:

const metrics = new Metrics({
  namespace: 'serverlessAirline',
  serviceName: 'orders',
});

export const handler = async () => {
  metrics.addDimension('environment', 'prod');

  metrics.addDimensions({
    dimension1: "1",
    dimension2: "2"
  });

  // continue emitting & flushing metrics as today
  metrics.addMetric('foo', MetricUnit.Count, 1);
  metrics.publishStoredMetrics();
};

instead generates this:

{
   "_aws":{
      "CloudWatchMetrics":[
         {
            "Namespace":"A",
            "Dimensions":[
               ["dimension1", "dimension2"],
            ],
            "Metrics":[
               {
                  "Name":"foo",
                  "Unit":"Bytes"
               }
            ]
         }
      ]
   },
   "dimension1":"1",
   "dimension2":"2",
   "foo":[1.0]
}

Code snippet

See above.

Steps to Reproduce

See above.

Possible Solution

The EMF specification already supports this type of use case, and specifically, it represents a dimension set as an array/list of dimensions within the Dimensions array/list of a metric, for example:

{
   "_aws":{
      "CloudWatchMetrics":[
         {
            "Namespace":"A",
            "Dimensions":[
               ["dimension1"],
               ["dimension1", "dimension2"],
               ["dimension1", "dimension2", "dimension3"]
            ],
            "Metrics":[
               {
                  "Name":"foo",
                  "Unit":"Bytes"
               }
            ]
         }
      ]
   },
   "dimension1":"1",
   "dimension2":"2",
   "dimension3":"3",
   "foo":[1.0]
}

In terms of developer experience, this is how the updated addDimensions() would work alongside existing functions:

Adding a new dimension set:

const metrics = new Metrics({
  namespace: 'serverlessAirline',
  serviceName: 'orders',
});

export const handler = async () => {
  // existing functionality for single dimension
  metrics.addDimension('environment', 'prod');

  // fixed feature
  metrics.addDimensions({
    dimension1: "1",
    dimension2: "2"
  });

  // continue emitting & flushing metrics as today
  metrics.addMetric('successfulBooking', MetricUnit.Count, 1);
  metrics.publishStoredMetrics();
};

Handling overwritten dimensions

const metrics = new Metrics({
  namespace: 'serverlessAirline',
  serviceName: 'orders',
});

export const handler = async () => {
  metrics.addDimension('dimension1', 'A');

  metrics.addDimensions({
    dimension1: "B", // last value to be set is used
    dimension2: "2"
  });
};
Click to see EMF output
{
   "_aws":{
      "CloudWatchMetrics":[
         {
            "Namespace":"A",
            "Dimensions":[
               ["dimension1"],
               ["dimension1", "dimension2"]
            ],
            "Metrics":[
               {
                  "Name":"foo",
                  "Unit":"Bytes"
               }
            ]
         }
      ]
   },
   "dimension1":"B",
   "dimension2":"2",
   "foo": [1.0]
}

Interaction with default dimensions:

const metrics = new Metrics({
  namespace: 'serverlessAirline',
  serviceName: 'orders',
  defaultDimensions: {
    environment: 'prod'
  }
});

export const handler = async () => {
  metrics.addDimensions({ // this set will include `environment` from default dimensions
    dimension1: "1",
    dimension2: "2"
  });
};
Click to see EMF output
{
   "_aws":{
      "CloudWatchMetrics":[
         {
            "Namespace":"A",
            "Dimensions":[
               ["environment", "dimension1", "dimension2"]
            ],
            "Metrics":[
               {
                  "Name":"foo",
                  "Unit":"Bytes"
               }
            ]
         }
      ]
   },
   "environment":"prod"
   "dimension1":"1",
   "dimension2":"2",
   "foo": [1.0]
}

Note: when default dimensions are added at runtime, for example via the metrics.setDefaultDimensions() method, only dimension sets added after the default dimensions were set will include these dimensions. Changes are not retroactive.

const metrics = new Metrics({
  namespace: 'serverlessAirline',
  serviceName: 'orders',
  defaultDimensions: {
    environment: 'prod'
  }
});

export const handler = async () => {
  metrics.addDimensions({"dimension1": "1", "dimension2": "2"}) # this includes environment

  // for some reason I want to add more default dimensions
  metrics.setDefaultDimensions({ tenantId: "1"}) // this does not set tenant_id retroactively into the previous set
  metrics.addDimensionSet({"foo": "1", "bar": "2"}) # this includes environment and tenantiId
}

In terms of implementation, below is a non-exhaustive list of actions that should be done:

  • update implementation of addDimensions() here to create a set instead of multiple separate dimensions
  • update documentation
  • update unit tests under packages/metrics/tests/unit/dimensions.ts

Powertools for AWS Lambda (TypeScript) version

latest

AWS Lambda function runtime

22.x

Packaging format used

npm

Execution logs

Activity

added
bugSomething isn't working
triageThis item has not been triaged by a maintainer, please wait
on Mar 25, 2025
added
on-holdThis item is on-hold and will be revisited in the future
confirmedThe scope is clear, ready for implementation
metricsThis item relates to the Metrics Utility
and removed
triageThis item has not been triaged by a maintainer, please wait
on Mar 25, 2025
removed
on-holdThis item is on-hold and will be revisited in the future
on May 22, 2025
dreamorosi

dreamorosi commented on May 22, 2025

@dreamorosi
ContributorAuthor

@mfigus can you please leave a comment here so I can assign the issue to you, since you're working on it.

moved this from On hold to Working on it in Powertools for AWS Lambda (TypeScript)on May 22, 2025

5 remaining items

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingconfirmedThe scope is clear, ready for implementationmetricsThis item relates to the Metrics Utility

Type

No type

Projects

Status

Working on it

Milestone

No milestone

Relationships

None yet

    Participants

    @matteofigus@dreamorosi

    Issue actions

      Bug: `addDimensions()` should create a set · Issue #3777 · aws-powertools/powertools-lambda-typescript