Description
Why is this needed?
Today, we are exposing the whole interface of the https://github.com/awslabs/aws-embedded-metrics-java library that we use in the Metrics utility for logging CloudWatch EMF metrics. Example:
import software.amazon.lambda.powertools.metrics.Metrics;
// We expose the MetricsLogger interface from the EMF library
import software.amazon.cloudwatchlogs.emf.logger.MetricsLogger;
public class MetricsEnabledHandler implements RequestHandler<Object, Object> {
MetricsLogger metricsLogger = MetricsUtils.metricsLogger();
@Override
@Metrics(namespace = "ExampleApplication", service = "booking")
public Object handleRequest(Object input, Context context) {
// User calls methods on software.amazon.cloudwatchlogs.emf.logger.MetricsLogger transitive dependency
metricsLogger.putDimensions(DimensionSet.of("environment", "prod"));
metricsLogger.putMetric("SuccessfulBooking", 1, Unit.COUNT);
}
}
This design is not optimal because it exposes the Metrics utility directly to breaking changes in this transitive dependency. This impacts the extensibility and interface design flexibility of the Metrics utility negatively:
- Breaking changes in the EMF dependency will directly impact customers and require major version bumps of the Metrics utility in Powertools
- Direct coupling with the EMF dependency only allows exposing metrics in EMF and hinders adoption of new Metrics backends
Which area does this relate to?
Metrics Utility tech debt
Suggestion
This issue suggests to add a Metrics interface similar to the other Powertools for AWS runtimes. For example, the same as .NET is doing: https://github.com/aws-powertools/powertools-lambda-dotnet/blob/develop/libraries/src/AWS.Lambda.Powertools.Metrics/IMetrics.cs.
Such an interface will abstract away the direct dependency on the EMF library and will allow us to add new backends or to replace the EMF backend with our own implementation in the future.
Example interface in Java:
package com.amazonaws.lambda.powertools.metrics;
import java.util.Map;
import com.amazonaws.services.lambda.runtime.Context;
public interface Metrics {
// MetricUnit, MetricResolution and other data classes need to be implement manually
void addMetric(String key, double value, MetricUnit unit, MetricResolution resolution);
default void addMetric(String key, double value, MetricUnit unit) {
addMetric(key, value, unit, MetricResolution.DEFAULT);
}
default void addMetric(String key, double value) {
addMetric(key, value, MetricUnit.NONE, MetricResolution.DEFAULT);
}
void addDimension(String key, String value);
void addMetadata(String key, Object value);
void setDefaultDimensions(Map<String, String> defaultDimensions);
void setNamespace(String namespace);
void setService(String service);
void setRaiseOnEmptyMetrics(boolean raiseOnEmptyMetrics);
void setCaptureColdStart(boolean captureColdStart);
void setFunctionName(String functionName);
void clearDefaultDimensions();
void flush();
void captureColdStartMetric(Context context);
}
Acknowledgment
- This request meets Powertools for AWS Lambda (Python) Tenets
- Should this be considered in other Powertools for AWS Lambda languages? i.e. Python, TypeScript, and .NET
Metadata
Metadata
Assignees
Labels
Type
Projects
Status