Skip to content

fix(metrics): addDimensions() documentation and tests #3964

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
12 changes: 12 additions & 0 deletions docs/features/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ You can create metrics using the `addMetric` method, and you can create dimensio
--8<-- "examples/snippets/metrics/customDimensions.ts"
```

### Creating dimension sets

You can create separate dimension sets for your metrics using the `addDimensions` method. This allows you to group metrics by different dimension combinations.

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.

=== "handler.ts"

```typescript hl_lines="9 12-15 18-21"
--8<-- "examples/snippets/metrics/dimensionSets.ts"
```

!!! tip "Autocomplete Metric Units"
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".

Expand Down
30 changes: 30 additions & 0 deletions examples/snippets/metrics/dimensionSets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics';

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

export const handler = async (
_event: unknown,
_context: unknown
): Promise<void> => {
// Add a single dimension
metrics.addDimension('environment', 'prod');

// Add a new dimension set
metrics.addDimensions({
dimension1: '1',
dimension2: '2',
});

// Add another dimension set
metrics.addDimensions({
region: 'us-east-1',
category: 'books',
});

// Add metrics
metrics.addMetric('successfulBooking', MetricUnit.Count, 1);
metrics.publishStoredMetrics();
};
76 changes: 67 additions & 9 deletions packages/metrics/src/Metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ class Metrics extends Utility implements MetricsInterface {
*/
private dimensions: Dimensions = {};

/**
* Additional dimension sets for the current metrics context
* @default []
*/
private dimensionSets: Dimensions[] = [];

/**
* Service for accessing environment variables
*/
Expand Down Expand Up @@ -267,9 +273,35 @@ class Metrics extends Utility implements MetricsInterface {
* @param dimensions - An object with key-value pairs of dimensions
*/
public addDimensions(dimensions: Dimensions): void {
for (const [name, value] of Object.entries(dimensions)) {
this.addDimension(name, value);
const newDimensionSet: Dimensions = {};
for (const [key, value] of Object.entries(dimensions)) {
if (!value) {
this.#logger.warn(
`The dimension ${key} doesn't meet the requirements and won't be added. Ensure the dimension name and value are non empty strings`
);
continue;
}
if (
Object.hasOwn(this.dimensions, key) ||
Object.hasOwn(this.defaultDimensions, key) ||
Object.hasOwn(newDimensionSet, key)
) {
this.#logger.warn(
`Dimension "${key}" has already been added. The previous value will be overwritten.`
);
}
newDimensionSet[key] = value;
}

const currentCount = this.getCurrentDimensionsCount();
const newSetCount = Object.keys(newDimensionSet).length;
if (currentCount + newSetCount >= MAX_DIMENSION_COUNT) {
throw new RangeError(
`The number of metric dimensions must be lower than ${MAX_DIMENSION_COUNT}`
);
}

this.dimensionSets.push(newDimensionSet);
}

/**
Expand Down Expand Up @@ -447,6 +479,7 @@ class Metrics extends Utility implements MetricsInterface {
*/
public clearDimensions(): void {
this.dimensions = {};
this.dimensionSets = [];
}

/**
Expand Down Expand Up @@ -692,26 +725,46 @@ class Metrics extends Utility implements MetricsInterface {
{}
);

const dimensionNames = [
...new Set([
const dimensionNames = [];

const allDimensionKeys = new Set([
...Object.keys(this.defaultDimensions),
...Object.keys(this.dimensions),
]);

if (Object.keys(this.dimensions).length > 0) {
dimensionNames.push([...allDimensionKeys]);
}

for (const dimensionSet of this.dimensionSets) {
const dimensionSetKeys = new Set([
...Object.keys(this.defaultDimensions),
...Object.keys(this.dimensions),
]),
];
...Object.keys(dimensionSet),
]);
dimensionNames.push([...dimensionSetKeys]);
}

if (
dimensionNames.length === 0 &&
Object.keys(this.defaultDimensions).length > 0
) {
dimensionNames.push([...Object.keys(this.defaultDimensions)]);
}

return {
_aws: {
Timestamp: this.#timestamp ?? new Date().getTime(),
CloudWatchMetrics: [
{
Namespace: this.namespace || DEFAULT_NAMESPACE,
Dimensions: [dimensionNames],
Dimensions: dimensionNames as [string[]],
Metrics: metricDefinitions,
},
],
},
...this.defaultDimensions,
...this.dimensions,
...this.dimensionSets.reduce((acc, dims) => Object.assign(acc, dims), {}),
...metricValues,
...this.metadata,
};
Expand Down Expand Up @@ -824,9 +877,14 @@ class Metrics extends Utility implements MetricsInterface {
* Gets the current number of dimensions count.
*/
private getCurrentDimensionsCount(): number {
const dimensionSetsCount = this.dimensionSets.reduce(
(total, dimensionSet) => total + Object.keys(dimensionSet).length,
0
);
return (
Object.keys(this.dimensions).length +
Object.keys(this.defaultDimensions).length
Object.keys(this.defaultDimensions).length +
dimensionSetsCount
);
}

Expand Down
Loading
Loading