diff --git a/packages/idempotency/README.md b/packages/idempotency/README.md index 6a3abc1dab..294dad5f8e 100644 --- a/packages/idempotency/README.md +++ b/packages/idempotency/README.md @@ -1,10 +1,25 @@ -# Powertools for AWS Lambda (TypeScript) - Idempotency Utility +# Powertools for AWS Lambda (TypeScript) - Idempotency Utility 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 package in both TypeScript and JavaScript code bases. +- [Intro](#intro) +- [Usage](#usage) + - [Function wrapper](#function-wrapper) + - [Decorator](#decorator) + - [Middy middleware](#middy-middleware) + - [DynamoDB persistence layer](#dynamodb-persistence-layer) +- [Contribute](#contribute) +- [Roadmap](#roadmap) +- [Connect](#connect) +- [How to support Powertools for AWS Lambda (TypeScript)?](#how-to-support-powertools-for-aws-lambda-typescript) + - [Becoming a reference customer](#becoming-a-reference-customer) + - [Sharing your work](#sharing-your-work) + - [Using Lambda Layer](#using-lambda-layer) +- [License](#license) + ## Intro This package provides a utility to implement idempotency in your Lambda functions. diff --git a/packages/metrics/README.md b/packages/metrics/README.md index c0e67baef0..40f7036aa7 100644 --- a/packages/metrics/README.md +++ b/packages/metrics/README.md @@ -4,17 +4,12 @@ Powertools for AWS Lambda (TypeScript) is a developer toolkit to implement Serve You can use the library in both TypeScript and JavaScript code bases. -> Also available in [Python](https://github.com/aws-powertools/powertools-lambda-python), [Java](https://github.com/aws-powertools/powertools-lambda-java), and [.NET](https://github.com/aws-powertools/powertools-lambda-dotnet). - -**[Documentation](https://docs.powertools.aws.dev/lambda/typescript/)** | **[npm](https://www.npmjs.com/org/aws-lambda-powertools)** | **[Roadmap](https://docs.powertools.aws.dev/lambda/typescript/latest/roadmap)** | **[Examples](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples)** | **[Serverless TypeScript Demo](https://github.com/aws-samples/serverless-typescript-demo)** - -## Table of contents - -- [Features](#features) -- [Getting started](#getting-started) - - [Installation](#installation) - - [Examples](#examples) - - [Demo applications](#demo-applications) +- [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) - [Contribute](#contribute) - [Roadmap](#roadmap) - [Connect](#connect) @@ -22,51 +17,154 @@ You can use the library in both TypeScript and JavaScript code bases. - [Becoming a reference customer](#becoming-a-reference-customer) - [Sharing your work](#sharing-your-work) - [Using Lambda Layer](#using-lambda-layer) -- [Credits](#credits) - [License](#license) -## Features +## Intro + +## Usage + +To get started, install the library by running: + +```sh +npm i @aws-lambda-powertools/metrics +``` + +### Basic usage -- **[Tracer](https://docs.powertools.aws.dev/lambda/typescript/latest/core/tracer/)** - Utilities to trace Lambda function handlers, and both synchronous and asynchronous functions -- **[Logger](https://docs.powertools.aws.dev/lambda/typescript/latest/core/logger/)** - Structured logging made easier, and a middleware to enrich log items with key details of the Lambda context -- **[Metrics](https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) -- **[Parameters](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM, Secrets Manager, AppConfig, and DynamoDB +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). -## Getting started +```ts +import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics'; -Find the complete project's [documentation here](https://docs.powertools.aws.dev/lambda/typescript). +const metrics = new Metrics({ + namespace: 'serverlessAirline', + serviceName: 'orders', +}); -### Installation +export const handler = async ( + _event: unknown, + _context: unknown +): Promise => { + metrics.addMetric('successfulBooking', MetricUnit.Count, 1); +}; +``` + +### 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: -The Powertools for AWS Lambda (TypeScript) utilities follow a modular approach, similar to the official [AWS SDK v3 for JavaScript](https://github.com/aws/aws-sdk-js-v3). -Each TypeScript utility is installed as standalone NPM package. +- manually by calling `publishStoredMetrics()` at the end of your Lambda function -Install all three core utilities at once with this single command: +```ts +import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics'; -```shell -npm install @aws-lambda-powertools/logger @aws-lambda-powertools/tracer @aws-lambda-powertools/metrics +const metrics = new Metrics({ + namespace: 'serverlessAirline', + serviceName: 'orders', +}); + +export const handler = async ( + _event: unknown, + _context: unknown +): Promise => { + metrics.addMetric('successfulBooking', MetricUnit.Count, 1); + metrics.publishStoredMetrics(); +}; ``` -Or refer to the installation guide of each utility: +- middy compatible middleware `logMetrics()` + +```ts +import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics'; +import { logMetrics } from '@aws-lambda-powertools/metrics/middleware'; +import middy from '@middy/core'; -👉 [Installation guide for the **Tracer** utility](https://docs.powertools.aws.dev/lambda/typescript/latest/core/tracer#getting-started) +const metrics = new Metrics({ + namespace: 'serverlessAirline', + serviceName: 'orders', +}); -👉 [Installation guide for the **Logger** utility](https://docs.powertools.aws.dev/lambda/typescript/latest/core/logger#getting-started) +const lambdaHandler = async ( + _event: unknown, + _context: unknown +): Promise => { + metrics.addMetric('successfulBooking', MetricUnit.Count, 1); +}; -👉 [Installation guide for the **Metrics** utility](https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics#getting-started) +export const handler = middy(lambdaHandler).use(logMetrics(metrics)); +``` -👉 [Installation guide for the **Parameters** utility](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#getting-started) +- using decorator `@logMetrics()` -### Examples +```ts +import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; +import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics'; -You can find examples of how to use Powertools for AWS Lambda (TypeScript) in the [examples](https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/examples/app) directory. The application is a simple REST API that can be deployed via either AWS CDK or AWS SAM. +const metrics = new Metrics({ + namespace: 'serverlessAirline', + serviceName: 'orders', +}); -### Demo applications +class Lambda implements LambdaInterface { + @metrics.logMetrics() + public async handler(_event: unknown, _context: unknown): Promise { + metrics.addMetric('successfulBooking', MetricUnit.Count, 1); + } +} -The [Serverless TypeScript Demo](https://github.com/aws-samples/serverless-typescript-demo) shows how to use Powertools for AWS Lambda (TypeScript). -You can find instructions on how to deploy and load test this application in the [repository](https://github.com/aws-samples/serverless-typescript-demo). +const handlerClass = new Lambda(); +export const handler = handlerClass.handler.bind(handlerClass); +``` -The [AWS Lambda performance tuning](https://github.com/aws-samples/optimizations-for-lambda-functions) repository also uses Powertools for AWS Lambda (TypeScript) as well as demonstrating other performance tuning techniques for Lambda functions written in TypeScript. +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', +}); + +export class MyFunction implements LambdaInterface { + @metrics.logMetrics({ captureColdStartMetric: true }) + public async handler(_event: unknown, _context: unknown): Promise { + metrics.addMetric('successfulBooking', MetricUnit.Count, 1); + } +} +``` + +### 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. + +```ts +import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics'; +import { logMetrics } from '@aws-lambda-powertools/metrics/middleware'; +import middy from '@middy/core'; + +const metrics = new Metrics({ + namespace: 'serverlessAirline', + serviceName: 'orders', +}); + +const lambdaHandler = async ( + _event: unknown, + _context: unknown +): Promise => { + metrics.addMetric('successfulBooking', MetricUnit.Count, 1); + metrics.addMetadata('bookingId', '7051cd10-6283-11ec-90d6-0242ac120003'); +}; + +export const handler = middy(lambdaHandler).use(logMetrics(metrics)); +``` ## Contribute @@ -86,7 +184,10 @@ Help us prioritize upcoming functionalities or utilities by [upvoting existing R ### Becoming a reference customer -Knowing which companies are using this library is important to help prioritize the project internally. If your company is using Powertools for AWS Lambda (TypeScript), you can request to have your name and logo added to the README file by raising a [Support Powertools for AWS Lambda (TypeScript) (become a reference)](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=customer-reference&template=support_powertools.yml&title=%5BSupport+Lambda+Powertools%5D%3A+%3Cyour+organization+name%3E) issue. +Knowing which companies are using this library is important to help prioritize the project internally. If your company +is using Powertools for AWS Lambda (TypeScript), you can request to have your name and logo added to the README file by +raising a [Support Powertools for AWS Lambda (TypeScript) (become a reference)](https://s12d.com/become-reference-pt-ts) +issue. The following companies, among others, use Powertools: @@ -112,11 +213,7 @@ Share what you did with Powertools for AWS Lambda (TypeScript) 💞💞. Blog po ### Using Lambda Layer -This helps us understand who uses Powertools for AWS Lambda (TypeScript) in a non-intrusive way, and helps us gain future investments for other Powertools for AWS Lambda languages. When [using Layers](#lambda-layers), you can add Powertools for AWS Lambda (TypeScript) as a dev dependency (or as part of your virtual env) to not impact the development process. - -## Credits - -Credits for the Powertools for AWS Lambda (TypeScript) idea go to [DAZN](https://github.com/getndazn) and their [DAZN Lambda Powertools](https://github.com/getndazn/dazn-lambda-powertools/). +This helps us understand who uses Powertools for AWS Lambda (TypeScript) in a non-intrusive way, and helps us gain future investments for other Powertools for AWS Lambda languages. When [using Layers](https://docs.powertools.aws.dev/lambda/typescript/latest/#lambda-layer), you can add Powertools as a dev dependency to not impact the development process. ## License diff --git a/packages/metrics/src/Metrics.ts b/packages/metrics/src/Metrics.ts index 811261f97c..8af6299542 100644 --- a/packages/metrics/src/Metrics.ts +++ b/packages/metrics/src/Metrics.ts @@ -64,7 +64,7 @@ import type { * * ### Object oriented way with decorator * - * If you are used to TypeScript Class usage to encapsulate your Lambda handler you can leverage the [@metrics.logMetrics()](./_aws_lambda_powertools_metrics.Metrics.html#logMetrics) decorator to automatically: + * If you are used to TypeScript Class usage to encapsulate your Lambda handler you can leverage the {@link Metrics.logMetrics} decorator to automatically: * * capture a `ColdStart` metric * * flush buffered metrics * * throw on empty metrics @@ -122,15 +122,60 @@ class Metrics extends Utility implements MetricsInterface { * @private */ private console!: Console; + /** + * Custom configuration service for metrics + */ private customConfigService?: ConfigServiceInterface; + + /** + * Default dimensions to be added to all metrics + * @default {} + */ private defaultDimensions: Dimensions = {}; + + /** + * Additional dimensions for the current metrics context + * @default {} + */ private dimensions: Dimensions = {}; + + /** + * Service for accessing environment variables + */ private envVarsService?: EnvironmentVariablesService; + + /** + * Name of the Lambda function + */ private functionName?: string; + + /** + * Flag indicating if this is a single metric instance + * @default false + */ private isSingleMetric = false; + + /** + * Additional metadata to be included with metrics + * @default {} + */ private metadata: Record = {}; + + /** + * Namespace for the metrics + */ private namespace?: string; + + /** + * Flag to determine if an error should be thrown when no metrics are recorded + * @default false + */ private shouldThrowOnEmptyMetrics = false; + + /** + * Storage for metrics before they are published + * @default {} + */ private storedMetrics: StoredMetrics = {}; public constructor(options: MetricsOptions = {}) { @@ -146,8 +191,8 @@ class Metrics extends Utility implements MetricsInterface { * A dimension is a key-value pair that is used to group metrics. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html#Dimension for more details. - * @param name - * @param value + * @param name The name of the dimension + * @param value The value of the dimension */ public addDimension(name: string, value: string): void { if (MAX_DIMENSION_COUNT <= this.getCurrentDimensionsCount()) { @@ -223,9 +268,9 @@ class Metrics extends Utility implements MetricsInterface { * metrics.addMetric('successfulBooking', MetricUnit.Count, 1, MetricResolution.High); * ``` * - * @param name - The metric name - * @param unit - The metric unit - * @param value - The metric value + * @param name The metric name + * @param unit The metric unit + * @param value The metric value * @param resolution - The metric resolution */ public addMetric( @@ -324,7 +369,7 @@ class Metrics extends Utility implements MetricsInterface { * export const handler = handlerClass.handler.bind(handlerClass); * ``` * - * @decorator Class + * @param options - The options to configure the logMetrics decorator */ public logMetrics(options: ExtraOptions = {}): HandlerMethodDecorator { const { throwOnEmptyMetrics, defaultDimensions, captureColdStartMetric } = @@ -470,7 +515,7 @@ class Metrics extends Utility implements MetricsInterface { } /** - * Sets default dimensions that will be added to all metrics. + * Set default dimensions that will be added to all metrics. * * @param dimensions The default dimensions to be added to all metrics. */ @@ -551,25 +596,21 @@ class Metrics extends Utility implements MetricsInterface { } /** - * Gets the custom config service if it exists. - * - * @returns the custom config service if it exists, undefined otherwise + * Get the custom config service if it exists. */ private getCustomConfigService(): ConfigServiceInterface | undefined { return this.customConfigService; } /** - * Gets the environment variables service. - * - * @returns the environment variables service + * Get the environment variables service. */ private getEnvVarsService(): EnvironmentVariablesService { return this.envVarsService as EnvironmentVariablesService; } /** - * Checks if a metric is new or not. + * Check if a metric is new or not. * * A metric is considered new if there is no metric with the same name already stored. * @@ -579,7 +620,6 @@ class Metrics extends Utility implements MetricsInterface { * * @param name The name of the metric * @param unit The unit of the metric - * @returns true if the metric is new, false if another metric with the same name already exists */ private isNewMetric(name: string, unit: MetricUnit): boolean { if (this.storedMetrics[name]) { @@ -596,7 +636,7 @@ class Metrics extends Utility implements MetricsInterface { } /** - * It initializes console property as an instance of the internal version of Console() class (PR #748) + * Initialize the console property as an instance of the internal version of Console() class (PR #748) * or as the global node console if the `POWERTOOLS_DEV' env variable is set and has truthy value. * * @private @@ -614,7 +654,7 @@ class Metrics extends Utility implements MetricsInterface { } /** - * Sets the custom config service to be used. + * Set the custom config service to be used. * * @param customConfigService The custom config service to be used */ @@ -627,14 +667,14 @@ class Metrics extends Utility implements MetricsInterface { } /** - * Sets the environment variables service to be used. + * Set the environment variables service to be used. */ private setEnvVarsService(): void { this.envVarsService = new EnvironmentVariablesService(); } /** - * Sets the namespace to be used. + * Set the namespace to be used. * * @param namespace The namespace to be used */ @@ -645,12 +685,11 @@ class Metrics extends Utility implements MetricsInterface { } /** - * Sets the options to be used by the Metrics instance. + * Set the options to be used by the Metrics instance. * * This method is used during the initialization of the Metrics instance. * * @param options The options to be used - * @returns the Metrics instance */ private setOptions(options: MetricsOptions): Metrics { const { @@ -673,7 +712,7 @@ class Metrics extends Utility implements MetricsInterface { } /** - * Sets the service to be used. + * Set the service to be used. * * @param service The service to be used */ @@ -689,7 +728,7 @@ class Metrics extends Utility implements MetricsInterface { } /** - * Stores a metric in the buffer. + * Store a metric in the buffer. * * If the buffer is full, or the metric reaches the maximum number of values, * the buffer is published to stdout. diff --git a/packages/metrics/src/config/EnvironmentVariablesService.ts b/packages/metrics/src/config/EnvironmentVariablesService.ts index 8894faf6f8..da6670dcce 100644 --- a/packages/metrics/src/config/EnvironmentVariablesService.ts +++ b/packages/metrics/src/config/EnvironmentVariablesService.ts @@ -9,8 +9,6 @@ class EnvironmentVariablesService /** * It returns the value of the POWERTOOLS_METRICS_NAMESPACE environment variable. - * - * @returns {string} */ public getNamespace(): string { return this.get(this.namespaceVariable); diff --git a/packages/metrics/src/middleware/middy.ts b/packages/metrics/src/middleware/middy.ts index a3d401fcdd..8274383829 100644 --- a/packages/metrics/src/middleware/middy.ts +++ b/packages/metrics/src/middleware/middy.ts @@ -32,7 +32,6 @@ import type { ExtraOptions } from '../types/Metrics.js'; * * @param target - The Metrics instance to use for emitting metrics * @param options - (_optional_) Options for the middleware - * @returns middleware - The middy middleware object */ const logMetrics = ( target: Metrics | Metrics[], diff --git a/packages/metrics/typedoc.json b/packages/metrics/typedoc.json index ecfe51c09b..dd6ff840a1 100644 --- a/packages/metrics/typedoc.json +++ b/packages/metrics/typedoc.json @@ -1,5 +1,9 @@ { "extends": ["../../typedoc.base.json"], - "entryPoints": ["./src/index.ts", "./src/types/index.ts"], + "entryPoints": [ + "./src/index.ts", + "./src/types/index.ts", + "./src/middleware/middy.ts" + ], "readme": "README.md" -} +} \ No newline at end of file