Skip to content

Commit a801636

Browse files
fix(metrics): addDimensions() documentation and tests (#3964)
Co-authored-by: Andrea Amorosi <dreamorosi@gmail.com>
1 parent 7a5dfef commit a801636

File tree

4 files changed

+338
-12
lines changed

4 files changed

+338
-12
lines changed

docs/features/metrics.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,18 @@ You can create metrics using the `addMetric` method, and you can create dimensio
119119
--8<-- "examples/snippets/metrics/customDimensions.ts"
120120
```
121121

122+
### Creating dimension sets
123+
124+
You can create separate dimension sets for your metrics using the `addDimensions` method. This allows you to group metrics by different dimension combinations.
125+
126+
When you call `addDimensions()`, it creates a new dimension set rather than adding to the existing dimensions. This is useful when you want to track the same metric across different dimension combinations.
127+
128+
=== "handler.ts"
129+
130+
```typescript hl_lines="9 12-15 18-21"
131+
--8<-- "examples/snippets/metrics/dimensionSets.ts"
132+
```
133+
122134
!!! tip "Autocomplete Metric Units"
123135
Use the `MetricUnit` enum to easily find a supported metric unit by CloudWatch. Alternatively, you can pass the value as a string if you already know them e.g. "Count".
124136

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics';
2+
3+
const metrics = new Metrics({
4+
namespace: 'serverlessAirline',
5+
serviceName: 'orders',
6+
});
7+
8+
export const handler = async (
9+
_event: unknown,
10+
_context: unknown
11+
): Promise<void> => {
12+
// Add a single dimension
13+
metrics.addDimension('environment', 'prod');
14+
15+
// Add a new dimension set
16+
metrics.addDimensions({
17+
dimension1: '1',
18+
dimension2: '2',
19+
});
20+
21+
// Add another dimension set
22+
metrics.addDimensions({
23+
region: 'us-east-1',
24+
category: 'books',
25+
});
26+
27+
// Add metrics
28+
metrics.addMetric('successfulBooking', MetricUnit.Count, 1);
29+
metrics.publishStoredMetrics();
30+
};

packages/metrics/src/Metrics.ts

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ class Metrics extends Utility implements MetricsInterface {
154154
*/
155155
private dimensions: Dimensions = {};
156156

157+
/**
158+
* Additional dimension sets for the current metrics context
159+
* @default []
160+
*/
161+
private dimensionSets: Dimensions[] = [];
162+
157163
/**
158164
* Service for accessing environment variables
159165
*/
@@ -267,9 +273,35 @@ class Metrics extends Utility implements MetricsInterface {
267273
* @param dimensions - An object with key-value pairs of dimensions
268274
*/
269275
public addDimensions(dimensions: Dimensions): void {
270-
for (const [name, value] of Object.entries(dimensions)) {
271-
this.addDimension(name, value);
276+
const newDimensionSet: Dimensions = {};
277+
for (const [key, value] of Object.entries(dimensions)) {
278+
if (!value) {
279+
this.#logger.warn(
280+
`The dimension ${key} doesn't meet the requirements and won't be added. Ensure the dimension name and value are non empty strings`
281+
);
282+
continue;
283+
}
284+
if (
285+
Object.hasOwn(this.dimensions, key) ||
286+
Object.hasOwn(this.defaultDimensions, key) ||
287+
Object.hasOwn(newDimensionSet, key)
288+
) {
289+
this.#logger.warn(
290+
`Dimension "${key}" has already been added. The previous value will be overwritten.`
291+
);
292+
}
293+
newDimensionSet[key] = value;
294+
}
295+
296+
const currentCount = this.getCurrentDimensionsCount();
297+
const newSetCount = Object.keys(newDimensionSet).length;
298+
if (currentCount + newSetCount >= MAX_DIMENSION_COUNT) {
299+
throw new RangeError(
300+
`The number of metric dimensions must be lower than ${MAX_DIMENSION_COUNT}`
301+
);
272302
}
303+
304+
this.dimensionSets.push(newDimensionSet);
273305
}
274306

275307
/**
@@ -447,6 +479,7 @@ class Metrics extends Utility implements MetricsInterface {
447479
*/
448480
public clearDimensions(): void {
449481
this.dimensions = {};
482+
this.dimensionSets = [];
450483
}
451484

452485
/**
@@ -692,26 +725,46 @@ class Metrics extends Utility implements MetricsInterface {
692725
{}
693726
);
694727

695-
const dimensionNames = [
696-
...new Set([
728+
const dimensionNames = [];
729+
730+
const allDimensionKeys = new Set([
731+
...Object.keys(this.defaultDimensions),
732+
...Object.keys(this.dimensions),
733+
]);
734+
735+
if (Object.keys(this.dimensions).length > 0) {
736+
dimensionNames.push([...allDimensionKeys]);
737+
}
738+
739+
for (const dimensionSet of this.dimensionSets) {
740+
const dimensionSetKeys = new Set([
697741
...Object.keys(this.defaultDimensions),
698-
...Object.keys(this.dimensions),
699-
]),
700-
];
742+
...Object.keys(dimensionSet),
743+
]);
744+
dimensionNames.push([...dimensionSetKeys]);
745+
}
746+
747+
if (
748+
dimensionNames.length === 0 &&
749+
Object.keys(this.defaultDimensions).length > 0
750+
) {
751+
dimensionNames.push([...Object.keys(this.defaultDimensions)]);
752+
}
701753

702754
return {
703755
_aws: {
704756
Timestamp: this.#timestamp ?? new Date().getTime(),
705757
CloudWatchMetrics: [
706758
{
707759
Namespace: this.namespace || DEFAULT_NAMESPACE,
708-
Dimensions: [dimensionNames],
760+
Dimensions: dimensionNames as [string[]],
709761
Metrics: metricDefinitions,
710762
},
711763
],
712764
},
713765
...this.defaultDimensions,
714766
...this.dimensions,
767+
...this.dimensionSets.reduce((acc, dims) => Object.assign(acc, dims), {}),
715768
...metricValues,
716769
...this.metadata,
717770
};
@@ -824,9 +877,14 @@ class Metrics extends Utility implements MetricsInterface {
824877
* Gets the current number of dimensions count.
825878
*/
826879
private getCurrentDimensionsCount(): number {
880+
const dimensionSetsCount = this.dimensionSets.reduce(
881+
(total, dimensionSet) => total + Object.keys(dimensionSet).length,
882+
0
883+
);
827884
return (
828885
Object.keys(this.dimensions).length +
829-
Object.keys(this.defaultDimensions).length
886+
Object.keys(this.defaultDimensions).length +
887+
dimensionSetsCount
830888
);
831889
}
832890

0 commit comments

Comments
 (0)