Skip to content

feat: single metric utility method to pick default namespace #305

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
merged 4 commits into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static long dimensionsCount() {
return metricsContext().getDimensions().size();
}

private static MetricsContext metricsContext() {
public static MetricsContext metricsContext() {
try {
Field f = metricsLogger().getClass().getDeclaredField("context");
f.setAccessible(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import java.util.function.Consumer;

import software.amazon.cloudwatchlogs.emf.config.SystemWrapper;
import software.amazon.cloudwatchlogs.emf.logger.MetricsLogger;
import software.amazon.cloudwatchlogs.emf.model.MetricsContext;
import software.amazon.cloudwatchlogs.emf.model.MetricsLoggerHelper;
import software.amazon.cloudwatchlogs.emf.model.Unit;

/**
Expand All @@ -26,6 +29,29 @@ public static MetricsLogger metricsLogger() {
return metricsLogger;
}

/**
* Add and immediately flush a single metric. It will use the default namespace
* specific either on {@link Metrics} annotation or via POWERTOOLS_METRICS_NAMESPACE env var.
*
* @param name the name of the metric
* @param value the value of the metric
* @param unit the unit type of the metric
* @param logger the MetricsLogger
*/
public static void withSingleMetricOnDefaultNameSpace(final String name,
Copy link
Contributor

Choose a reason for hiding this comment

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

This is great. Really appreciate that.
I'd say that maybe we can expand this to also set the AwsRequestId property. Probably we should do the same for withSingleMetric.

If we do the AwsRequestId part that will ensure that all metrics metrcisLogger() and withSingleMetric methods from MetricsUtils have the request Id and the traceId which ensures good observability and tracing

I know you've taken a very explicit approach in naming the function, but I think the OnDefaultNameSpace suffix can be dropped in favour of documentation calling out the usage of the default namespace.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I kind of like the idea here. Appreciate the feedback.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggestion incorporated. Now it will capture request id, trace id whenever possible as property

final double value,
final Unit unit,
final Consumer<MetricsLogger> logger) {
MetricsLogger metricsLogger = new MetricsLogger();
try {
metricsLogger.setNamespace(defaultNameSpace());
metricsLogger.putMetric(name, value, unit);
logger.accept(metricsLogger);
} finally {
metricsLogger.flush();
}
}

/**
* Add and immediately flush a single metric.
*
Expand All @@ -49,4 +75,10 @@ public static void withSingleMetric(final String name,
metricsLogger.flush();
}
}

private static String defaultNameSpace() {
MetricsContext context = MetricsLoggerHelper.metricsContext();
return "aws-embedded-metrics".equals(context.getNamespace()) ?
SystemWrapper.getenv("POWERTOOLS_METRICS_NAMESPACE"): context.getNamespace();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,33 @@ void singleMetricsCaptureUtility() {
}
}

@Test
void singleMetricsCaptureUtilityWithDefaultNameSpace() {
try (MockedStatic<SystemWrapper> mocked = mockStatic(SystemWrapper.class)) {
mocked.when(() -> SystemWrapper.getenv("AWS_EMF_ENVIRONMENT")).thenReturn("Lambda");
mocked.when(() -> SystemWrapper.getenv("POWERTOOLS_METRICS_NAMESPACE")).thenReturn("GlobalName");

MetricsUtils.withSingleMetricOnDefaultNameSpace("Metric1", 1, Unit.COUNT,
metricsLogger -> metricsLogger.setDimensions(DimensionSet.of("Dimension1", "Value1")));

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

assertThat(logAsJson)
.containsEntry("Metric1", 1.0)
.containsEntry("Dimension1", "Value1")
.containsKey("_aws");

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

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

private Map<String, Object> readAsJson(String s) {
try {
return mapper.readValue(s, Map.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import software.amazon.cloudwatchlogs.emf.logger.MetricsLogger;
import software.amazon.cloudwatchlogs.emf.model.DimensionSet;
import software.amazon.cloudwatchlogs.emf.model.Unit;
import software.amazon.lambda.powertools.metrics.Metrics;

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

public class PowertoolsMetricsEnabledHandler implements RequestHandler<Object, Object> {

Expand All @@ -16,6 +18,10 @@ public Object handleRequest(Object input, Context context) {
MetricsLogger metricsLogger = metricsLogger();
metricsLogger.putMetric("Metric1", 1, Unit.BYTES);


withSingleMetricOnDefaultNameSpace("Metric2", 1, Unit.COUNT,
log -> log.setDimensions(DimensionSet.of("Dimension1", "Value1")));

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,23 @@ public void metricsWithoutColdStart() {
mocked.when(() -> SystemWrapper.getenv("AWS_EMF_ENVIRONMENT")).thenReturn("Lambda");
requestHandler.handleRequest("input", context);

assertThat(out.toString())
assertThat(out.toString().split("\n"))
.hasSize(2)
.satisfies(s -> {
Map<String, Object> logAsJson = readAsJson(s);
Map<String, Object> logAsJson = readAsJson(s[0]);

assertThat(logAsJson)
.containsEntry("Metric2", 1.0)
.containsEntry("Dimension1", "Value1")
.containsKey("_aws");

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

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

logAsJson = readAsJson(s[1]);

assertThat(logAsJson)
.containsEntry("Metric1", 1.0)
Expand Down