Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

@aws-lambda-powertools/metrics

Package Overview
Dependencies
Maintainers
2
Versions
125
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@aws-lambda-powertools/metrics - npm Package Compare versions

Comparing version
2.28.1
to
2.29.0
+24
lib/cjs/DimensionsStore.d.ts
import '@aws/lambda-invoke-store';
import type { Dimensions } from './types/Metrics.js';
/**
* Manages storage of metrics dimensions with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
declare class DimensionsStore {
#private;
addDimension(name: string, value: string): string;
addDimensionSet(dimensionSet: Dimensions): Dimensions;
getDimensions(): Dimensions;
getDimensionSets(): Dimensions[];
clearRequestDimensions(): void;
clearDefaultDimensions(): void;
getDimensionCount(): number;
setDefaultDimensions(dimensions: Dimensions): void;
getDefaultDimensions(): Dimensions;
}
export { DimensionsStore };
//# sourceMappingURL=DimensionsStore.d.ts.map
{"version":3,"file":"DimensionsStore.d.ts","sourceRoot":"","sources":["../../src/DimensionsStore.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;GAOG;AACH,cAAM,eAAe;;IA4CZ,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAKjD,eAAe,CAAC,YAAY,EAAE,UAAU,GAAG,UAAU;IAKrD,aAAa,IAAI,UAAU;IAI3B,gBAAgB,IAAI,UAAU,EAAE;IAIhC,sBAAsB,IAAI,IAAI;IAgB9B,sBAAsB,IAAI,IAAI;IAI9B,iBAAiB,IAAI,MAAM;IAc3B,oBAAoB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAIlD,oBAAoB,IAAI,UAAU;CAG1C;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DimensionsStore = void 0;
require("@aws/lambda-invoke-store");
const env_1 = require("@aws-lambda-powertools/commons/utils/env");
/**
* Manages storage of metrics dimensions with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
class DimensionsStore {
#dimensionsKey = Symbol('powertools.metrics.dimensions');
#dimensionSetsKey = Symbol('powertools.metrics.dimensionSets');
#fallbackDimensions = {};
#fallbackDimensionSets = [];
#defaultDimensions = {};
#getDimensions() {
if (!(0, env_1.shouldUseInvokeStore)()) {
return this.#fallbackDimensions;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
let stored = store.get(this.#dimensionsKey);
if (stored == null) {
stored = {};
store.set(this.#dimensionsKey, stored);
}
return stored;
}
#getDimensionSets() {
if (!(0, env_1.shouldUseInvokeStore)()) {
return this.#fallbackDimensionSets;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
let stored = store.get(this.#dimensionSetsKey);
if (stored == null) {
stored = [];
store.set(this.#dimensionSetsKey, stored);
}
return stored;
}
addDimension(name, value) {
this.#getDimensions()[name] = value;
return value;
}
addDimensionSet(dimensionSet) {
this.#getDimensionSets().push({ ...dimensionSet });
return dimensionSet;
}
getDimensions() {
return { ...this.#getDimensions() };
}
getDimensionSets() {
return this.#getDimensionSets().map((set) => ({ ...set }));
}
clearRequestDimensions() {
if (!(0, env_1.shouldUseInvokeStore)()) {
this.#fallbackDimensions = {};
this.#fallbackDimensionSets = [];
return;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
store.set(this.#dimensionsKey, {});
store.set(this.#dimensionSetsKey, []);
}
clearDefaultDimensions() {
this.#defaultDimensions = {};
}
getDimensionCount() {
const dimensions = this.#getDimensions();
const dimensionSets = this.#getDimensionSets();
const dimensionSetsCount = dimensionSets.reduce((total, dimensionSet) => total + Object.keys(dimensionSet).length, 0);
return (Object.keys(dimensions).length +
Object.keys(this.#defaultDimensions).length +
dimensionSetsCount);
}
setDefaultDimensions(dimensions) {
this.#defaultDimensions = { ...dimensions };
}
getDefaultDimensions() {
return { ...this.#defaultDimensions };
}
}
exports.DimensionsStore = DimensionsStore;
import '@aws/lambda-invoke-store';
/**
* Manages storage of metrics #metadata with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
declare class MetadataStore {
#private;
set(key: string, value: string): string;
getAll(): Record<string, string>;
clear(): void;
}
export { MetadataStore };
//# sourceMappingURL=MetadataStore.d.ts.map
{"version":3,"file":"MetadataStore.d.ts","sourceRoot":"","sources":["../../src/MetadataStore.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC;AAGlC;;;;;;;GAOG;AACH,cAAM,aAAa;;IAyBV,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAKvC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIhC,KAAK,IAAI,IAAI;CAarB;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MetadataStore = void 0;
require("@aws/lambda-invoke-store");
const env_1 = require("@aws-lambda-powertools/commons/utils/env");
/**
* Manages storage of metrics #metadata with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
class MetadataStore {
#metadataKey = Symbol('powertools.metrics.metadata');
#fallbackStorage = {};
#getStorage() {
if (!(0, env_1.shouldUseInvokeStore)()) {
return this.#fallbackStorage;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
let stored = store.get(this.#metadataKey);
if (stored == null) {
stored = {};
store.set(this.#metadataKey, stored);
}
return stored;
}
set(key, value) {
this.#getStorage()[key] = value;
return value;
}
getAll() {
return { ...this.#getStorage() };
}
clear() {
if (!(0, env_1.shouldUseInvokeStore)()) {
this.#fallbackStorage = {};
return;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
store.set(this.#metadataKey, {});
}
}
exports.MetadataStore = MetadataStore;
import '@aws/lambda-invoke-store';
import type { MetricResolution, MetricUnit, StoredMetric } from './types/index.js';
/**
* Manages storage of metrics with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
declare class MetricsStore {
#private;
getMetric(name: string): StoredMetric | undefined;
/**
* Adds a metric value to storage. If a metric with the same name already exists,
* the value is appended to an array. Validates that the unit matches any existing metric.
*
* @example
* ```typescript
* store.setMetric('latency', MetricUnit.Milliseconds, 100);
* // Returns: { name: 'latency', unit: 'Milliseconds', value: 100, resolution: 60 }
*
* store.setMetric('latency', MetricUnit.Milliseconds, 150);
* // Returns: { name: 'latency', unit: 'Milliseconds', value: [100, 150], resolution: 60 }
* ```
*
* @param name - The metric name
* @param unit - The metric unit (must match existing metric if present)
* @param value - The metric value to add
* @param resolution - The metric resolution (defaults to Standard)
* @returns The stored metric with updated values
* @throws Error if unit doesn't match existing metric
*/
setMetric(name: string, unit: MetricUnit, value: number, resolution?: MetricResolution): StoredMetric;
getMetricNames(): string[];
getAllMetrics(): StoredMetric[];
clearMetrics(): void;
hasMetrics(): boolean;
getMetricsCount(): number;
getTimestamp(): number | undefined;
setTimestamp(timestamp: number | Date): number;
}
export { MetricsStore };
//# sourceMappingURL=MetricsStore.d.ts.map
{"version":3,"file":"MetricsStore.d.ts","sourceRoot":"","sources":["../../src/MetricsStore.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC;AAIlC,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACV,YAAY,EAEb,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;GAOG;AACH,cAAM,YAAY;;IAyBT,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIxD;;;;;;;;;;;;;;;;;;;OAmBG;IACI,SAAS,CACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,gBAA6C,GACxD,YAAY;IA6BR,cAAc,IAAI,MAAM,EAAE;IAI1B,aAAa,IAAI,YAAY,EAAE;IAI/B,YAAY,IAAI,IAAI;IAgBpB,UAAU,IAAI,OAAO;IAIrB,eAAe,IAAI,MAAM;IAIzB,YAAY,IAAI,MAAM,GAAG,SAAS;IAalC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;CA0BtD;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MetricsStore = void 0;
require("@aws/lambda-invoke-store");
const typeutils_1 = require("@aws-lambda-powertools/commons/typeutils");
const env_1 = require("@aws-lambda-powertools/commons/utils/env");
const constants_js_1 = require("./constants.js");
/**
* Manages storage of metrics with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
class MetricsStore {
#storedMetricsKey = Symbol('powertools.metrics.storedMetrics');
#timestampKey = Symbol('powertools.metrics.timestamp');
#fallbackStorage = {};
#fallbackTimestamp;
#getStorage() {
if (!(0, env_1.shouldUseInvokeStore)()) {
return this.#fallbackStorage;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
let stored = store.get(this.#storedMetricsKey);
if (stored == null) {
stored = {};
store.set(this.#storedMetricsKey, stored);
}
return stored;
}
getMetric(name) {
return this.#getStorage()[name];
}
/**
* Adds a metric value to storage. If a metric with the same name already exists,
* the value is appended to an array. Validates that the unit matches any existing metric.
*
* @example
* ```typescript
* store.setMetric('latency', MetricUnit.Milliseconds, 100);
* // Returns: { name: 'latency', unit: 'Milliseconds', value: 100, resolution: 60 }
*
* store.setMetric('latency', MetricUnit.Milliseconds, 150);
* // Returns: { name: 'latency', unit: 'Milliseconds', value: [100, 150], resolution: 60 }
* ```
*
* @param name - The metric name
* @param unit - The metric unit (must match existing metric if present)
* @param value - The metric value to add
* @param resolution - The metric resolution (defaults to Standard)
* @returns The stored metric with updated values
* @throws Error if unit doesn't match existing metric
*/
setMetric(name, unit, value, resolution = constants_js_1.MetricResolution.Standard) {
const storage = this.#getStorage();
const existingMetric = storage[name];
if (existingMetric === undefined) {
const newMetric = {
name,
unit,
value,
resolution,
};
storage[name] = newMetric;
return { ...newMetric };
}
if (existingMetric.unit !== unit) {
const currentUnit = existingMetric.unit;
throw new Error(`Metric "${name}" has already been added with unit "${currentUnit}", but we received unit "${unit}". Did you mean to use metric unit "${currentUnit}"?`);
}
if (!Array.isArray(existingMetric.value)) {
existingMetric.value = [existingMetric.value];
}
existingMetric.value.push(value);
return { ...existingMetric, value: [...existingMetric.value] };
}
getMetricNames() {
return Object.keys(this.#getStorage());
}
getAllMetrics() {
return Object.values(this.#getStorage());
}
clearMetrics() {
if (!(0, env_1.shouldUseInvokeStore)()) {
this.#fallbackStorage = {};
this.#fallbackTimestamp = undefined;
return;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
store.set(this.#storedMetricsKey, {});
store.set(this.#timestampKey, undefined);
}
hasMetrics() {
return this.getMetricNames().length > 0;
}
getMetricsCount() {
return this.getMetricNames().length;
}
getTimestamp() {
if (!(0, env_1.shouldUseInvokeStore)()) {
return this.#fallbackTimestamp;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
return store.get(this.#timestampKey);
}
setTimestamp(timestamp) {
const timestampMs = this.#convertTimestampToEmfFormat(timestamp);
if (!(0, env_1.shouldUseInvokeStore)()) {
this.#fallbackTimestamp = timestampMs;
return timestampMs;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
store.set(this.#timestampKey, timestampMs);
return timestampMs;
}
#convertTimestampToEmfFormat(timestamp) {
if ((0, typeutils_1.isIntegerNumber)(timestamp)) {
return timestamp;
}
if (timestamp instanceof Date) {
return timestamp.getTime();
}
return 0;
}
}
exports.MetricsStore = MetricsStore;
import '@aws/lambda-invoke-store';
import type { Dimensions } from './types/Metrics.js';
/**
* Manages storage of metrics dimensions with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
declare class DimensionsStore {
#private;
addDimension(name: string, value: string): string;
addDimensionSet(dimensionSet: Dimensions): Dimensions;
getDimensions(): Dimensions;
getDimensionSets(): Dimensions[];
clearRequestDimensions(): void;
clearDefaultDimensions(): void;
getDimensionCount(): number;
setDefaultDimensions(dimensions: Dimensions): void;
getDefaultDimensions(): Dimensions;
}
export { DimensionsStore };
//# sourceMappingURL=DimensionsStore.d.ts.map
{"version":3,"file":"DimensionsStore.d.ts","sourceRoot":"","sources":["../../src/DimensionsStore.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;GAOG;AACH,cAAM,eAAe;;IA4CZ,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAKjD,eAAe,CAAC,YAAY,EAAE,UAAU,GAAG,UAAU;IAKrD,aAAa,IAAI,UAAU;IAI3B,gBAAgB,IAAI,UAAU,EAAE;IAIhC,sBAAsB,IAAI,IAAI;IAgB9B,sBAAsB,IAAI,IAAI;IAI9B,iBAAiB,IAAI,MAAM;IAc3B,oBAAoB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAIlD,oBAAoB,IAAI,UAAU;CAG1C;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
import '@aws/lambda-invoke-store';
import { shouldUseInvokeStore } from '@aws-lambda-powertools/commons/utils/env';
/**
* Manages storage of metrics dimensions with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
class DimensionsStore {
#dimensionsKey = Symbol('powertools.metrics.dimensions');
#dimensionSetsKey = Symbol('powertools.metrics.dimensionSets');
#fallbackDimensions = {};
#fallbackDimensionSets = [];
#defaultDimensions = {};
#getDimensions() {
if (!shouldUseInvokeStore()) {
return this.#fallbackDimensions;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
let stored = store.get(this.#dimensionsKey);
if (stored == null) {
stored = {};
store.set(this.#dimensionsKey, stored);
}
return stored;
}
#getDimensionSets() {
if (!shouldUseInvokeStore()) {
return this.#fallbackDimensionSets;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
let stored = store.get(this.#dimensionSetsKey);
if (stored == null) {
stored = [];
store.set(this.#dimensionSetsKey, stored);
}
return stored;
}
addDimension(name, value) {
this.#getDimensions()[name] = value;
return value;
}
addDimensionSet(dimensionSet) {
this.#getDimensionSets().push({ ...dimensionSet });
return dimensionSet;
}
getDimensions() {
return { ...this.#getDimensions() };
}
getDimensionSets() {
return this.#getDimensionSets().map((set) => ({ ...set }));
}
clearRequestDimensions() {
if (!shouldUseInvokeStore()) {
this.#fallbackDimensions = {};
this.#fallbackDimensionSets = [];
return;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
store.set(this.#dimensionsKey, {});
store.set(this.#dimensionSetsKey, []);
}
clearDefaultDimensions() {
this.#defaultDimensions = {};
}
getDimensionCount() {
const dimensions = this.#getDimensions();
const dimensionSets = this.#getDimensionSets();
const dimensionSetsCount = dimensionSets.reduce((total, dimensionSet) => total + Object.keys(dimensionSet).length, 0);
return (Object.keys(dimensions).length +
Object.keys(this.#defaultDimensions).length +
dimensionSetsCount);
}
setDefaultDimensions(dimensions) {
this.#defaultDimensions = { ...dimensions };
}
getDefaultDimensions() {
return { ...this.#defaultDimensions };
}
}
export { DimensionsStore };
import '@aws/lambda-invoke-store';
/**
* Manages storage of metrics #metadata with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
declare class MetadataStore {
#private;
set(key: string, value: string): string;
getAll(): Record<string, string>;
clear(): void;
}
export { MetadataStore };
//# sourceMappingURL=MetadataStore.d.ts.map
{"version":3,"file":"MetadataStore.d.ts","sourceRoot":"","sources":["../../src/MetadataStore.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC;AAGlC;;;;;;;GAOG;AACH,cAAM,aAAa;;IAyBV,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAKvC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIhC,KAAK,IAAI,IAAI;CAarB;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
import '@aws/lambda-invoke-store';
import { shouldUseInvokeStore } from '@aws-lambda-powertools/commons/utils/env';
/**
* Manages storage of metrics #metadata with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
class MetadataStore {
#metadataKey = Symbol('powertools.metrics.metadata');
#fallbackStorage = {};
#getStorage() {
if (!shouldUseInvokeStore()) {
return this.#fallbackStorage;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
let stored = store.get(this.#metadataKey);
if (stored == null) {
stored = {};
store.set(this.#metadataKey, stored);
}
return stored;
}
set(key, value) {
this.#getStorage()[key] = value;
return value;
}
getAll() {
return { ...this.#getStorage() };
}
clear() {
if (!shouldUseInvokeStore()) {
this.#fallbackStorage = {};
return;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
store.set(this.#metadataKey, {});
}
}
export { MetadataStore };
import '@aws/lambda-invoke-store';
import type { MetricResolution, MetricUnit, StoredMetric } from './types/index.js';
/**
* Manages storage of metrics with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
declare class MetricsStore {
#private;
getMetric(name: string): StoredMetric | undefined;
/**
* Adds a metric value to storage. If a metric with the same name already exists,
* the value is appended to an array. Validates that the unit matches any existing metric.
*
* @example
* ```typescript
* store.setMetric('latency', MetricUnit.Milliseconds, 100);
* // Returns: { name: 'latency', unit: 'Milliseconds', value: 100, resolution: 60 }
*
* store.setMetric('latency', MetricUnit.Milliseconds, 150);
* // Returns: { name: 'latency', unit: 'Milliseconds', value: [100, 150], resolution: 60 }
* ```
*
* @param name - The metric name
* @param unit - The metric unit (must match existing metric if present)
* @param value - The metric value to add
* @param resolution - The metric resolution (defaults to Standard)
* @returns The stored metric with updated values
* @throws Error if unit doesn't match existing metric
*/
setMetric(name: string, unit: MetricUnit, value: number, resolution?: MetricResolution): StoredMetric;
getMetricNames(): string[];
getAllMetrics(): StoredMetric[];
clearMetrics(): void;
hasMetrics(): boolean;
getMetricsCount(): number;
getTimestamp(): number | undefined;
setTimestamp(timestamp: number | Date): number;
}
export { MetricsStore };
//# sourceMappingURL=MetricsStore.d.ts.map
{"version":3,"file":"MetricsStore.d.ts","sourceRoot":"","sources":["../../src/MetricsStore.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC;AAIlC,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACV,YAAY,EAEb,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;GAOG;AACH,cAAM,YAAY;;IAyBT,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIxD;;;;;;;;;;;;;;;;;;;OAmBG;IACI,SAAS,CACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,gBAA6C,GACxD,YAAY;IA6BR,cAAc,IAAI,MAAM,EAAE;IAI1B,aAAa,IAAI,YAAY,EAAE;IAI/B,YAAY,IAAI,IAAI;IAgBpB,UAAU,IAAI,OAAO;IAIrB,eAAe,IAAI,MAAM;IAIzB,YAAY,IAAI,MAAM,GAAG,SAAS;IAalC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM;CA0BtD;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
import '@aws/lambda-invoke-store';
import { isIntegerNumber } from '@aws-lambda-powertools/commons/typeutils';
import { shouldUseInvokeStore } from '@aws-lambda-powertools/commons/utils/env';
import { MetricResolution as MetricResolutions } from './constants.js';
/**
* Manages storage of metrics with automatic context detection.
*
* This class abstracts the storage mechanism for metrics, automatically
* choosing between AsyncLocalStorage (when in async context) and a fallback
* object (when outside async context). The decision is made at runtime on
* every method call to support Lambda's transition to async contexts.
*/
class MetricsStore {
#storedMetricsKey = Symbol('powertools.metrics.storedMetrics');
#timestampKey = Symbol('powertools.metrics.timestamp');
#fallbackStorage = {};
#fallbackTimestamp;
#getStorage() {
if (!shouldUseInvokeStore()) {
return this.#fallbackStorage;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
let stored = store.get(this.#storedMetricsKey);
if (stored == null) {
stored = {};
store.set(this.#storedMetricsKey, stored);
}
return stored;
}
getMetric(name) {
return this.#getStorage()[name];
}
/**
* Adds a metric value to storage. If a metric with the same name already exists,
* the value is appended to an array. Validates that the unit matches any existing metric.
*
* @example
* ```typescript
* store.setMetric('latency', MetricUnit.Milliseconds, 100);
* // Returns: { name: 'latency', unit: 'Milliseconds', value: 100, resolution: 60 }
*
* store.setMetric('latency', MetricUnit.Milliseconds, 150);
* // Returns: { name: 'latency', unit: 'Milliseconds', value: [100, 150], resolution: 60 }
* ```
*
* @param name - The metric name
* @param unit - The metric unit (must match existing metric if present)
* @param value - The metric value to add
* @param resolution - The metric resolution (defaults to Standard)
* @returns The stored metric with updated values
* @throws Error if unit doesn't match existing metric
*/
setMetric(name, unit, value, resolution = MetricResolutions.Standard) {
const storage = this.#getStorage();
const existingMetric = storage[name];
if (existingMetric === undefined) {
const newMetric = {
name,
unit,
value,
resolution,
};
storage[name] = newMetric;
return { ...newMetric };
}
if (existingMetric.unit !== unit) {
const currentUnit = existingMetric.unit;
throw new Error(`Metric "${name}" has already been added with unit "${currentUnit}", but we received unit "${unit}". Did you mean to use metric unit "${currentUnit}"?`);
}
if (!Array.isArray(existingMetric.value)) {
existingMetric.value = [existingMetric.value];
}
existingMetric.value.push(value);
return { ...existingMetric, value: [...existingMetric.value] };
}
getMetricNames() {
return Object.keys(this.#getStorage());
}
getAllMetrics() {
return Object.values(this.#getStorage());
}
clearMetrics() {
if (!shouldUseInvokeStore()) {
this.#fallbackStorage = {};
this.#fallbackTimestamp = undefined;
return;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
store.set(this.#storedMetricsKey, {});
store.set(this.#timestampKey, undefined);
}
hasMetrics() {
return this.getMetricNames().length > 0;
}
getMetricsCount() {
return this.getMetricNames().length;
}
getTimestamp() {
if (!shouldUseInvokeStore()) {
return this.#fallbackTimestamp;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
return store.get(this.#timestampKey);
}
setTimestamp(timestamp) {
const timestampMs = this.#convertTimestampToEmfFormat(timestamp);
if (!shouldUseInvokeStore()) {
this.#fallbackTimestamp = timestampMs;
return timestampMs;
}
if (globalThis.awslambda?.InvokeStore === undefined) {
throw new Error('InvokeStore is not available');
}
const store = globalThis.awslambda.InvokeStore;
store.set(this.#timestampKey, timestampMs);
return timestampMs;
}
#convertTimestampToEmfFormat(timestamp) {
if (isIntegerNumber(timestamp)) {
return timestamp;
}
if (timestamp instanceof Date) {
return timestamp.getTime();
}
return 0;
}
}
export { MetricsStore };
+0
-42

@@ -117,17 +117,2 @@ import { Utility } from '@aws-lambda-powertools/commons';

/**
* 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

@@ -142,7 +127,2 @@ */

/**
* Additional metadata to be included with metrics
* @default {}
*/
private metadata;
/**
* Namespace for the metrics

@@ -157,7 +137,2 @@ */

/**
* Storage for metrics before they are published
* @default {}
*/
private storedMetrics;
/**
* Whether to disable metrics

@@ -545,6 +520,2 @@ */

/**
* Gets the current number of dimensions count.
*/
private getCurrentDimensionsCount;
/**
* Get the custom config service if it exists.

@@ -554,15 +525,2 @@ */

/**
* 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)

@@ -569,0 +527,0 @@ * or as the global node console if the `POWERTOOLS_DEV' env variable is set and has truthy value.

+68
-136

@@ -8,2 +8,5 @@ "use strict";

const constants_js_1 = require("./constants.js");
const DimensionsStore_js_1 = require("./DimensionsStore.js");
const MetadataStore_js_1 = require("./MetadataStore.js");
const MetricsStore_js_1 = require("./MetricsStore.js");
/**

@@ -121,17 +124,6 @@ * 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)}.

/**
* Default dimensions to be added to all metrics
* @default {}
* Storage for dimensions
*/
defaultDimensions = {};
#dimensionsStore = new DimensionsStore_js_1.DimensionsStore();
/**
* Additional dimensions for the current metrics context
* @default {}
*/
dimensions = {};
/**
* Additional dimension sets for the current metrics context
* @default []
*/
dimensionSets = [];
/**
* Name of the Lambda function

@@ -153,5 +145,4 @@ */

* Additional metadata to be included with metrics
* @default {}
*/
metadata = {};
#metadataStore = new MetadataStore_js_1.MetadataStore();
/**

@@ -168,5 +159,4 @@ * Namespace for the metrics

* Storage for metrics before they are published
* @default {}
*/
storedMetrics = {};
#metricsStore = new MetricsStore_js_1.MetricsStore();
/**

@@ -187,9 +177,4 @@ * Whether to disable metrics

};
/**
* Custom timestamp for the metrics
*/
#timestamp;
constructor(options = {}) {
super();
this.dimensions = {};
this.setEnvConfig();

@@ -218,10 +203,12 @@ this.setConsole();

}
if (constants_js_1.MAX_DIMENSION_COUNT <= this.getCurrentDimensionsCount()) {
if (constants_js_1.MAX_DIMENSION_COUNT <= this.#dimensionsStore.getDimensionCount()) {
throw new RangeError(`The number of metric dimensions must be lower than ${constants_js_1.MAX_DIMENSION_COUNT}`);
}
if (Object.hasOwn(this.dimensions, name) ||
Object.hasOwn(this.defaultDimensions, name)) {
const dimensions = this.#dimensionsStore.getDimensions();
const defaultDimensions = this.#dimensionsStore.getDefaultDimensions();
if (Object.hasOwn(dimensions, name) ||
Object.hasOwn(defaultDimensions, name)) {
this.#logger.warn(`Dimension "${name}" has already been added. The previous value will be overwritten.`);
}
this.dimensions[name] = value;
this.#dimensionsStore.addDimension(name, value);
}

@@ -242,3 +229,3 @@ /**

const newDimensions = this.#sanitizeDimensions(dimensions);
const currentCount = this.getCurrentDimensionsCount();
const currentCount = this.#dimensionsStore.getDimensionCount();
const newSetCount = Object.keys(newDimensions).length;

@@ -248,3 +235,3 @@ if (currentCount + newSetCount >= constants_js_1.MAX_DIMENSION_COUNT) {

}
this.dimensionSets.push(newDimensions);
this.#dimensionsStore.addDimensionSet(newDimensions);
}

@@ -279,3 +266,3 @@ /**

addMetadata(key, value) {
this.metadata[key] = value;
this.#metadataStore.set(key, value);
}

@@ -381,3 +368,3 @@ /**

clearDefaultDimensions() {
this.defaultDimensions = {};
this.#dimensionsStore.clearDefaultDimensions();
}

@@ -414,4 +401,3 @@ /**

clearDimensions() {
this.dimensions = {};
this.dimensionSets = [];
this.#dimensionsStore.clearRequestDimensions();
}

@@ -427,3 +413,3 @@ /**

clearMetadata() {
this.metadata = {};
this.#metadataStore.clear();
}

@@ -438,3 +424,3 @@ /**

clearMetrics() {
this.storedMetrics = {};
this.#metricsStore.clearMetrics();
}

@@ -445,3 +431,3 @@ /**

hasStoredMetrics() {
return Object.keys(this.storedMetrics).length > 0;
return this.#metricsStore.hasMetrics();
}

@@ -550,2 +536,3 @@ /**

}
/* v8 ignore else -- @preserve */
if (!this.disabled) {

@@ -594,3 +581,3 @@ const emfOutput = this.serializeMetrics();

}
this.#timestamp = this.#convertTimestampToEmfFormat(timestamp);
this.#metricsStore.setTimestamp(timestamp);
}

@@ -610,10 +597,13 @@ /**

serializeMetrics() {
// Storage resolution is included only for High resolution metrics
const metricDefinitions = Object.values(this.storedMetrics).map((metricDefinition) => ({
Name: metricDefinition.name,
Unit: metricDefinition.unit,
...(metricDefinition.resolution === constants_js_1.MetricResolution.High
? { StorageResolution: metricDefinition.resolution }
: {}),
}));
const metricDefinitions = this.#metricsStore
.getAllMetrics()
.map((metricDefinition) => {
return {
Name: metricDefinition.name,
Unit: metricDefinition.unit,
...(metricDefinition.resolution === constants_js_1.MetricResolution.High
? { StorageResolution: metricDefinition.resolution }
: {}),
};
});
if (metricDefinitions.length === 0 && this.shouldThrowOnEmptyMetrics) {

@@ -626,3 +616,3 @@ throw new RangeError('The number of metrics recorded must be higher than zero');

// name as the key and the value as the value.
const metricValues = Object.values(this.storedMetrics).reduce((result, { name, value }) => {
const metricValues = this.#metricsStore.getAllMetrics().reduce((result, { name, value, }) => {
result[name] = value;

@@ -632,12 +622,15 @@ return result;

const dimensionNames = [];
const dimensions = this.#dimensionsStore.getDimensions();
const dimensionSets = this.#dimensionsStore.getDimensionSets();
const defaultDimensions = this.#dimensionsStore.getDefaultDimensions();
const allDimensionKeys = new Set([
...Object.keys(this.defaultDimensions),
...Object.keys(this.dimensions),
...Object.keys(defaultDimensions),
...Object.keys(dimensions),
]);
if (Object.keys(this.dimensions).length > 0) {
if (Object.keys(dimensions).length > 0) {
dimensionNames.push([...allDimensionKeys]);
}
for (const dimensionSet of this.dimensionSets) {
for (const dimensionSet of dimensionSets) {
const dimensionSetKeys = new Set([
...Object.keys(this.defaultDimensions),
...Object.keys(defaultDimensions),
...Object.keys(dimensionSet),

@@ -648,8 +641,8 @@ ]);

if (dimensionNames.length === 0 &&
Object.keys(this.defaultDimensions).length > 0) {
dimensionNames.push([...Object.keys(this.defaultDimensions)]);
Object.keys(defaultDimensions).length > 0) {
dimensionNames.push(Object.keys(defaultDimensions));
}
return {
_aws: {
Timestamp: this.#timestamp ?? Date.now(),
Timestamp: this.#metricsStore.getTimestamp() ?? Date.now(),
CloudWatchMetrics: [

@@ -663,6 +656,6 @@ {

},
...this.defaultDimensions,
...this.dimensions,
...defaultDimensions,
...dimensions,
// Merge all dimension sets efficiently by mutating the accumulator
...this.dimensionSets.reduce((acc, dims) => {
...dimensionSets.reduce((acc, dims) => {
for (const [key, value] of Object.entries(dims)) {

@@ -674,3 +667,3 @@ acc[key] = value;

...metricValues,
...this.metadata,
...this.#metadataStore.getAll(),
};

@@ -704,3 +697,4 @@ }

const newDimensions = this.#sanitizeDimensions(dimensions);
const currentCount = Object.keys(this.defaultDimensions).length;
const currentDefaultDimensions = this.#dimensionsStore.getDefaultDimensions();
const currentCount = Object.keys(currentDefaultDimensions).length;
const newSetCount = Object.keys(newDimensions).length;

@@ -710,6 +704,6 @@ if (currentCount + newSetCount >= constants_js_1.MAX_DIMENSION_COUNT) {

}
this.defaultDimensions = {
...this.defaultDimensions,
this.#dimensionsStore.setDefaultDimensions({
...currentDefaultDimensions,
...newDimensions,
};
});
}

@@ -722,5 +716,5 @@ /**

*/
/* v8 ignore start */ setFunctionName(name) {
/* v8 ignore next -- @preserve */ setFunctionName(name) {
this.functionName = name;
} /* v8 ignore end */
}
/**

@@ -769,3 +763,3 @@ * Set the flag to throw an error if no metrics are emitted.

namespace: this.namespace,
defaultDimensions: this.defaultDimensions,
defaultDimensions: this.#dimensionsStore.getDefaultDimensions(),
singleMetric: true,

@@ -778,13 +772,4 @@ logger: this.#logger,

*/
/* v8 ignore start */ throwOnEmptyMetrics() {
/* v8 ignore next -- @preserve */ throwOnEmptyMetrics() {
this.shouldThrowOnEmptyMetrics = true;
} /* v8 ignore stop */
/**
* Gets the current number of dimensions count.
*/
getCurrentDimensionsCount() {
const dimensionSetsCount = this.dimensionSets.reduce((total, dimensionSet) => total + Object.keys(dimensionSet).length, 0);
return (Object.keys(this.dimensions).length +
Object.keys(this.defaultDimensions).length +
dimensionSetsCount);
}

@@ -798,24 +783,2 @@ /**

/**
* 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
*/
isNewMetric(name, unit) {
if (this.storedMetrics[name]) {
if (this.storedMetrics[name].unit !== unit) {
const currentUnit = this.storedMetrics[name].unit;
throw new Error(`Metric "${name}" has already been added with unit "${currentUnit}", but we received unit "${unit}". Did you mean to use metric unit "${currentUnit}"?`);
}
return false;
}
return true;
}
/**
* Initialize the console property as an instance of the internal version of `Console()` class (PR #748)

@@ -956,23 +919,10 @@ * or as the global node console if the `POWERTOOLS_DEV' env variable is set and has truthy value.

throw new RangeError(`Invalid metric resolution '${resolution}', expected either option: ${Object.values(constants_js_1.MetricResolution).join(',')}`);
if (Object.keys(this.storedMetrics).length >= constants_js_1.MAX_METRICS_SIZE) {
if (this.#metricsStore.getMetricsCount() >= constants_js_1.MAX_METRICS_SIZE) {
this.publishStoredMetrics();
}
if (this.isNewMetric(name, unit)) {
this.storedMetrics[name] = {
unit,
value,
name,
resolution,
};
const storedMetric = this.#metricsStore.setMetric(name, unit, value, resolution);
if (Array.isArray(storedMetric.value) &&
storedMetric.value.length === constants_js_1.MAX_METRIC_VALUES_SIZE) {
this.publishStoredMetrics();
}
else {
const storedMetric = this.storedMetrics[name];
if (!Array.isArray(storedMetric.value)) {
storedMetric.value = [storedMetric.value];
}
storedMetric.value.push(value);
if (storedMetric.value.length === constants_js_1.MAX_METRIC_VALUES_SIZE) {
this.publishStoredMetrics();
}
}
}

@@ -1001,22 +951,2 @@ /**

/**
* Converts a given timestamp to EMF compatible format.
*
* @param timestamp - The timestamp to convert, which can be either a number (in milliseconds) or a Date object.
* @returns The timestamp in milliseconds. If the input is invalid, returns 0.
*/
#convertTimestampToEmfFormat(timestamp) {
if ((0, commons_1.isIntegerNumber)(timestamp)) {
return timestamp;
}
if (timestamp instanceof Date) {
return timestamp.getTime();
}
/**
* If this point is reached, it indicates timestamp was neither a valid number nor Date
* Returning zero represents the initial date of epoch time,
* which will be skipped by Amazon CloudWatch.
*/
return 0;
}
/**
* Sanitizes the dimensions by removing invalid entries and skipping duplicates.

@@ -1028,2 +958,3 @@ *

const newDimensions = {};
const currentDimensions = this.#dimensionsStore.getDimensions();
for (const [key, value] of Object.entries(dimensions)) {

@@ -1035,4 +966,5 @@ if ((0, commons_1.isStringUndefinedNullEmpty)(key) ||

}
if (Object.hasOwn(this.dimensions, key) ||
Object.hasOwn(this.defaultDimensions, key) ||
const defaultDimensions = this.#dimensionsStore.getDefaultDimensions();
if (Object.hasOwn(currentDimensions, key) ||
Object.hasOwn(defaultDimensions, key) ||
Object.hasOwn(newDimensions, key)) {

@@ -1039,0 +971,0 @@ this.#logger.warn(`Dimension "${key}" has already been added. The previous value will be overwritten.`);

@@ -117,17 +117,2 @@ import { Utility } from '@aws-lambda-powertools/commons';

/**
* 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

@@ -142,7 +127,2 @@ */

/**
* Additional metadata to be included with metrics
* @default {}
*/
private metadata;
/**
* Namespace for the metrics

@@ -157,7 +137,2 @@ */

/**
* Storage for metrics before they are published
* @default {}
*/
private storedMetrics;
/**
* Whether to disable metrics

@@ -545,6 +520,2 @@ */

/**
* Gets the current number of dimensions count.
*/
private getCurrentDimensionsCount;
/**
* Get the custom config service if it exists.

@@ -554,15 +525,2 @@ */

/**
* 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)

@@ -569,0 +527,0 @@ * or as the global node console if the `POWERTOOLS_DEV' env variable is set and has truthy value.

@@ -5,2 +5,5 @@ import { Console } from 'node:console';

import { COLD_START_METRIC, DEFAULT_NAMESPACE, EMF_MAX_TIMESTAMP_FUTURE_AGE, EMF_MAX_TIMESTAMP_PAST_AGE, MAX_DIMENSION_COUNT, MAX_METRIC_NAME_LENGTH, MAX_METRIC_VALUES_SIZE, MAX_METRICS_SIZE, MetricResolution as MetricResolutions, MetricUnit as MetricUnits, MIN_METRIC_NAME_LENGTH, } from './constants.js';
import { DimensionsStore } from './DimensionsStore.js';
import { MetadataStore } from './MetadataStore.js';
import { MetricsStore } from './MetricsStore.js';
/**

@@ -118,17 +121,6 @@ * 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)}.

/**
* Default dimensions to be added to all metrics
* @default {}
* Storage for dimensions
*/
defaultDimensions = {};
#dimensionsStore = new DimensionsStore();
/**
* Additional dimensions for the current metrics context
* @default {}
*/
dimensions = {};
/**
* Additional dimension sets for the current metrics context
* @default []
*/
dimensionSets = [];
/**
* Name of the Lambda function

@@ -150,5 +142,4 @@ */

* Additional metadata to be included with metrics
* @default {}
*/
metadata = {};
#metadataStore = new MetadataStore();
/**

@@ -165,5 +156,4 @@ * Namespace for the metrics

* Storage for metrics before they are published
* @default {}
*/
storedMetrics = {};
#metricsStore = new MetricsStore();
/**

@@ -184,9 +174,4 @@ * Whether to disable metrics

};
/**
* Custom timestamp for the metrics
*/
#timestamp;
constructor(options = {}) {
super();
this.dimensions = {};
this.setEnvConfig();

@@ -215,10 +200,12 @@ this.setConsole();

}
if (MAX_DIMENSION_COUNT <= this.getCurrentDimensionsCount()) {
if (MAX_DIMENSION_COUNT <= this.#dimensionsStore.getDimensionCount()) {
throw new RangeError(`The number of metric dimensions must be lower than ${MAX_DIMENSION_COUNT}`);
}
if (Object.hasOwn(this.dimensions, name) ||
Object.hasOwn(this.defaultDimensions, name)) {
const dimensions = this.#dimensionsStore.getDimensions();
const defaultDimensions = this.#dimensionsStore.getDefaultDimensions();
if (Object.hasOwn(dimensions, name) ||
Object.hasOwn(defaultDimensions, name)) {
this.#logger.warn(`Dimension "${name}" has already been added. The previous value will be overwritten.`);
}
this.dimensions[name] = value;
this.#dimensionsStore.addDimension(name, value);
}

@@ -239,3 +226,3 @@ /**

const newDimensions = this.#sanitizeDimensions(dimensions);
const currentCount = this.getCurrentDimensionsCount();
const currentCount = this.#dimensionsStore.getDimensionCount();
const newSetCount = Object.keys(newDimensions).length;

@@ -245,3 +232,3 @@ if (currentCount + newSetCount >= MAX_DIMENSION_COUNT) {

}
this.dimensionSets.push(newDimensions);
this.#dimensionsStore.addDimensionSet(newDimensions);
}

@@ -276,3 +263,3 @@ /**

addMetadata(key, value) {
this.metadata[key] = value;
this.#metadataStore.set(key, value);
}

@@ -378,3 +365,3 @@ /**

clearDefaultDimensions() {
this.defaultDimensions = {};
this.#dimensionsStore.clearDefaultDimensions();
}

@@ -411,4 +398,3 @@ /**

clearDimensions() {
this.dimensions = {};
this.dimensionSets = [];
this.#dimensionsStore.clearRequestDimensions();
}

@@ -424,3 +410,3 @@ /**

clearMetadata() {
this.metadata = {};
this.#metadataStore.clear();
}

@@ -435,3 +421,3 @@ /**

clearMetrics() {
this.storedMetrics = {};
this.#metricsStore.clearMetrics();
}

@@ -442,3 +428,3 @@ /**

hasStoredMetrics() {
return Object.keys(this.storedMetrics).length > 0;
return this.#metricsStore.hasMetrics();
}

@@ -547,2 +533,3 @@ /**

}
/* v8 ignore else -- @preserve */
if (!this.disabled) {

@@ -591,3 +578,3 @@ const emfOutput = this.serializeMetrics();

}
this.#timestamp = this.#convertTimestampToEmfFormat(timestamp);
this.#metricsStore.setTimestamp(timestamp);
}

@@ -607,10 +594,13 @@ /**

serializeMetrics() {
// Storage resolution is included only for High resolution metrics
const metricDefinitions = Object.values(this.storedMetrics).map((metricDefinition) => ({
Name: metricDefinition.name,
Unit: metricDefinition.unit,
...(metricDefinition.resolution === MetricResolutions.High
? { StorageResolution: metricDefinition.resolution }
: {}),
}));
const metricDefinitions = this.#metricsStore
.getAllMetrics()
.map((metricDefinition) => {
return {
Name: metricDefinition.name,
Unit: metricDefinition.unit,
...(metricDefinition.resolution === MetricResolutions.High
? { StorageResolution: metricDefinition.resolution }
: {}),
};
});
if (metricDefinitions.length === 0 && this.shouldThrowOnEmptyMetrics) {

@@ -623,3 +613,3 @@ throw new RangeError('The number of metrics recorded must be higher than zero');

// name as the key and the value as the value.
const metricValues = Object.values(this.storedMetrics).reduce((result, { name, value }) => {
const metricValues = this.#metricsStore.getAllMetrics().reduce((result, { name, value, }) => {
result[name] = value;

@@ -629,12 +619,15 @@ return result;

const dimensionNames = [];
const dimensions = this.#dimensionsStore.getDimensions();
const dimensionSets = this.#dimensionsStore.getDimensionSets();
const defaultDimensions = this.#dimensionsStore.getDefaultDimensions();
const allDimensionKeys = new Set([
...Object.keys(this.defaultDimensions),
...Object.keys(this.dimensions),
...Object.keys(defaultDimensions),
...Object.keys(dimensions),
]);
if (Object.keys(this.dimensions).length > 0) {
if (Object.keys(dimensions).length > 0) {
dimensionNames.push([...allDimensionKeys]);
}
for (const dimensionSet of this.dimensionSets) {
for (const dimensionSet of dimensionSets) {
const dimensionSetKeys = new Set([
...Object.keys(this.defaultDimensions),
...Object.keys(defaultDimensions),
...Object.keys(dimensionSet),

@@ -645,8 +638,8 @@ ]);

if (dimensionNames.length === 0 &&
Object.keys(this.defaultDimensions).length > 0) {
dimensionNames.push([...Object.keys(this.defaultDimensions)]);
Object.keys(defaultDimensions).length > 0) {
dimensionNames.push(Object.keys(defaultDimensions));
}
return {
_aws: {
Timestamp: this.#timestamp ?? Date.now(),
Timestamp: this.#metricsStore.getTimestamp() ?? Date.now(),
CloudWatchMetrics: [

@@ -660,6 +653,6 @@ {

},
...this.defaultDimensions,
...this.dimensions,
...defaultDimensions,
...dimensions,
// Merge all dimension sets efficiently by mutating the accumulator
...this.dimensionSets.reduce((acc, dims) => {
...dimensionSets.reduce((acc, dims) => {
for (const [key, value] of Object.entries(dims)) {

@@ -671,3 +664,3 @@ acc[key] = value;

...metricValues,
...this.metadata,
...this.#metadataStore.getAll(),
};

@@ -701,3 +694,4 @@ }

const newDimensions = this.#sanitizeDimensions(dimensions);
const currentCount = Object.keys(this.defaultDimensions).length;
const currentDefaultDimensions = this.#dimensionsStore.getDefaultDimensions();
const currentCount = Object.keys(currentDefaultDimensions).length;
const newSetCount = Object.keys(newDimensions).length;

@@ -707,6 +701,6 @@ if (currentCount + newSetCount >= MAX_DIMENSION_COUNT) {

}
this.defaultDimensions = {
...this.defaultDimensions,
this.#dimensionsStore.setDefaultDimensions({
...currentDefaultDimensions,
...newDimensions,
};
});
}

@@ -719,5 +713,5 @@ /**

*/
/* v8 ignore start */ setFunctionName(name) {
/* v8 ignore next -- @preserve */ setFunctionName(name) {
this.functionName = name;
} /* v8 ignore end */
}
/**

@@ -766,3 +760,3 @@ * Set the flag to throw an error if no metrics are emitted.

namespace: this.namespace,
defaultDimensions: this.defaultDimensions,
defaultDimensions: this.#dimensionsStore.getDefaultDimensions(),
singleMetric: true,

@@ -775,13 +769,4 @@ logger: this.#logger,

*/
/* v8 ignore start */ throwOnEmptyMetrics() {
/* v8 ignore next -- @preserve */ throwOnEmptyMetrics() {
this.shouldThrowOnEmptyMetrics = true;
} /* v8 ignore stop */
/**
* Gets the current number of dimensions count.
*/
getCurrentDimensionsCount() {
const dimensionSetsCount = this.dimensionSets.reduce((total, dimensionSet) => total + Object.keys(dimensionSet).length, 0);
return (Object.keys(this.dimensions).length +
Object.keys(this.defaultDimensions).length +
dimensionSetsCount);
}

@@ -795,24 +780,2 @@ /**

/**
* 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
*/
isNewMetric(name, unit) {
if (this.storedMetrics[name]) {
if (this.storedMetrics[name].unit !== unit) {
const currentUnit = this.storedMetrics[name].unit;
throw new Error(`Metric "${name}" has already been added with unit "${currentUnit}", but we received unit "${unit}". Did you mean to use metric unit "${currentUnit}"?`);
}
return false;
}
return true;
}
/**
* Initialize the console property as an instance of the internal version of `Console()` class (PR #748)

@@ -953,23 +916,10 @@ * or as the global node console if the `POWERTOOLS_DEV' env variable is set and has truthy value.

throw new RangeError(`Invalid metric resolution '${resolution}', expected either option: ${Object.values(MetricResolutions).join(',')}`);
if (Object.keys(this.storedMetrics).length >= MAX_METRICS_SIZE) {
if (this.#metricsStore.getMetricsCount() >= MAX_METRICS_SIZE) {
this.publishStoredMetrics();
}
if (this.isNewMetric(name, unit)) {
this.storedMetrics[name] = {
unit,
value,
name,
resolution,
};
const storedMetric = this.#metricsStore.setMetric(name, unit, value, resolution);
if (Array.isArray(storedMetric.value) &&
storedMetric.value.length === MAX_METRIC_VALUES_SIZE) {
this.publishStoredMetrics();
}
else {
const storedMetric = this.storedMetrics[name];
if (!Array.isArray(storedMetric.value)) {
storedMetric.value = [storedMetric.value];
}
storedMetric.value.push(value);
if (storedMetric.value.length === MAX_METRIC_VALUES_SIZE) {
this.publishStoredMetrics();
}
}
}

@@ -998,22 +948,2 @@ /**

/**
* Converts a given timestamp to EMF compatible format.
*
* @param timestamp - The timestamp to convert, which can be either a number (in milliseconds) or a Date object.
* @returns The timestamp in milliseconds. If the input is invalid, returns 0.
*/
#convertTimestampToEmfFormat(timestamp) {
if (isIntegerNumber(timestamp)) {
return timestamp;
}
if (timestamp instanceof Date) {
return timestamp.getTime();
}
/**
* If this point is reached, it indicates timestamp was neither a valid number nor Date
* Returning zero represents the initial date of epoch time,
* which will be skipped by Amazon CloudWatch.
*/
return 0;
}
/**
* Sanitizes the dimensions by removing invalid entries and skipping duplicates.

@@ -1025,2 +955,3 @@ *

const newDimensions = {};
const currentDimensions = this.#dimensionsStore.getDimensions();
for (const [key, value] of Object.entries(dimensions)) {

@@ -1032,4 +963,5 @@ if (isStringUndefinedNullEmpty(key) ||

}
if (Object.hasOwn(this.dimensions, key) ||
Object.hasOwn(this.defaultDimensions, key) ||
const defaultDimensions = this.#dimensionsStore.getDefaultDimensions();
if (Object.hasOwn(currentDimensions, key) ||
Object.hasOwn(defaultDimensions, key) ||
Object.hasOwn(newDimensions, key)) {

@@ -1036,0 +968,0 @@ this.#logger.warn(`Dimension "${key}" has already been added. The previous value will be overwritten.`);

{
"name": "@aws-lambda-powertools/metrics",
"version": "2.28.1",
"version": "2.29.0",
"description": "The metrics package for the Powertools for AWS Lambda (TypeScript) library",

@@ -27,3 +27,3 @@ "author": {

"dependencies": {
"@aws-lambda-powertools/commons": "2.28.1"
"@aws-lambda-powertools/commons": "2.29.0"
},

@@ -30,0 +30,0 @@ "peerDependencies": {

@@ -164,2 +164,3 @@ # Powertools for AWS Lambda (TypeScript)

- [Certible](https://www.certible.com/)
- [Codeac](https://www.codeac.io/)
- [Elva](https://elva-group.com)

@@ -166,0 +167,0 @@ - [Flyweight](https://flyweight.io/)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet