89 lines
2.7 KiB
TypeScript
89 lines
2.7 KiB
TypeScript
import { type Counter, type Histogram, metrics } from "@opentelemetry/api";
|
|
|
|
/** Low-cardinality `mode` enum for the histograms below. */
|
|
export type GenerateMode = "random" | "pronounceable" | "passphrase" | "pin";
|
|
|
|
let _generateDurationMs: Histogram | undefined;
|
|
let _entropyBits: Histogram | undefined;
|
|
let _errorsTotal: Counter | undefined;
|
|
|
|
function getInstruments(): {
|
|
generateDurationMs: Histogram;
|
|
entropyBits: Histogram;
|
|
errorsTotal: Counter;
|
|
} {
|
|
const meter = metrics.getMeter("@suaveplan/password-generator");
|
|
_generateDurationMs ??= meter.createHistogram(
|
|
"pwgen.generate_duration_ms",
|
|
{
|
|
description:
|
|
"Wall-clock duration of a single successful password / passphrase / PIN generation",
|
|
unit: "ms",
|
|
}
|
|
);
|
|
_entropyBits ??= meter.createHistogram("pwgen.entropy_bits", {
|
|
description: "Estimated entropy of the generated secret",
|
|
unit: "bit",
|
|
});
|
|
_errorsTotal ??= meter.createCounter("pwgen.errors_total", {
|
|
description:
|
|
"Count of typed errors thrown from @suaveplan/password-generator",
|
|
});
|
|
return {
|
|
generateDurationMs: _generateDurationMs,
|
|
entropyBits: _entropyBits,
|
|
errorsTotal: _errorsTotal,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Record a successful generation. Threading every production path through
|
|
* a single helper keeps the attribute key set ("mode") consistent and the
|
|
* cardinality bounded.
|
|
*/
|
|
export function recordGeneration(
|
|
mode: GenerateMode,
|
|
durationMs: number,
|
|
bits: number
|
|
): void {
|
|
const { generateDurationMs, entropyBits } = getInstruments();
|
|
generateDurationMs.record(durationMs, { mode });
|
|
entropyBits.record(bits, { mode });
|
|
}
|
|
|
|
/** Record a typed error by stable code. */
|
|
export function recordError(code: string): void {
|
|
const { errorsTotal } = getInstruments();
|
|
errorsTotal.add(1, { code });
|
|
}
|
|
|
|
/** Reset the cached instruments (test-only). */
|
|
export function _resetInstruments(): void {
|
|
_generateDurationMs = undefined;
|
|
_entropyBits = undefined;
|
|
_errorsTotal = undefined;
|
|
}
|
|
|
|
/**
|
|
* Public-facing accessors so callers (and tests) can inspect the
|
|
* underlying instruments. Lazy-evaluated so the active MeterProvider is
|
|
* always honoured.
|
|
*/
|
|
export const generateDurationMs = {
|
|
record(value: number, attrs: { mode: GenerateMode }): void {
|
|
getInstruments().generateDurationMs.record(value, attrs);
|
|
},
|
|
};
|
|
|
|
export const entropyBits = {
|
|
record(value: number, attrs: { mode: GenerateMode }): void {
|
|
getInstruments().entropyBits.record(value, attrs);
|
|
},
|
|
};
|
|
|
|
export const errorsTotal = {
|
|
add(value: number, attrs: { code: string }): void {
|
|
getInstruments().errorsTotal.add(value, attrs);
|
|
},
|
|
};
|