UNPKG

@middy/cloudwatch-metrics

Version:

Embedded CloudWatch metrics middleware for the middy framework

89 lines (75 loc) 2.75 kB
// Copyright 2017 - 2026 will Farrell, Luciano Mammino, and Middy contributors. // SPDX-License-Identifier: MIT import { validateOptions } from "@middy/util"; import awsEmbeddedMetrics from "aws-embedded-metrics"; const name = "cloudwatch-metrics"; const pkg = `@middy/${name}`; // Stryker disable next-line ObjectLiteral: value is already undefined, so dropping the key is observably identical after spread + destructuring const defaults = { onFlushError: undefined, }; // `dimensions` accepts either a single dimension set (object of // string->string) or an array of dimension sets, matching the documented // API and aws-embedded-metrics' `setDimensions(dimensionSets)` signature. const dimensionSetSchema = { type: "object", maxProperties: 30, additionalProperties: { type: "string", minLength: 1, maxLength: 1024 }, }; const optionSchema = { type: "object", properties: { namespace: { type: "string", minLength: 1, maxLength: 256 }, dimensions: { oneOf: [dimensionSetSchema, { type: "array", items: dimensionSetSchema }], }, onFlushError: { instanceof: "Function" }, }, additionalProperties: false, }; export const cloudwatchMetricsValidateOptions = (options) => validateOptions(pkg, optionSchema, options); const cloudwatchMetricsMiddleware = (opts = {}) => { const { namespace, dimensions, onFlushError } = { ...defaults, ...opts }; if (dimensions) { const dimensionSets = Array.isArray(dimensions) ? dimensions : [dimensions]; for (const set of dimensionSets) { if (Object.keys(set).length > 30) { throw new Error( `${pkg} a dimension set may contain at most 30 dimensions`, { cause: { package: pkg } }, ); } } } const cloudwatchMetricsBefore = async (request) => { const metrics = awsEmbeddedMetrics.createMetricsLogger(); // If not set, defaults to aws-embedded-metrics if (namespace) { metrics.setNamespace(namespace); } // If not set, keeps defaults as defined here https://github.com/awslabs/aws-embedded-metrics-node/#configuration if (dimensions) { metrics.setDimensions(dimensions); } Object.assign(request.context, { metrics }); }; const flushMetrics = async (request) => { try { await request.context.metrics?.flush(); } catch (err) { // Flush errors are swallowed to prevent metrics from crashing the // handler. Users who need visibility (e.g., to catch IAM or network // misconfigurations) can pass `onFlushError` to observe them. onFlushError?.(err); } }; const cloudwatchMetricsAfter = flushMetrics; const cloudwatchMetricsOnError = flushMetrics; return { before: cloudwatchMetricsBefore, after: cloudwatchMetricsAfter, onError: cloudwatchMetricsOnError, }; }; export default cloudwatchMetricsMiddleware;