Description
Expected Behaviour
As a user, when using the Metrics utility I want dimensions and metadata added during a function execution to be cleared when flushing. At the same time, I also want default dimensions and service name to be preserved.
Take the function code shown in the "code snippet" section below, then run it twice. The EMF logs emitted should look like this:
First invocation:
{
"_aws": {
"Timestamp": 1667915882250,
"CloudWatchMetrics": [
{
"Namespace": "someNS",
"Dimensions": [
[
"service", // <-- Service dimension is here
"foo"
]
],
"Metrics": []
}
]
},
"service": "someName", // <-- Service value is here
"foo": "bar"
}
Subsequent invocation:
{
"_aws": {
"Timestamp": 1667915928090,
"CloudWatchMetrics": [
{
"Namespace": "someNS",
"Dimensions": [
[
"service", // <-- Service dimension is still here
"foo"
]
],
"Metrics": []
}
]
},
"service": "someName", // <-- Service is still here
"foo": "bar"
}
Current Behaviour
After the changes made in #1129 (which correspond to v1.4.0
), however the service name is cleared together with the non-default dimensions and metadata.
The function below, executed twice, emits these logs:
First invocation:
{
"_aws": {
"Timestamp": 1667915882250,
"CloudWatchMetrics": [
{
"Namespace": "someNS",
"Dimensions": [
[
"service", // <-- Service dimension is here
"foo"
]
],
"Metrics": []
}
]
},
"service": "someName", // <-- Service value is here
"foo": "bar"
}
Subsequent invocation:
{
"_aws": {
"Timestamp": 1667915928090,
"CloudWatchMetrics": [
{
"Namespace": "someNS",
"Dimensions": [
[
"foo"
] <-- Service dimension is gone
],
"Metrics": []
}
]
},
"foo": "bar"
// <-- Service value is also gone
}
Code snippet
import { Metrics, logMetrics } from "@aws-lambda-powertools/metrics";
import middy from "@middy/core";
const metrics = new Metrics({ serviceName: "someName", namespace: 'someNS' });
export const handler = middy(async () => {
return true;
}).use(logMetrics(metrics, { captureColdStartMetric: true }));
Finally, run the function twice.
Possible Solution
The current Metrics implementation (in v1.4.0
) looks like this:
public publishStoredMetrics(): void {
const target = this.serializeMetrics();
console.log(JSON.stringify(target));
this.storedMetrics = {};
this.clearMetrics();
this.clearDimensions(); // <- this is causing the bug
this.clearMetadata();
}
public clearDimensions(): void {
this.dimensions = {};
}
The above means that every time metrics are flushed, stored metrics, dimensions, and metadata are cleared.
This is fine, however default dimensions and service name should be preserved.
Currently, dimensions
and defaultDimensions
are stored in two separate objects in a Metrics
instance. The clearDimensions
empties the former but leaves the latter untouched.
However, the service name is currently being stored in dimensions
:
private setService(service: string | undefined): void {
const targetService = (service ||
this.getCustomConfigService()?.getServiceName() ||
this.getEnvVarsService().getServiceName()) as string;
if (targetService.length > 0) {
this.addDimension('service', targetService);
}
}
A potential fix would be to instead store the service name in the default dimensions, which would have the side effect of keeping it around when clearDimensions
is called.
private setService(service: string | undefined): void {
const targetService = (service ||
this.getCustomConfigService()?.getServiceName() ||
this.getEnvVarsService().getServiceName()) as string;
if (targetService.length > 0) {
- this.addDimension('service', targetService);
+ this.setDefaultDimensions({ service: targetService });
}
}
An alternative solution that would allow to keep storing the service in dimensions
would involve saving the value of serviceName
passed to the utility constructor & resolving its value using the setService()
method after any publishStoredMetrics()
call.
Steps to Reproduce
Create a Lambda function using any Node.js runtime and use Powertools v1.4.0
, use the code shown in the "Code snippet" section, then run twice.
AWS Lambda Powertools for TypeScript version
v1.4.0 (latest)
AWS Lambda function runtime
16.x
Packaging format used
Lambda Layers, Npm
Debugging logs
No response