import { type Counter, type Histogram, metrics } from "@opentelemetry/api"; /** * Bundle of OpenTelemetry instruments emitted by the banking plugin. * * - `banksTotal{op}` — bank lifecycle transitions. `op ∈ * "create" | "soft-delete" | "update"`. * - `accountsTotal{op}` — account lifecycle transitions. `op ∈ * "create" | "delete" | "update" | "status-change"`. * - `transfersTotal{outcome}` — `transferFunds` call counter. * `outcome ∈ "success" | "insufficient_funds" | "error"`. * - `transferAmount` — histogram of transfer amounts (units: currency * minor units, treated as a unitless float for genericity). * - `fundOperationsTotal{op,outcome}` — `addFunds` / `subtractFunds`. * `op ∈ "add" | "subtract"`, `outcome ∈ "success" | "error" | * "insufficient_funds"`. * - `queryDurationMs{op}` — histogram of repository query wall-clock * duration in ms, partitioned by op (`"bank.list"`, `"account.list"`, * `"transfer"`, etc.). */ export interface BankingInstruments { readonly banksTotal: Counter; readonly accountsTotal: Counter; readonly transfersTotal: Counter; readonly transferAmount: Histogram; readonly fundOperationsTotal: Counter; readonly queryDurationMs: Histogram; } let cached: BankingInstruments | undefined; /** * Lazily build (and cache) the banking instruments bundle against the * current global `MeterProvider`. Call {@link resetBankingInstruments} * in test setup to force a re-bind against a freshly-installed * provider. */ export function getBankingInstruments(): BankingInstruments { if (cached !== undefined) return cached; const meter = metrics.getMeter("@suaveplan/api-plugin-banking"); cached = { banksTotal: meter.createCounter("banking.banks_total", { description: "Total bank lifecycle transitions, partitioned by op label", }), accountsTotal: meter.createCounter("banking.accounts_total", { description: "Total bank-account lifecycle transitions, partitioned by op label", }), transfersTotal: meter.createCounter("banking.transfers_total", { description: "Total transferFunds() calls, partitioned by outcome label", }), transferAmount: meter.createHistogram("banking.transfer_amount", { description: "Histogram of transfer amounts (unitless float; treat as minor currency units)", }), fundOperationsTotal: meter.createCounter( "banking.fund_operations_total", { description: "Total addFunds/subtractFunds calls, partitioned by op + outcome", } ), queryDurationMs: meter.createHistogram("banking.query_duration_ms", { description: "Wall-clock duration of banking repository queries in ms", unit: "ms", }), }; return cached; } /** * Drop the cached instrument bundle so the next * {@link getBankingInstruments} call rebinds against the global * `MeterProvider` in effect at that point. Tests call this after * installing a fresh `MeterProvider`. */ export function resetBankingInstruments(): void { cached = undefined; }