Skip to content

Bug: Metric dimensions are persisting across Lambda invocationsΒ #2327

@surajkumar

Description

@surajkumar

Expected Behaviour

When adding custom dimensions to metrics, they should not persist across Lambda invocations.

Current Behaviour

  • Metric dimensions are persisting across Lambda invocations which causes inaccurate metric data.
  • This has been tested on version 2.1.0 and the latest 2.8.0

Code snippet

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import software.amazon.lambda.powertools.logging.CorrelationIdPaths;
import software.amazon.lambda.powertools.logging.Logging;
import software.amazon.lambda.powertools.metrics.FlushMetrics;
import software.amazon.lambda.powertools.metrics.Metrics;
import software.amazon.lambda.powertools.metrics.MetricsFactory;
import software.amazon.lambda.powertools.metrics.model.DimensionSet;

import java.util.Map;

public class LambdaHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
    private static final Logger LOGGER = LogManager.getLogger(LambdaHandler.class);
    private static final Metrics METRICS = MetricsFactory.getMetricsInstance();

    private boolean shouldEmitMetric = true;

    public LambdaHandler() {}

    @Override
    @Logging(correlationIdPath = CorrelationIdPaths.API_GATEWAY_REST, clearState = true)
    @FlushMetrics(namespace = "test-aws-stack", captureColdStart = true)
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
        LOGGER.info("Entry LambdaHandler#handleRequest");

        try {
            if (shouldEmitMetric) {
                Map<String, String> dimensions = Map.of("EXAMPLE_KEY", "EXAMPLE_VALUE");
                DimensionSet dimensionSet = new DimensionSet();
                dimensions.forEach(dimensionSet::addDimension);
                METRICS.addDimension(dimensionSet);
                METRICS.addMetric("SERL", 1d);

                shouldEmitMetric = false;
                LOGGER.info("Emitted example `SERL` metric and EXAMPLE dimensions");
            } else {
                LOGGER.info("Metric has been emitted in a previous invocation so will not emit this time");
            }

            METRICS.addMetric("Expected", 1d);

        } catch (Exception e) {
            LOGGER.error("An error occurred", e);
        }

        LOGGER.info("Finished!");

        return response();
    }

    private static APIGatewayProxyResponseEvent response() {
        APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();
        response.withHeaders(Map.of("Content-Type", "application/json"));
        response.setStatusCode(200);
        response.setBody("{}");
        return response;
    }
}

Possible Solution

Clear dimensions at the end of an invocation.

We have tried a few things like @FlushMetrics, manually calling metrics.flush() etc but no success.

Steps to Reproduce

Create a metric with a custom dimension e.g.

Map<String, String> dimensions = Map.of("EXAMPLE_KEY", "EXAMPLE_VALUE");
DimensionSet dimensionSet = new DimensionSet();
dimensions.forEach(dimensionSet::addDimension);
METRICS.addDimension(dimensionSet);
METRICS.addMetric("SERL", 1d);

Wrap it in a controllable if-statement so that it only executes once. See code in Code snippet section of this bug report.

Ensure to do this in a Java Lambda.

Assert logs still contain the "EXAMPLE_KEY" and "EXAMPLE_VALUE" in the log group e.g.

{
    "_aws": {
        "Timestamp": 1765297536692,
        "CloudWatchMetrics": [
            {
                "Namespace": "test-aws-stack",
                "Metrics": [
                    {
                        "Name": "Expected",
                        "Unit": "None"
                    }
                ],
                "Dimensions": [
                    [
                        "LogGroup",
                        "ServiceName",
                        "ServiceType",
                        "EXAMPLE_KEY"
                    ]
                ]
            }
        ]
    },
    "function_request_id": "....",
    "Expected": 1,
    "xray_trace_id": "...",
    "EXAMPLE_KEY": "EXAMPLE_VALUE",
    "LogGroup": "aws-stack-LambdaFunction-Q7sUiq8ZLlT1",
    "ServiceName": "aws-stack-LambdaFunction-Q7sUiq8ZLlT1",
    "ServiceType": "AWS::Lambda::Function"
}

Powertools for AWS Lambda (Java) version

latest

AWS Lambda function runtime

Java 21

Debugging logs

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

Status

Working on it

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions