Skip to content

Commit

Permalink
feat(metrics): introduce MetricsUtils.withMetricsLogger utility (#1000)
Browse files Browse the repository at this point in the history
feat(metrics): introduce  MetricsUtils.withMetricsLogger utility (#1000)
  • Loading branch information
humanzz authored Feb 16, 2023
1 parent 1f4b89c commit 7dfe9c3
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 14 deletions.
26 changes: 25 additions & 1 deletion docs/core/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,28 @@ CloudWatch EMF uses the same dimensions across all your metrics. Use `withSingle
});
}
}
```
```

## Creating metrics with different configurations

Use `withMetricsLogger` if you have one or more metrics that should have different configurations e.g. dimensions or namespace.

=== "App.java"

```java hl_lines="7 8 9 10 11 12 13"
import static software.amazon.lambda.powertools.metrics.MetricsUtils.withMetricsLogger;

public class App implements RequestHandler<Object, Object> {

@Override
public Object handleRequest(Object input, Context context) {
withMetricsLogger(logger -> {
// override default dimensions
logger.setDimensions(DimensionSet.of("AnotherService", "CustomService"));
// add metrics
logger.putMetric("CustomMetrics1", 1, Unit.COUNT);
logger.putMetric("CustomMetrics2", 5, Unit.COUNT);
});
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,10 @@ public static void withSingleMetric(final String name,
final double value,
final Unit unit,
final Consumer<MetricsLogger> logger) {
MetricsLogger metricsLogger = logger();

try {
metricsLogger.setNamespace(defaultNameSpace());
withMetricLogger(metricsLogger -> {
metricsLogger.putMetric(name, value, unit);
captureRequestAndTraceId(metricsLogger);
logger.accept(metricsLogger);
} finally {
metricsLogger.flush();
}
});
}

/**
Expand All @@ -109,11 +103,26 @@ public static void withSingleMetric(final String name,
final Unit unit,
final String namespace,
final Consumer<MetricsLogger> logger) {
withMetricLogger(metricsLogger -> {
metricsLogger.setNamespace(namespace);
metricsLogger.putMetric(name, value, unit);
logger.accept(metricsLogger);
});
}

/**
* 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
*/
public static void withMetricLogger(final Consumer<MetricsLogger> logger) {
MetricsLogger metricsLogger = logger();

try {
metricsLogger.setNamespace(namespace);
metricsLogger.putMetric(name, value, unit);
metricsLogger.setNamespace(defaultNameSpace());
captureRequestAndTraceId(metricsLogger);
logger.accept(metricsLogger);
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -16,9 +15,9 @@
import software.amazon.cloudwatchlogs.emf.model.DimensionSet;
import software.amazon.cloudwatchlogs.emf.model.Unit;

import static java.util.Collections.*;
import static org.assertj.core.api.Assertions.*;
import static java.util.Collections.emptyMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNullPointerException;
import static org.mockito.Mockito.mockStatic;
import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv;

Expand Down Expand Up @@ -123,6 +122,38 @@ void singleMetricsCaptureUtilityWithDefaultNameSpace() {
}
}

@Test
void metricsLoggerCaptureUtilityWithDefaultNameSpace() {
try (MockedStatic<SystemWrapper> mocked = mockStatic(SystemWrapper.class);
MockedStatic<software.amazon.lambda.powertools.core.internal.SystemWrapper> internalWrapper = mockStatic(software.amazon.lambda.powertools.core.internal.SystemWrapper.class)) {
mocked.when(() -> SystemWrapper.getenv("AWS_EMF_ENVIRONMENT")).thenReturn("Lambda");
mocked.when(() -> SystemWrapper.getenv("POWERTOOLS_METRICS_NAMESPACE")).thenReturn("GlobalName");
internalWrapper.when(() -> getenv("_X_AMZN_TRACE_ID")).thenReturn("Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1\"");

MetricsUtils.withMetricLogger(metricsLogger -> {
metricsLogger.setDimensions(DimensionSet.of("Dimension1", "Value1"));
metricsLogger.putMetric("Metric1", 1, Unit.COUNT);
});

assertThat(out.toString())
.satisfies(s -> {
Map<String, Object> logAsJson = readAsJson(s);

assertThat(logAsJson)
.containsEntry("Metric1", 1.0)
.containsEntry("Dimension1", "Value1")
.containsKey("_aws")
.containsEntry("xray_trace_id", "1-5759e988-bd862e3fe1be46a994272793");

Map<String, Object> aws = (Map<String, Object>) logAsJson.get("_aws");

assertThat(aws.get("CloudWatchMetrics"))
.asString()
.contains("Namespace=GlobalName");
});
}
}

@Test
void shouldThrowExceptionWhenDefaultDimensionIsNull() {
assertThatNullPointerException()
Expand Down

0 comments on commit 7dfe9c3

Please sign in to comment.