Skip to content

feat(v2): upgrade embedded-metrics to v4 #1405

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

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions docs/core/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,12 @@ You can create metrics using `putMetric`, and manually create dimensions for all
@Override
@Metrics(namespace = "ExampleApplication", service = "booking")
public Object handleRequest(Object input, Context context) {
metricsLogger.putDimensions(DimensionSet.of("environment", "prod"));
metricsLogger.putMetric("SuccessfulBooking", 1, Unit.COUNT);
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth documenting the exception transformation here, probably? I'm also wondering if we should reach out to the SDK team to understand their thinking for the checked exceptions here; maybe we are missing something.

metricsLogger.putDimensions(DimensionSet.of("environment", "prod"));
metricsLogger.putMetric("SuccessfulBooking", 1, Unit.COUNT);
} catch (InvalidDimensionException | InvalidMetricException | DimensionSetExceededException e) {
LOG.error(e);
}
...
}
}
Expand Down Expand Up @@ -306,8 +310,12 @@ You can use `putMetadata` for advanced use cases, where you want to metadata as
@Override
@Metrics(namespace = "ServerlessAirline", service = "payment")
public Object handleRequest(Object input, Context context) {
metricsLogger().putMetric("CustomMetric1", 1, Unit.COUNT);
metricsLogger().putMetadata("booking_id", "1234567890");
try {
metricsLogger().putMetadata("booking_id", "1234567890");
metricsLogger().putMetric("CustomMetric1", 1, Unit.COUNT);
} catch (InvalidMetricException e) {
throw new RuntimeException(e);
}
...
}
}
Expand All @@ -332,7 +340,11 @@ Dimension, it can be done via `#!java MetricsUtils.defaultDimensions()`.
MetricsLogger metricsLogger = MetricsUtils.metricsLogger();

static {
MetricsUtils.defaultDimensions(DimensionSet.of("CustomDimension", "booking"));
try {
MetricsUtils.defaultDimensions(DimensionSet.of("CustomDimension", "booking"));
} catch (InvalidDimensionException | DimensionSetExceededException e) {
throw new RuntimeException(e);
}
}

