From 462dc9371c2ed976a461a0a7a51fa3e7fc582969 Mon Sep 17 00:00:00 2001 From: fengxueweilai Date: Fri, 23 Oct 2026 14:18:11 +0800 Subject: [PATCH] fix(metrics-simple): support prototype-like metric names and labels Signed-off-by: fengxueweilai --- packages/metrics-simple/src/index.ts | 16 ++++++------- packages/metrics-simple/test/index.spec.ts | 27 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/packages/metrics-simple/src/index.ts b/packages/metrics-simple/src/index.ts index efb3b5baa6..42a4ca1898 100644 --- a/packages/metrics-simple/src/index.ts +++ b/packages/metrics-simple/src/index.ts @@ -72,7 +72,7 @@ class SimpleMetric implements Metric { } class SimpleGroupMetric implements MetricGroup { - private values: Record = {} + private values: Record = Object.create(null) private readonly calculate?: CalculateMetric> constructor (opts?: CalculatedMetricOptions>) { @@ -112,7 +112,7 @@ class SimpleGroupMetric implements MetricGroup { } reset (): void { - this.values = {} + this.values = Object.create(null) } timer (key: string): StopTimer { @@ -182,12 +182,12 @@ class SimpleHistogram implements Histogram { } class SimpleHistogramGroup implements HistogramGroup { - public histograms: Record = {} + public histograms: Record = Object.create(null) private readonly opts: HistogramOptions private readonly calculate?: CalculateMetric> constructor (opts?: Partial>>) { - this.histograms = {} + this.histograms = Object.create(null) this.opts = { buckets: opts?.buckets } @@ -199,7 +199,7 @@ class SimpleHistogramGroup implements HistogramGroup { this.observe(await this.calculate()) } - const output: Record }> = {} + const output: Record }> = Object.create(null) for (const [key, histogram] of Object.entries(this.histograms)) { output[key] = await histogram.collect() @@ -286,12 +286,12 @@ class SimpleSummary implements Summary { } class SimpleSummaryGroup implements SummaryGroup { - public summaries: Record = {} + public summaries: Record = Object.create(null) private readonly opts: SummaryOptions private readonly calculate?: CalculateMetric> constructor (opts?: Partial>>) { - this.summaries = {} + this.summaries = Object.create(null) this.opts = { percentiles: opts?.percentiles, compressCount: opts?.compressCount @@ -405,7 +405,7 @@ class SimpleMetrics implements Metrics, Startable { private _emitMetrics (): void { Promise.resolve().then(async () => { - const output: Record = {} + const output: Record = Object.create(null) for (const [name, metric] of this.metrics.entries()) { output[name] = await metric.collect() diff --git a/packages/metrics-simple/test/index.spec.ts b/packages/metrics-simple/test/index.spec.ts index e3927e95df..7eae162132 100644 --- a/packages/metrics-simple/test/index.spec.ts +++ b/packages/metrics-simple/test/index.spec.ts @@ -8,6 +8,33 @@ import type { Metrics } from '@libp2p/interface' describe('simple-metrics', () => { let s: Metrics + it('should support metric names and labels that match object prototype properties', async () => { + const deferred = pDefer>() + s = simpleMetrics({ onMetrics: deferred.resolve, intervalMs: 10 })({ + logger: defaultLogger() + }) + s.registerCounter('__proto__').increment(7) + const group = s.registerMetricGroup('group') + const counters = s.registerCounterGroup('counters') + const histograms = s.registerHistogramGroup('histograms') + const summaries = s.registerSummaryGroup('summaries') + for (const label of ['constructor', 'toString', '__proto__']) { + group.update({ [label]: 2 }) + counters.increment({ [label]: 3 }) + histograms.observe({ [label]: 4 }) + summaries.observe({ [label]: 5 }) + } + await start(s) + const metrics = await deferred.promise + expect(metrics).to.have.own.property('__proto__', 7) + for (const label of ['constructor', 'toString', '__proto__']) { + expect(metrics.group[label]).to.equal(2) + expect(metrics.counters[label]).to.equal(3) + expect(metrics.histograms[label].count).to.equal(1) + expect(metrics.summaries[label].count).to.equal(1) + } + }) + afterEach(async () => { if (s != null) { await stop(s)