diff --git a/packages/metrics/src/Metrics.ts b/packages/metrics/src/Metrics.ts index 64f1540945..be34372f70 100644 --- a/packages/metrics/src/Metrics.ts +++ b/packages/metrics/src/Metrics.ts @@ -320,6 +320,10 @@ class Metrics extends Utility implements MetricsInterface { * @param value - The value of the metadata */ public addMetadata(key: string, value: string): this { + if (this.#metricsStore.getMetric(key) !== undefined) + throw new Error( + `Metadata key "${key}" conflicts with an existing metric name and would overwrite it in the EMF output` + ); this.#metadataStore.set(key, value); return this; } @@ -1067,6 +1071,16 @@ class Metrics extends Utility implements MetricsInterface { ).join(',')}` ); + const dimensionKeys = new Set([ + ...Object.keys(this.#dimensionsStore.getDimensions()), + ...Object.keys(this.#dimensionsStore.getDefaultDimensions()), + ...this.#dimensionsStore.getDimensionSets().flatMap(Object.keys), + ]); + if (dimensionKeys.has(name)) + throw new Error( + `Metric name "${name}" conflicts with an existing dimension key and would overwrite it in the EMF output` + ); + if (this.#metricsStore.getMetricsCount() >= MAX_METRICS_SIZE) { this.publishStoredMetrics(); } diff --git a/packages/metrics/tests/unit/dimensions.test.ts b/packages/metrics/tests/unit/dimensions.test.ts index 774a748795..6edefacf21 100644 --- a/packages/metrics/tests/unit/dimensions.test.ts +++ b/packages/metrics/tests/unit/dimensions.test.ts @@ -647,4 +647,63 @@ describe('Working with dimensions', () => { expect.not.objectContaining({ [name]: value }) ); }); + + it('throws when a metric name conflicts with an existing dimension key', () => { + // Prepare + const metrics = new Metrics({ + singleMetric: true, + }); + metrics.addDimension('environment', 'prod'); + + // Act & Assess + expect(() => + metrics.addMetric('environment', MetricUnit.Count, 1) + ).toThrowError( + 'Metric name "environment" conflicts with an existing dimension key' + ); + }); + + it('throws when a metric name conflicts with an existing default dimension key', () => { + // Prepare + const metrics = new Metrics({ + singleMetric: true, + defaultDimensions: { environment: 'prod' }, + }); + + // Act & Assess + expect(() => + metrics.addMetric('environment', MetricUnit.Count, 1) + ).toThrowError( + 'Metric name "environment" conflicts with an existing dimension key' + ); + }); + + it('throws when a metric name conflicts with the built-in service dimension', () => { + // Prepare + const metrics = new Metrics({ + singleMetric: true, + }); + + // Act & Assess + expect(() => + metrics.addMetric('service', MetricUnit.Count, 1) + ).toThrowError( + 'Metric name "service" conflicts with an existing dimension key' + ); + }); + + it('throws when a metric name conflicts with a key added via addDimensions', () => { + // Prepare + const metrics = new Metrics({ + singleMetric: true, + }); + metrics.addDimensions({ environment: 'prod' }); + + // Act & Assess + expect(() => + metrics.addMetric('environment', MetricUnit.Count, 1) + ).toThrowError( + 'Metric name "environment" conflicts with an existing dimension key' + ); + }); }); diff --git a/packages/metrics/tests/unit/metadata.test.ts b/packages/metrics/tests/unit/metadata.test.ts index 5b0353f0c5..a8ee12120e 100644 --- a/packages/metrics/tests/unit/metadata.test.ts +++ b/packages/metrics/tests/unit/metadata.test.ts @@ -86,4 +86,17 @@ describe('Working with metadata', () => { expect.not.objectContaining({ 'cost-center': '1234' }) ); }); + + it('throws when a metadata key conflicts with an existing metric name', () => { + // Prepare + const metrics = new Metrics({ namespace: 'test' }); + metrics.addMetric('request_count', MetricUnit.Count, 42); + + // Act & Assess + expect(() => + metrics.addMetadata('request_count', 'not-a-number') + ).toThrowError( + 'Metadata key "request_count" conflicts with an existing metric name' + ); + }); });