By default AWS Lambda creates a number of default metrics about your function. These include errors, throttles, duration, concurrency and many more. These are all metrics which can be produced about your function without knowing anything about what your function does. When you want to create your own custom metrics you have a few choices. In this post I will talk about the various ways you can integrate with Amazon CloudWatch including what I think is best practice for working with Lambda.
Firstly, why would you want to create your own custom metrics? In most cases there is information about your function which is important to the business process it is part of. For example recording that a purchase has been made, a seat has been allocated, a booking cancelled, or that any of these were attempted and failed. As your system grows it’s important to develop useful metrics which can be used to monitor the health of your system and business.
If you’re already using AWS Lambda you’ll most likely be aware of the benefits of managed services. Amazon CloudWatch is a fully managed service which provides many monitoring capabilities, metrics being just one. Developers who are familiar with CloudWatch and who have worked on other compute services might use the CloudWatch PutMetricData API to record a single custom metric.
This will absolutely work, but isn’t ideal for Lambda. Because this API call is synchronous and Lambda is billed in part by the duration of each execution, you will be paying Lambda costs while your PutMetricData API call is being processed. This can be further exacerbated if you are making multiple PutMetricData calls for each function request. This can be simplified by batching your metrics into a single API call.
A better way is to use CloudWatch Embedded Metrics Format (EMF). EMF doesn’t make an API call to CloudWatch, instead it produces a JSON object describing your metric and outputs it to standard out. As you probably know, all logs produced to standard out are shipped to CloudWatch. CloudWatch knows to look for JSON objects conforming to the EMF standard and creates metrics on your behalf. This has the advantage of being entirely asynchronous. Low level EMF client libraries are available in Node.js, Python, Java and C#.
The Open-Source Lambda Powertools project has higher level clients which help your interact with EMF more easily. Lambda Powertools are currently available for Java and Python, with more language support on the way.
Before we look at some examples, let’s recap on some of the CloudWatch terms to make sure we understand what the Lambda Powertools functionality is doing. CloudWatch allows you to distinguish between your metrics in a number of ways, the highest level being the namespace. Each namespace can have multiple dimensions.
In the diagram an example is given of an ‘e-commerce-app’ being the namespace and highest level item. Then three dimensions representing other distinct aspects of that functionality.
In this example we use the @Metrics annotations to make this handler Powertools metrics enabled. We can use the annotation variables to set the namespace and a dimension reducing the amount of duplicated code. You can then get access to the low level MetricsLogger using the MetricsUtils Powertools class and record metrics using the putMetric method. Behind the scenes Powertools is validating, serializing and flushing your metrics just before the handler method returns.
Lambda Powertools can help you to record cold starts automatically using another variable within the annotation.
For more information about Powertools visit the documentation pages. You’ll find instructions on how to add it to your project.
Notes on cost.
Using the synchronous PutMetricData API call to CloudWatch is charged at $0.01 per 1000 requests.
EMF is free, but you will incur more cost for ingesting log data, this is charged at $0.50 per GB.
Both methods will incur costs for custom metrics at $0.30 per metric/month.
Detailed pricing information can be found on the CloudWatch pricing page.