Description
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
Metadata
Metadata
Assignees
Labels
Type
Projects
Status