@Override
Expand Down Expand Up @@ -361,8 +373,12 @@ CloudWatch EMF uses the same dimensions across all your metrics. Use `withSingle

@Override
public Object handleRequest(Object input, Context context) {
withSingleMetric("CustomMetrics2", 1, Unit.COUNT, "Another", (metric) -> {
metric.setDimensions(DimensionSet.of("AnotherService", "CustomService"));
withSingleMetric("CustomMetrics2", 1, Unit.COUNT, "Another", (metric) -> {
try {
metric.setDimensions(DimensionSet.of("AnotherService", "CustomService"));
} catch (InvalidDimensionException | DimensionSetExceededException e) {
throw new RuntimeException(e);
}
});
}
}
Expand Down
4 changes: 2 additions & 2 deletions examples/powertools-examples-core-utilities/cdk/app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
<modelVersion>4.0.0</modelVersion>

<groupId>software.amazon.lambda.examples</groupId>
<version>1.16.1</version>
<version>1.17.0</version>
<artifactId>powertools-examples-core-utilities-cdk</artifactId>
<packaging>jar</packaging>

<name>Powertools for AWS Lambda (Java) library Examples - Core</name>
<name>Powertools for AWS Lambda (Java) library Examples - Core Utilities (logging, tracing, metrics) with CDK</name>

<properties>
<log4j.version>2.20.0</log4j.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
* Handler for requests to Lambda function.
*/
public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
private final static Logger log = LogManager.getLogger(App.class);
private static final Logger log = LogManager.getLogger(App.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's up with all the whitespace changes?


@Logging(logEvent = true, samplingRate = 0.7)
@Tracing(captureMode = CaptureMode.RESPONSE_AND_ERROR)
Expand All @@ -57,11 +57,11 @@ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEv

metricsLogger().putMetric("CustomMetric1", 1, Unit.COUNT);

withSingleMetric("CustomMetrics2", 1, Unit.COUNT, "Another", (metric) ->
{
metric.setDimensions(DimensionSet.of("AnotherService", "CustomService"));
metric.setDimensions(DimensionSet.of("AnotherService1", "CustomService1"));
});
withSingleMetric("CustomMetrics2", 1, Unit.COUNT, "Another", metric ->
{
metric.setDimensions(DimensionSet.of("AnotherService", "CustomService"));
metric.setDimensions(DimensionSet.of("AnotherService1", "CustomService1"));
});

LoggingUtils.appendKey("test", "willBeLogged");

Expand All @@ -74,11 +74,11 @@ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEv
String output = String.format("{ \"message\": \"hello world\", \"location\": \"%s\" }", pageContents);

TracingUtils.withSubsegment("loggingResponse", subsegment ->
{
String sampled = "log something out";
log.info(sampled);
log.info(output);
});
{
String sampled = "log something out";
log.info(sampled);
log.info(output);
});

log.info("After output");
return response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>software.amazon.lambda.examples</groupId>
<artifactId>cdk</artifactId>
<version>1.18.0-SNAPSHOT</version>
<version>2.0.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cdk.version>2.91.0</cdk.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import software.amazon.cloudwatchlogs.emf.exception.DimensionSetExceededException;
import software.amazon.cloudwatchlogs.emf.exception.InvalidDimensionException;
import software.amazon.cloudwatchlogs.emf.exception.InvalidMetricException;
import software.amazon.cloudwatchlogs.emf.model.DimensionSet;
import software.amazon.cloudwatchlogs.emf.model.Unit;
import software.amazon.lambda.powertools.logging.Logging;
Expand All @@ -55,12 +58,20 @@ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEv
headers.put("Content-Type", "application/json");
headers.put("X-Custom-Header", "application/json");

metricsLogger().putMetric("CustomMetric1", 1, Unit.COUNT);
try {
metricsLogger().putMetric("CustomMetric1", 1, Unit.COUNT);
} catch (InvalidMetricException e) {
log.error(e);
}

withSingleMetric("CustomMetrics2", 1, Unit.COUNT, "Another", (metric) ->
{
metric.setDimensions(DimensionSet.of("AnotherService", "CustomService"));
metric.setDimensions(DimensionSet.of("AnotherService1", "CustomService1"));
try {
metric.setDimensions(DimensionSet.of("AnotherService", "CustomService"));
metric.setDimensions(DimensionSet.of("AnotherService1", "CustomService1"));
} catch (InvalidDimensionException | DimensionSetExceededException e) {
log.error(e);
}
});

LoggingUtils.appendKey("test", "willBeLogged");
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
<maven-source-plugin.version>3.3.0</maven-source-plugin.version>
<maven-gpg-plugin.version>3.1.0</maven-gpg-plugin.version>
<junit.version>5.10.0</junit.version>
<aws-embedded-metrics.version>1.0.6</aws-embedded-metrics.version>
<aws-embedded-metrics.version>4.1.1</aws-embedded-metrics.version>
<jmespath.version>0.5.1</jmespath.version>
</properties>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import software.amazon.cloudwatchlogs.emf.exception.DimensionSetExceededException;
import software.amazon.cloudwatchlogs.emf.exception.InvalidDimensionException;
import software.amazon.cloudwatchlogs.emf.exception.InvalidMetricException;
import software.amazon.cloudwatchlogs.emf.logger.MetricsLogger;
import software.amazon.cloudwatchlogs.emf.model.DimensionSet;
import software.amazon.cloudwatchlogs.emf.model.Unit;
Expand All @@ -30,10 +33,21 @@ public class Function implements RequestHandler<Input, String> {
public String handleRequest(Input input, Context context) {

DimensionSet dimensionSet = new DimensionSet();
input.getDimensions().forEach((key, value) -> dimensionSet.addDimension(key, value));
input.getDimensions().forEach((key, value) -> {
try {
dimensionSet.addDimension(key, value);
} catch (InvalidDimensionException | DimensionSetExceededException e) {
// log or something
}
});
metricsLogger.putDimensions(dimensionSet);

input.getMetrics().forEach((key, value) -> metricsLogger.putMetric(key, value, Unit.COUNT));
input.getMetrics().forEach((key, value) -> {
try {
metricsLogger.putMetric(key, value, Unit.COUNT);
} catch (InvalidMetricException e) {
// log or something
}
});

return "OK";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@

package software.amazon.cloudwatchlogs.emf.model;


import static software.amazon.lambda.powertools.metrics.MetricsUtils.metricsLogger;

import java.lang.reflect.Field;
import software.amazon.cloudwatchlogs.emf.exception.DimensionSetExceededException;
import software.amazon.lambda.powertools.metrics.exception.InvalidMetricDimensionException;

public final class MetricsLoggerHelper {

private MetricsLoggerHelper() {
}

Expand All @@ -27,7 +31,11 @@ public static boolean hasNoMetrics() {
}

public static long dimensionsCount() {
return metricsContext().getDimensions().size();
try {
return metricsContext().getDimensions().size();
} catch (DimensionSetExceededException e) {
throw new InvalidMetricDimensionException(e);
}
}

public static MetricsContext metricsContext() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

package software.amazon.lambda.powertools.metrics;

import static java.util.Objects.requireNonNull;
import static java.util.Optional.ofNullable;
import static software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor.getXrayTraceId;
import static software.amazon.lambda.powertools.metrics.internal.LambdaMetricsAspect.REQUEST_ID_PROPERTY;
Expand All @@ -25,11 +24,14 @@
import java.util.function.Consumer;
import software.amazon.cloudwatchlogs.emf.config.SystemWrapper;
import software.amazon.cloudwatchlogs.emf.environment.EnvironmentProvider;
import software.amazon.cloudwatchlogs.emf.exception.InvalidMetricException;
import software.amazon.cloudwatchlogs.emf.exception.InvalidNamespaceException;
import software.amazon.cloudwatchlogs.emf.logger.MetricsLogger;
import software.amazon.cloudwatchlogs.emf.model.DimensionSet;
import software.amazon.cloudwatchlogs.emf.model.MetricsContext;
import software.amazon.cloudwatchlogs.emf.model.MetricsLoggerHelper;
import software.amazon.cloudwatchlogs.emf.model.Unit;
import software.amazon.lambda.powertools.metrics.exception.InvalidMetricNamespaceException;

/**
* A class used to retrieve the instance of the {@code MetricsLogger} used by
Expand Down Expand Up @@ -63,23 +65,6 @@ public static void defaultDimensions(final DimensionSet... dimensionSets) {
MetricsUtils.defaultDimensions = dimensionSets;
}

/**
* Configure default dimension to be used by logger.
* By default, @{@link Metrics} annotation captures configured service as a dimension <i>Service</i>
*
* @param dimensionSet Default value of dimension set for logger
* @deprecated use {@link #defaultDimensions(DimensionSet...)} instead
*/
@Deprecated
public static void defaultDimensionSet(final DimensionSet dimensionSet) {
requireNonNull(dimensionSet, "Null dimension set not allowed");

if (dimensionSet.getDimensionKeys().size() > 0) {
defaultDimensions(dimensionSet);
}
}


/**
* Add and immediately flush a single metric. It will use the default namespace
* specified either on {@link Metrics} annotation or via POWERTOOLS_METRICS_NAMESPACE env var.
Expand All @@ -95,11 +80,20 @@ public static void withSingleMetric(final String name,
final double value,
final Unit unit,
final Consumer<MetricsLogger> logger) {
withMetricsLogger(metricsLogger ->
{
MetricsLogger metricsLogger = logger();

try {
metricsLogger.setNamespace(defaultNameSpace());
metricsLogger.putMetric(name, value, unit);
captureRequestAndTraceId(metricsLogger);
logger.accept(metricsLogger);
});
} catch (InvalidNamespaceException e) {
throw new InvalidMetricNamespaceException(e);
} catch (InvalidMetricException e) {
throw new software.amazon.lambda.powertools.metrics.exception.InvalidMetricException(e);
} finally {
metricsLogger.flush();
}
}

/**
Expand All @@ -118,12 +112,20 @@ public static void withSingleMetric(final String name,
final Unit unit,
final String namespace,
final Consumer<MetricsLogger> logger) {
withMetricsLogger(metricsLogger ->
{
MetricsLogger metricsLogger = logger();

try {
metricsLogger.setNamespace(namespace);
metricsLogger.putMetric(name, value, unit);
captureRequestAndTraceId(metricsLogger);
logger.accept(metricsLogger);
});
} catch (InvalidNamespaceException e) {
throw new InvalidMetricNamespaceException(e);
} catch (InvalidMetricException e) {
throw new software.amazon.lambda.powertools.metrics.exception.InvalidMetricException(e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit confusing that sometimes the wrapping RuntimeException has the same name and only a different NS and sometimes not

} finally {
metricsLogger.flush();
}
}

/**
Expand All @@ -141,25 +143,13 @@ public static void withMetricsLogger(final Consumer<MetricsLogger> logger) {
metricsLogger.setNamespace(defaultNameSpace());
captureRequestAndTraceId(metricsLogger);
logger.accept(metricsLogger);
} catch (InvalidNamespaceException e) {
throw new InvalidMetricNamespaceException(e);
} finally {
metricsLogger.flush();
}
}

/**
* Provide and immediately flush a {@link MetricsLogger}. It uses the default namespace
* specified either on {@link Metrics} annotation or via POWERTOOLS_METRICS_NAMESPACE env var.
* It by default captures function_request_id as property if used together with {@link Metrics} annotation. It will also
* capture xray_trace_id as property if tracing is enabled.
*
* @param logger the MetricsLogger
* @deprecated use {@link MetricsUtils#withMetricsLogger} instead
*/
@Deprecated
public static void withMetricLogger(final Consumer<MetricsLogger> logger) {
withMetricsLogger(logger);
}

public static DimensionSet[] getDefaultDimensions() {
return Arrays.copyOf(defaultDimensions, defaultDimensions.length);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2023 Amazon.com, Inc. or its affiliates.
* Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package software.amazon.lambda.powertools.metrics.exception;

public class InvalidMetricDimensionException extends RuntimeException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gather we are using these to wrap the checked exceptions with RuntimeExceptions while retaining something catchable.

Worth explaining that and why we're doing it on the javadoc ?


private static final long serialVersionUID = -2011349422261364971L;

public InvalidMetricDimensionException(Throwable e) {
super(e);
}
}
Loading