UNPKG

@aws-lambda-powertools/metrics

Version:
625 lines 25.6 kB
import { Utility } from '@aws-lambda-powertools/commons'; import type { HandlerMethodDecorator } from '@aws-lambda-powertools/commons/types'; import type { Dimensions, EmfOutput, ExtraOptions, MetricResolution, MetricsInterface, MetricsOptions, MetricUnit } from './types/index.js'; /** * The Metrics utility creates custom metrics asynchronously by logging metrics to standard output following {@link https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html | 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. * * After initializing the Metrics class, you can add metrics using the {@link Metrics.addMetric | `addMetric()`} method. * The metrics are stored in a buffer and are flushed when calling {@link Metrics.publishStoredMetrics | `publishStoredMetrics()`}. * Each metric can have dimensions and metadata added to it. * * @example * ```typescript * import { Metrics, MetricUnit } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders', * defaultDimensions: { environment: 'dev' }, * }); * * export const handler = async (event: { requestId: string }) => { * metrics.addMetadata('request_id', event.requestId); * metrics.addMetric('successfulBooking', MetricUnit.Count, 1); * metrics.publishStoredMetrics(); * }; * ``` * * If you don't want to manually flush the metrics, you can use the {@link Metrics.logMetrics | `logMetrics()`} decorator or * the Middy.js middleware to automatically flush the metrics after the handler function returns or throws an error. * * In addition to this, the decorator and middleware can also be configured to capture a `ColdStart` metric and * set default dimensions for all metrics. * * **Class method decorator** * * @example * * ```typescript * import type { Context } from 'aws-lambda'; * import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; * import { Metrics, MetricUnit } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders' * }); * * class Lambda implements LambdaInterface { * ⁣@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); * ``` * * Note that 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. * * **Middy.js middleware** * * @example * * ```typescript * import { Metrics, MetricUnit } 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' * }); * * export const handler = middy(async () => { * metrics.addMetadata('request_id', event.requestId); * metrics.addMetric('successfulBooking', MetricUnit.Count, 1); * }).use(logMetrics(metrics, { * captureColdStartMetric: true, * throwOnEmptyMetrics: true, * })); * ``` * * The `logMetrics()` middleware is compatible with `@middy/core@3.x` and above. * */ declare class Metrics extends Utility implements MetricsInterface { #private; /** * Console instance used to print logs. * * In AWS Lambda, we create a new instance of the Console class so that we can have * full control over the output of the logs. In testing environments, we use the * default console instance. * * This property is initialized in the constructor in setOptions(). * * @private */ private console; /** * Custom configuration service for metrics */ private customConfigService?; /** * Default dimensions to be added to all metrics * @default {} */ private defaultDimensions; /** * Additional dimensions for the current metrics context * @default {} */ private dimensions; /** * Additional dimension sets for the current metrics context * @default [] */ private dimensionSets; /** * Name of the Lambda function */ private functionName?; /** * Flag indicating if this is a single metric instance * @default false */ private isSingleMetric; /** * Additional metadata to be included with metrics * @default {} */ private metadata; /** * Namespace for the metrics */ private namespace?; /** * Flag to determine if an error should be thrown when no metrics are recorded * @default false */ private shouldThrowOnEmptyMetrics; /** * Storage for metrics before they are published * @default {} */ private storedMetrics; /** * Whether to disable metrics */ private disabled; constructor(options?: MetricsOptions); /** * Add a dimension to metrics. * * A dimension is a key-value pair that is used to group metrics, and it is included in all metrics emitted after it is added. * Invalid dimension values are skipped and a warning is logged. * * When calling the {@link Metrics.publishStoredMetrics | `publishStoredMetrics()`} method, the dimensions are cleared. This type of * dimension is useful when you want to add request-specific dimensions to your metrics. If you want to add dimensions that are * included in all metrics, use the {@link Metrics.setDefaultDimensions | `setDefaultDimensions()`} method. * * @param name - The name of the dimension * @param value - The value of the dimension */ addDimension(name: string, value: string): void; /** * Add multiple dimensions to the metrics. * * This method is useful when you want to add multiple dimensions to the metrics at once. * Invalid dimension values are skipped and a warning is logged. * * When calling the {@link Metrics.publishStoredMetrics | `publishStoredMetrics()`} method, the dimensions are cleared. This type of * dimension is useful when you want to add request-specific dimensions to your metrics. If you want to add dimensions that are * included in all metrics, use the {@link Metrics.setDefaultDimensions | `setDefaultDimensions()`} method. * * @param dimensions - An object with key-value pairs of dimensions */ addDimensions(dimensions: Dimensions): void; /** * A metadata key-value pair to be included with metrics. * * You can use this method to add high-cardinality data as part of your metrics. * This is useful when you want to search highly contextual information along with your metrics in your logs. * * Note that the metadata is not included in the Amazon CloudWatch UI, but it can be used to search and filter logs. * * @example * ```typescript * import { Metrics } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders' * }); * * export const handler = async (event) => { * metrics.addMetadata('request_id', event.requestId); * metrics.addMetric('successfulBooking', MetricUnit.Count, 1); * metrics.publishStoredMetrics(); * }; * ``` * * @param key - The key of the metadata * @param value - The value of the metadata */ addMetadata(key: string, value: string): void; /** * Add a metric to the metrics buffer. * * By default, metrics are buffered and flushed when calling {@link Metrics.publishStoredMetrics | `publishStoredMetrics()`} method, * or at the end of the handler function when using the {@link Metrics.logMetrics | `logMetrics()`} decorator or the Middy.js middleware. * * Metrics are emitted to standard output in the Amazon CloudWatch EMF (Embedded Metric Format) schema. * * You can add a metric by specifying the metric name, unit, and value. For convenience, * we provide a set of constants for the most common units in the {@link MetricUnits | MetricUnit} dictionary object. * * Optionally, you can specify a {@link https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html#Resolution_definition | resolution}, which can be either `High` or `Standard`, using the {@link MetricResolutions | MetricResolution} dictionary object. * By default, metrics are published with a resolution of `Standard`. * * @example * ```typescript * import { Metrics, MetricUnit } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders' * }); * * export const handler = async () => { * metrics.addMetric('successfulBooking', MetricUnit.Count, 1); * metrics.publishStoredMetrics(); * }; * ``` * * @param name - The metric name * @param unit - The metric unit, see {@link MetricUnits | MetricUnit} * @param value - The metric value * @param resolution - The metric resolution, see {@link MetricResolutions | MetricResolution} */ addMetric(name: string, unit: MetricUnit, value: number, resolution?: MetricResolution): void; /** * Immediately emit a `ColdStart` metric if this is a cold start invocation. * * A cold start is when AWS Lambda initializes a new instance of your function. To take advantage of this feature, * you must instantiate the Metrics class outside of the handler function. * * By using this method, the metric will be emitted immediately without you having to call {@link Metrics.publishStoredMetrics | `publishStoredMetrics()`}. * * If you are using the {@link Metrics.logMetrics | `logMetrics()`} decorator, or the Middy.js middleware, you can enable this * feature by setting the `captureColdStartMetric` option to `true`. * * @example * ```typescript * import { Metrics } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders' * }); * * export const handler = async () => { * metrics.captureColdStartMetric(); * }; * ``` * * @param functionName - Optional function name to use as `function_name` dimension in the metric. It's used only if the `functionName` constructor parameter or environment variable are not set. */ captureColdStartMetric(functionName?: string): void; /** * Clear all previously set default dimensions. * * This will remove all default dimensions set by the {@link Metrics.setDefaultDimensions | `setDefaultDimensions()`} method * or via the `defaultDimensions` parameter in the constructor. * * @example * ```typescript * import { Metrics } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders', * defaultDimensions: { environment: 'dev' }, * }); * * metrics.setDefaultDimensions({ region: 'us-west-2' }); * * // both environment and region dimensions are removed * metrics.clearDefaultDimensions(); * ``` */ clearDefaultDimensions(): void; /** * Clear all the dimensions added to the Metrics instance via {@link Metrics.addDimension | `addDimension()`} or {@link Metrics.addDimensions | `addDimensions()`}. * * These dimensions are normally cleared when calling {@link Metrics.publishStoredMetrics | `publishStoredMetrics()`}, but * you can use this method to clear specific dimensions that you no longer need at runtime. * * This method does not clear the default dimensions set via {@link Metrics.setDefaultDimensions | `setDefaultDimensions()`} or via * the `defaultDimensions` parameter in the constructor. * * @example * ```typescript * import { Metrics } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders' * }); * * export const handler = async () => { * metrics.addDimension('region', 'us-west-2'); * * // ... * * metrics.clearDimensions(); // olnly the region dimension is removed * }; * ``` * * The method is primarily intended for internal use, but it is exposed for advanced use cases. */ clearDimensions(): void; /** * Clear all the metadata added to the Metrics instance. * * Metadata is normally cleared when calling {@link Metrics.publishStoredMetrics | `publishStoredMetrics()`}, but * you can use this method to clear specific metadata that you no longer need at runtime. * * The method is primarily intended for internal use, but it is exposed for advanced use cases. */ clearMetadata(): void; /** * Clear all the metrics stored in the buffer. * * This is useful when you want to clear the metrics stored in the buffer without publishing them. * * The method is primarily intended for internal use, but it is exposed for advanced use cases. */ clearMetrics(): void; /** * Check if there are stored metrics in the buffer. */ hasStoredMetrics(): boolean; /** * Whether metrics are disabled. */ protected isDisabled(): boolean; /** * A class method decorator to automatically log metrics after the method returns or throws an error. * * The decorator can be used with TypeScript classes and can be configured to optionally capture a `ColdStart` metric (see {@link Metrics.captureColdStartMetric | `captureColdStartMetric()`}), * throw an error if no metrics are emitted (see {@link Metrics.setThrowOnEmptyMetrics | `setThrowOnEmptyMetrics()`}), * and set default dimensions for all metrics (see {@link Metrics.setDefaultDimensions | `setDefaultDimensions()`}). * * @example * * ```typescript * import type { Context } from 'aws-lambda'; * import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; * import { Metrics, MetricUnit } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders' * }); * * class Lambda implements LambdaInterface { * ⁣@metrics.logMetrics({ captureColdStartMetric: 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); * ``` * * You can configure the decorator with the following options: * - `captureColdStartMetric` - Whether to capture a `ColdStart` metric * - `defaultDimensions` - Default dimensions to add to all metrics * - `throwOnEmptyMetrics` - Whether to throw an error if no metrics are emitted * * @param options - Options to configure the behavior of the decorator, see {@link ExtraOptions} */ logMetrics(options?: ExtraOptions): HandlerMethodDecorator; /** * Flush the stored metrics to standard output. * * The method empties the metrics buffer and emits the metrics to standard output in the Amazon CloudWatch EMF (Embedded Metric Format) schema. * * When using the {@link Metrics.logMetrics | `logMetrics()`} decorator, or the Middy.js middleware, the metrics are automatically flushed after the handler function returns or throws an error. * * @example * ```typescript * import { Metrics, MetricUnit } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders' * }); * * export const handler = async () => { * metrics.addMetric('successfulBooking', MetricUnit.Count, 1); * metrics.publishStoredMetrics(); * }; * ``` */ publishStoredMetrics(): void; /** * Sets the timestamp for the metric. * * If an integer is provided, it is assumed to be the epoch time in milliseconds. * If a Date object is provided, it will be converted to epoch time in milliseconds. * * The timestamp must be a Date object or an integer representing an epoch time. * This should not exceed 14 days in the past or be more than 2 hours in the future. * Any metrics failing to meet this criteria will be skipped by Amazon CloudWatch. * * See: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format_Specification.html * See: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatch-Logs-Monitoring-CloudWatch-Metrics.html * * @example * ```typescript * import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders', * }); * * export const handler = async () => { * const metricTimestamp = new Date(Date.now() - 24 * 60 * 60 * 1000); // 24 hours ago * metrics.setTimestamp(metricTimestamp); * metrics.addMetric('successfulBooking', MetricUnit.Count, 1); * }; * ``` * @param timestamp - The timestamp to set, which can be a number or a Date object. */ setTimestamp(timestamp: number | Date): void; /** * Serialize the stored metrics into a JSON object compliant with the Amazon CloudWatch EMF (Embedded Metric Format) schema. * * The EMF schema is a JSON object that contains the following properties: * - `_aws`: An object containing the timestamp and the CloudWatch metrics. * - `CloudWatchMetrics`: An array of CloudWatch metrics objects. * - `Namespace`: The namespace of the metrics. * - `Dimensions`: An array of dimensions for the metrics. * - `Metrics`: An array of metric definitions. * * The object is then emitted to standard output, which in AWS Lambda is picked up by CloudWatch logs and processed asynchronously. */ serializeMetrics(): EmfOutput; /** * Set default dimensions that will be added to all metrics. * * This method will merge the provided dimensions with the existing default dimensions. * * @example * ```typescript * import { Metrics } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders', * defaultDimensions: { environment: 'dev' }, * }); * * // Default dimensions will contain both region and environment * metrics.setDefaultDimensions({ * region: 'us-west-2', * environment: 'prod', * }); * ``` * * @param dimensions - The dimensions to be added to the default dimensions object */ setDefaultDimensions(dimensions: Dimensions | undefined): void; /** * @deprecated Override the function name for `ColdStart` metrics inferred from the context either via: * - `functionName` constructor parameter * - `POWERTOOLS_FUNCTION_NAME` environment variable * - {@link Metrics.captureColdStartMetric | `captureColdStartMetric('myFunctionName')`} method */ setFunctionName(name: string): void; /** * Set the flag to throw an error if no metrics are emitted. * * You can use this method to enable or disable this opt-in feature. This is useful if you want to ensure * that at least one metric is emitted when flushing the metrics. This can be useful to catch bugs where * metrics are not being emitted as expected. * * @param enabled - Whether to throw an error if no metrics are emitted */ setThrowOnEmptyMetrics(enabled: boolean): void; /** * Create a new Metrics instance configured to immediately flush a single metric. * * CloudWatch EMF uses the same dimensions and timestamp across all your metrics, this is useful when you have a metric that should have different dimensions * or when you want to emit a single metric without buffering it. * * This method is used internally by the {@link Metrics.captureColdStartMetric | `captureColdStartMetric()`} method to emit the `ColdStart` metric immediately * after the handler function is called. * * @example * ```typescript * import { Metrics } from '@aws-lambda-powertools/metrics'; * * const metrics = new Metrics({ * namespace: 'serverlessAirline', * serviceName: 'orders' * }); * * export const handler = async () => { * const singleMetric = metrics.singleMetric(); * // The single metric will be emitted immediately * singleMetric.addMetric('ColdStart', MetricUnit.Count, 1); * * // These other metrics will be buffered and emitted when calling `publishStoredMetrics()` * metrics.addMetric('successfulBooking', MetricUnit.Count, 1); * metrics.publishStoredMetrics(); * }; */ singleMetric(): Metrics; /** * @deprecated Use {@link Metrics.setThrowOnEmptyMetrics | `setThrowOnEmptyMetrics()`} instead. */ throwOnEmptyMetrics(): void; /** * Gets the current number of dimensions count. */ private getCurrentDimensionsCount; /** * Get the custom config service if it exists. */ private getCustomConfigService; /** * Check if a metric is new or not. * * A metric is considered new if there is no metric with the same name already stored. * * When a metric is not new, we also check if the unit is consistent with the stored metric with * the same name. If the units are inconsistent, we throw an error as this is likely a bug or typo. * This can happen if a metric is added without using the `MetricUnit` helper in JavaScript codebases. * * @param name - The name of the metric * @param unit - The unit of the metric */ private isNewMetric; /** * 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 */ private setConsole; /** * Set the custom config service to be used. * * @param customConfigService The custom config service to be used */ private setCustomConfigService; /** * Set the environment variables service to be used. */ private setEnvConfig; /** * Set the function name for the cold start metric. * * @param functionName - The function name to be used for the cold start metric set in the constructor */ protected setFunctionNameForColdStartMetric(functionName?: string): void; /** * Set the namespace to be used. * * @param namespace - The namespace to be used */ private setNamespace; /** * Set the disbaled flag based on the environment variables `POWERTOOLS_METRICS_DISABLED` and `POWERTOOLS_DEV`. * * The `POWERTOOLS_METRICS_DISABLED` environment variable takes precedence over `POWERTOOLS_DEV`. */ private setDisabled; /** * 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 */ private setOptions; /** * Set the service to be used. * * @param service - The service to be used */ private setService; /** * Store a metric in the buffer. * * If the buffer is full, or the metric reaches the maximum number of values, * the metrics are flushed to stdout. * * @param name - The name of the metric to store * @param unit - The unit of the metric to store * @param value - The value of the metric to store * @param resolution - The resolution of the metric to store */ private storeMetric; } export { Metrics }; //# sourceMappingURL=Metrics.d.ts.map