Skip to content

chore(metrics): expose MetricsInterface as return type of single metric and further improve API docs #3145

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 5 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
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
124 changes: 44 additions & 80 deletions packages/metrics/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
# Powertools for AWS Lambda (TypeScript) <!-- omit in toc -->
# Powertools for AWS Lambda (TypeScript)

Powertools for AWS Lambda (TypeScript) is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://docs.powertools.aws.dev/lambda/typescript/latest/#features).

You can use the library in both TypeScript and JavaScript code bases.

- [Intro](#intro)
- [Usage](#usage)
- [Basic usage](#basic-usage)
- [Flushing metrics](#flushing-metrics)
- [Capturing cold start as a metric](#capturing-cold-start-as-a-metric)
- [Adding metadata](#adding-metadata)
- [Class method decorator](#class-method-decorator)
- [Middy.js middleware](#middyjs-middleware)
- [Contribute](#contribute)
- [Roadmap](#roadmap)
- [Connect](#connect)
Expand All @@ -19,134 +18,99 @@ You can use the library in both TypeScript and JavaScript code bases.
- [Using Lambda Layer](#using-lambda-layer)
- [License](#license)

## Intro

## Usage

The library provides a utility function to emit metrics to CloudWatch using [Embedded Metric Format (EMF)](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html).

To get started, install the library by running:

```sh
npm i @aws-lambda-powertools/metrics
```

### Basic usage
After initializing the Metrics class, you can add metrics using the [https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics/#creating-metrics](`addMetric()`) method. The metrics are stored in a buffer and are flushed when calling [https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics/#flushing-metrics](`publishStoredMetrics()`).

The library provides a utility function to emit metrics to CloudWatch using [Embedded Metric Format (EMF)](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html).
Each metric can also have dimensions and metadata added to it.

```ts
import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics';
import { Metrics, MetricUnit } from '@aws-lambda-powertools/metrics';

const metrics = new Metrics({
namespace: 'serverlessAirline',
serviceName: 'orders',
defaultDimensions: { environment: process.env.ENVIRONMENT },
});

export const handler = async (
_event: unknown,
_context: unknown
): Promise<void> => {
export const handler = async (event: { requestId: string }) => {
metrics.addMetadata('request_id', event.requestId);
metrics.addMetric('successfulBooking', MetricUnit.Count, 1);
metrics.publishStoredMetrics();
};
```

### 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:
As you finish adding all your metrics, you need to serialize and "flush them" by calling `publishStoredMetrics()`, which will emit the metrics to stdout in the Embedded Metric Format (EMF). The metrics are then picked up by the Lambda runtime and sent to CloudWatch.

- manually by calling `publishStoredMetrics()` at the end of your Lambda function
The `publishStoredMetrics()` method is synchronous and will block the event loop until the metrics are flushed. If you want Metrics to flush automatically at the end of your Lambda function, you can use the `@logMetrics()` decorator or the `logMetrics()` middleware.

```ts
import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics';

const metrics = new Metrics({
namespace: 'serverlessAirline',
serviceName: 'orders',
});
### Capturing cold start as a metric

export const handler = async (
_event: unknown,
_context: unknown
): Promise<void> => {
metrics.addMetric('successfulBooking', MetricUnit.Count, 1);
metrics.publishStoredMetrics();
};
```
With Metrics, you can capture cold start as a metric by calling the `captureColdStartMetric()` method. This method will add a metric with the name `ColdStart` and the value `1` to the metrics buffer.

- middy compatible middleware `logMetrics()`
This metric is flushed automatically as soon as the method is called, to ensure that the cold start is captured regardless of whether the metrics are flushed manually or automatically.

```ts
import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics';
import { logMetrics } from '@aws-lambda-powertools/metrics/middleware';
import middy from '@middy/core';
import { Metrics, MetricUnit } from '@aws-lambda-powertools/metrics';

const metrics = new Metrics({
namespace: 'serverlessAirline',
serviceName: 'orders',
});

const lambdaHandler = async (
_event: unknown,
_context: unknown
): Promise<void> => {
metrics.addMetric('successfulBooking', MetricUnit.Count, 1);
export const handler = async (event: { requestId: string }) => {
metrics.captureColdStartMetric();
};

export const handler = middy(lambdaHandler).use(logMetrics(metrics));
```

- using decorator `@logMetrics()`
Note that we don't emit a `ColdStart` metric with value `0` when the function is warm, as this would result in a high volume of metrics being emitted to CloudWatch, so you'll need to rely on the absence of the `ColdStart` metric to determine if the function is warm.

### Class method decorator

If you are using TypeScript and are comfortable with writing classes, you can use the `@logMetrics()` decorator to automatically flush metrics at the end of your Lambda function as well as configure additional options such as throwing an error if no metrics are added, capturing cold start as a metric, and more.

```ts
import type { Context } from 'aws-lambda';
import type { LambdaInterface } from '@aws-lambda-powertools/commons/types';
import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics';
import { Metrics, MetricUnit } from '@aws-lambda-powertools/metrics';

const metrics = new Metrics({
namespace: 'serverlessAirline',
serviceName: 'orders',
});

class Lambda implements LambdaInterface {
@metrics.logMetrics()
public async handler(_event: unknown, _context: unknown): Promise<void> {
⁣@metrics.logMetrics({ captureColdStartMetric: true, throwOnEmptyMetrics: true })
public async handler(event: { requestId: string }, _: Context) {
metrics.addMetadata('request_id', event.requestId);
metrics.addMetric('successfulBooking', MetricUnit.Count, 1);
}
}

const handlerClass = new Lambda();
export const handler = handlerClass.handler.bind(handlerClass);
export const handler = handlerClass.handler.bind(handlerClass);
```

Using the Middy middleware or decorator will automatically validate, serialize, and flush all your metrics.

### Capturing cold start as a metric

You can optionally capture cold start metrics with the logMetrics middleware or decorator via the captureColdStartMetric param.

```ts
import type { LambdaInterface } from '@aws-lambda-powertools/commons/types';
import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics';

const metrics = new Metrics({
namespace: 'serverlessAirline',
serviceName: 'orders',
});
Decorators are a Stage 3 proposal for JavaScript and are not yet part of the ECMAScript standard. The current implmementation in this library is based on the legacy TypeScript decorator syntax enabled by the [`experimentalDecorators` flag](https://www.typescriptlang.org/tsconfig/#experimentalDecorators) set to `true` in the `tsconfig.json` file.

export class MyFunction implements LambdaInterface {
@metrics.logMetrics({ captureColdStartMetric: true })
public async handler(_event: unknown, _context: unknown): Promise<void> {
metrics.addMetric('successfulBooking', MetricUnit.Count, 1);
}
}
```
### Middy.js middleware

### Adding metadata
If instead you are using [Middy.js](http://middy.js.org) and prefer to use middleware, you can use the `@logMetrics()` middleware to do the same as the class method decorator.

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.
The `@logMetrics()` middleware can be used with Middy.js to automatically flush metrics at the end of your Lambda function as well as configure additional options such as throwing an error if no metrics are added, capturing cold start as a metric, and set default dimensions.

```ts
import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics';
import { Metrics, MetricUnit } from '@aws-lambda-powertools/metrics';
import { logMetrics } from '@aws-lambda-powertools/metrics/middleware';
import middy from '@middy/core';

Expand All @@ -155,17 +119,17 @@ const metrics = new Metrics({
serviceName: 'orders',
});

const lambdaHandler = async (
_event: unknown,
_context: unknown
): Promise<void> => {
export const handler = middy(async (event) => {
metrics.addMetadata('request_id', event.requestId);
metrics.addMetric('successfulBooking', MetricUnit.Count, 1);
metrics.addMetadata('bookingId', '7051cd10-6283-11ec-90d6-0242ac120003');
};

export const handler = middy(lambdaHandler).use(logMetrics(metrics));
}).use(logMetrics(metrics, {
captureColdStartMetric: true,
throwOnEmptyMetrics: true,
}));
```

The `logMetrics()` middleware is compatible with `@middy/[email protected]` and above.

## Contribute

If you are interested in contributing to this project, please refer to our [Contributing Guidelines](https://github.com/aws-powertools/powertools-lambda-typescript/blob/main/CONTRIBUTING.md).
Expand Down
Loading