feat(core-shared): IMetrics interface + NoopMetrics impl
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
export type MetricAttributeValue = string | number | boolean;
|
||||
|
||||
/**
|
||||
* Vendor-neutral metrics signal interface. Mirrors the pattern of ITracer / ILogger.
|
||||
* Three impls: NoopMetrics (noop), OtelMetrics (OTel API), RecordingMetrics (core-testing).
|
||||
*
|
||||
* gauge() limitation: uses UpDownCounter under the hood, which accumulates deltas.
|
||||
* True "set to absolute value" semantics require ObservableGauge with a callback —
|
||||
* deferred to a v2 interface when the first true-gauge use case lands.
|
||||
*/
|
||||
export interface IMetrics {
|
||||
/** Monotonic counter. Use for event counts (signups, errors, requests). */
|
||||
counter(
|
||||
name: string,
|
||||
value?: number,
|
||||
attributes?: Record<string, MetricAttributeValue>,
|
||||
): void;
|
||||
|
||||
/** Distribution. Use for measured quantities (latency, payload size). */
|
||||
histogram(
|
||||
name: string,
|
||||
value: number,
|
||||
attributes?: Record<string, MetricAttributeValue>,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Point-in-time value. UpDownCounter under the hood — true gauge semantics
|
||||
* (set to absolute value) require ObservableGauge with an async callback;
|
||||
* that is deferred to a future v2 spec when the first true-gauge use case arrives.
|
||||
*/
|
||||
gauge(
|
||||
name: string,
|
||||
value: number,
|
||||
attributes?: Record<string, MetricAttributeValue>,
|
||||
): void;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { NoopMetrics } from "./noop-metrics";
|
||||
|
||||
describe("NoopMetrics", () => {
|
||||
it("counter() returns undefined without throwing", () => {
|
||||
const metrics = new NoopMetrics();
|
||||
expect(() => metrics.counter("my.counter")).not.toThrow();
|
||||
expect(() => metrics.counter("my.counter", 5)).not.toThrow();
|
||||
expect(() =>
|
||||
metrics.counter("my.counter", 1, { feature: "auth", success: true }),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it("histogram() returns undefined without throwing", () => {
|
||||
const metrics = new NoopMetrics();
|
||||
expect(() => metrics.histogram("my.latency", 42)).not.toThrow();
|
||||
expect(() =>
|
||||
metrics.histogram("my.latency", 100, { route: "/api/me" }),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it("gauge() returns undefined without throwing", () => {
|
||||
const metrics = new NoopMetrics();
|
||||
expect(() => metrics.gauge("queue.depth", 7)).not.toThrow();
|
||||
expect(() =>
|
||||
metrics.gauge("queue.depth", 3, { queue: "emails" }),
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
21
packages/core-shared/src/instrumentation/noop-metrics.ts
Normal file
21
packages/core-shared/src/instrumentation/noop-metrics.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { IMetrics, MetricAttributeValue } from "./metrics.interface";
|
||||
|
||||
export class NoopMetrics implements IMetrics {
|
||||
counter(
|
||||
_name: string,
|
||||
_value?: number,
|
||||
_attributes?: Record<string, MetricAttributeValue>,
|
||||
): void {}
|
||||
|
||||
histogram(
|
||||
_name: string,
|
||||
_value: number,
|
||||
_attributes?: Record<string, MetricAttributeValue>,
|
||||
): void {}
|
||||
|
||||
gauge(
|
||||
_name: string,
|
||||
_value: number,
|
||||
_attributes?: Record<string, MetricAttributeValue>,
|
||||
): void {}
|
||||
}
|
||||
Reference in New Issue
Block a user