Metrics
Metrics creates custom metrics asynchronously by logging metrics to standard output following Amazon CloudWatch Embedded Metric Format (EMF).
These metrics can be visualized through Amazon CloudWatch Console.
Key features¶
- Aggregating up to 100 metrics using a single CloudWatch EMF object (large JSON blob).
- Validating your metrics against common metric definitions mistakes (for example, metric unit, values, max dimensions, max metrics).
- Metrics are created asynchronously by the CloudWatch service. You do not need any custom stacks, and there is no impact to Lambda function latency.
- Creating a one-off metric with different dimensions.
Terminologies¶
If you're new to Amazon CloudWatch, there are two terminologies you must be aware of before using this utility:
- Namespace. It's the highest level container that will group multiple metrics from multiple services for a given application, for example
ServerlessEcommerce
. - Dimensions. Metrics metadata in key-value format. They help you slice and dice metrics visualization, for example
ColdStart
metric by Paymentservice
. - Metric. It's the name of the metric, for example: SuccessfulBooking or UpdatedBooking.
- Unit. It's a value representing the unit of measure for the corresponding metric, for example: Count or Seconds.
- Resolution. It's a value representing the storage resolution for the corresponding metric. Metrics can be either Standard or High resolution. Read more here.
Getting started¶
Installation¶
Install the library in your project:
1 |
|
Caution
Using the Lambda Advanced Logging Controls feature requires you to update your version of Powertools for AWS Lambda (TypeScript) to at least v1.15.0 to ensure metrics are reported correctly to Amazon CloudWatch Metrics.
Usage¶
The Metrics
utility must always be instantiated outside of the Lambda handler. In doing this, subsequent invocations processed by the same instance of your function can reuse these resources. This saves cost by reducing function run time. In addition, Metrics
can track cold start and emit the appropriate metrics.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Utility settings¶
The library requires two settings. You can set them as environment variables, or pass them in the constructor.
These settings will be used across all metrics emitted:
Setting | Description | Environment variable | Default | Allowed Values | Example | Constructor parameter |
---|---|---|---|---|---|---|
Service | Optionally, sets service metric dimension across all metrics | POWERTOOLS_SERVICE_NAME |
service_undefined |
Any string | serverlessAirline |
serviceName |
Metric namespace | Logical container where all metrics will be placed | POWERTOOLS_METRICS_NAMESPACE |
default_namespace |
Any string | serverlessAirline |
default_namespace |
Tip
Use your application name or main service as the metric namespace to easily group all metrics
Example using AWS Serverless Application Model (SAM)¶
The Metrics
utility is instantiated outside of the Lambda handler. In doing this, the same instance can be used across multiple invocations inside the same execution environment. This allows Metrics
to be aware of things like whether or not a given invocation had a cold start or not.
1 2 3 4 5 6 7 8 9 10 11 |
|
1 2 3 4 5 6 7 8 9 |
|
You can initialize Metrics anywhere in your code - It'll keep track of your aggregate metrics in memory.
Creating metrics¶
You can create metrics using the addMetric
method, and you can create dimensions for all your aggregate metrics using the addDimension
method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Autocomplete Metric Units
Use the MetricUnit
enum to easily find a supported metric unit by CloudWatch. Alternatively, you can pass the value as a string if you already know them e.g. "Count".
Metrics overflow
CloudWatch EMF supports a max of 100 metrics per batch. Metrics will automatically propagate all the metrics when adding the 100th metric. Subsequent metrics, e.g. 101th, will be aggregated into a new EMF object, for your convenience.
Do not create metrics or dimensions outside the handler
Metrics or dimensions added in the global scope will only be added during cold start. Disregard if that's the intended behavior.
Adding high-resolution metrics¶
You can create high-resolution metrics passing resolution
as parameter to addMetric
.
When is it useful?
High-resolution metrics are data with a granularity of one second and are very useful in several situations such as telemetry, time series, real-time incident management, and others.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Autocomplete Metric Resolutions
Use the MetricResolution
type to easily find a supported metric resolution by CloudWatch. Alternatively, you can pass the allowed values of 1 or 60 as an integer.
Adding multi-value metrics¶
You can call addMetric()
with the same name multiple times. The values will be grouped together in an array.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Adding default dimensions¶
You can add default dimensions to your metrics by passing them as parameters in 4 ways:
- in the constructor
- in the Middy-compatible middleware
- using the
setDefaultDimensions
method - in the decorator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
A note about Middy
Currently we support only Middy v3.x
that you can install it by running npm i @middy/core@~3
.
Check their docs to learn more about Middy and its middleware stack as well as best practices when working with Powertools.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Note
The class method decorators in this project follow the experimental implementation enabled via the experimentalDecorators
compiler option in TypeScript. Additionally, they are implemented in a way that fits asynchronous methods. When decorating a synchronous method, the decorator replaces its implementation with an asynchronous one causing the caller to have to await
the now decorated method.
If this is not the desired behavior, you can use the logMetrics
middleware instead.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
- Binding your handler method allows your handler to access
this
within the class methods.
If you'd like to remove them at some point, you can use the clearDefaultDimensions
method.
Flushing metrics¶
As you finish adding all your metrics, you need to serialize and "flush them" by calling publishStoredMetrics()
. This will print the metrics to standard output.
You can flush metrics automatically using one of the following methods:
- manually
- Middy-compatible middleware
- class decorator
Using the Middy middleware or decorator will automatically validate, serialize, and flush all your metrics. During metrics validation, if no metrics are provided then a warning will be logged, but no exception will be thrown. If you do not use the middleware or decorator, you have to flush your metrics manually.
Metric validation
If metrics are provided, and any of the following criteria are not met, a RangeError
error will be thrown:
- Maximum of 29 dimensions
- Namespace is set only once (or none)
- Metric units must be supported by CloudWatch
Middy middleware¶
See below an example of how to automatically flush metrics with the Middy-compatible logMetrics
middleware.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Using the class decorator¶
Note
The class method decorators in this project follow the experimental implementation enabled via the experimentalDecorators
compiler option in TypeScript. Additionally, they are implemented in a way that fits asynchronous methods. When decorating a synchronous method, the decorator replaces its implementation with an asynchronous one causing the caller to have to await
the now decorated method.
If this is not the desired behavior, you can use the logMetrics
middleware instead.
The logMetrics
decorator of the metrics utility can be used when your Lambda handler function is implemented as method of a Class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
- Binding your handler method allows your handler to access
this
within the class methods.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Manually¶
You can manually flush the metrics with publishStoredMetrics
as follows:
Warning
Metrics, dimensions and namespace validation still applies.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Throwing a RangeError when no metrics are emitted¶
If you want to ensure that at least one metric is emitted before you flush them, you can use the throwOnEmptyMetrics
parameter and pass it to the middleware or decorator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Capturing a cold start invocation as metric¶
You can optionally capture cold start metrics with the logMetrics
middleware or decorator via the captureColdStartMetric
param.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
If it's a cold start invocation, this feature will:
- Create a separate EMF blob solely containing a metric named
ColdStart
- Add the
function_name
,service
and default dimensions
This has the advantage of keeping cold start metric separate from your application metrics, where you might have unrelated dimensions.
We do not emit 0 as a value for the ColdStart metric for cost-efficiency reasons. Let us know if you'd prefer a flag to override it.
Advanced¶
Adding metadata¶
You can add high-cardinality data as part of your Metrics log with the addMetadata
method. This is useful when you want to search highly contextual information along with your metrics in your logs.
Warning
This will not be available during metrics visualization - Use dimensions for this purpose
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Single metric with different dimensions¶
CloudWatch EMF uses the same dimensions across all your metrics. Use singleMetric
if you have a metric that should have different dimensions.
Info
For cost-efficiency, this feature would be used sparsely since you pay for unique metric. Keep the following formula in mind:
unique metric = (metric_name + dimension_name + dimension_value)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
- Binding your handler method allows your handler to access
this
within the class methods.