first commit
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# `otel/instruments`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Registers the OpenTelemetry counter and histogram that every CLI command
|
||||
in `@suaveplan/server-keys` emits exactly once per invocation through the
|
||||
`runFunction` wrapper. The instruments live behind the global meter
|
||||
provider supplied by `@opentelemetry/api`, so production deployments can
|
||||
plug in any exporter (OTLP, Prometheus, Jaeger) without changing the
|
||||
package. Tests wire an in-memory `MeterProvider` in `tests/setup/polyfills.ts`
|
||||
before any source module is imported, so the meter resolved at load time
|
||||
is the real provider's meter, never the noop fallback.
|
||||
|
||||
The `recordCommand(command, outcome, durationMs, errorCode?)` helper is the
|
||||
single call site every command goes through — keeping the attribute keys
|
||||
consistent and the histogram unit (`ms`) authoritative.
|
||||
|
||||
## Features
|
||||
|
||||
- Counter `server_keys.command_total{command, command.outcome[, command.error_code]}`.
|
||||
- Histogram `server_keys.command_duration_ms{command, command.outcome[, command.error_code]}`
|
||||
with `unit: "ms"`.
|
||||
- Stable attribute-key constants (`ATTR_COMMAND`, `ATTR_OUTCOME`,
|
||||
`ATTR_ERROR_CODE`) so tests can assert by name.
|
||||
- `recordCommand` records both instruments atomically so dashboards built
|
||||
on the counter and the histogram never disagree.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { recordCommand } from "@suaveplan/server-keys/otel/instruments";
|
||||
|
||||
const start = performance.now();
|
||||
try {
|
||||
await doWork();
|
||||
recordCommand("create-root-keys", "success", performance.now() - start);
|
||||
} catch (err) {
|
||||
recordCommand("create-root-keys", "error", performance.now() - start);
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Attach the typed error code when failing, so dashboards can break down
|
||||
failures by reason without scraping log lines:
|
||||
|
||||
```ts
|
||||
import { recordCommand } from "@suaveplan/server-keys/otel/instruments";
|
||||
import { ServerKeysError } from "@suaveplan/server-keys/error-codes/error-codes";
|
||||
|
||||
try {
|
||||
await prepareFileCommand(...);
|
||||
recordCommand("prepare-file", "success", elapsed);
|
||||
} catch (err) {
|
||||
const code = err instanceof ServerKeysError ? err.code : "UNKNOWN";
|
||||
recordCommand("prepare-file", "error", elapsed, code);
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
Or query the in-memory test exporter to assert on emitted metrics:
|
||||
|
||||
```ts
|
||||
await flushTestMetrics(); // from tests/setup/polyfills.ts
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `commandTotal: Counter` — total CLI commands executed.
|
||||
- `commandDurationMs: Histogram` — per-command duration (ms).
|
||||
- `ATTR_COMMAND`, `ATTR_OUTCOME`, `ATTR_ERROR_CODE` — string-literal
|
||||
attribute keys.
|
||||
- `CommandOutcome = "success" | "error"`.
|
||||
- `recordCommand(command, outcome, durationMs, errorCode?)` — record one
|
||||
observation on both instruments.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`metrics.getMeter(name, version)` returns the meter from the current
|
||||
global provider; if no provider is registered, the API package returns a
|
||||
noop meter so production code never throws on missing telemetry. Setting
|
||||
the meter provider AFTER `instruments.ts` is imported has no effect on
|
||||
this module's meter handle, so the test polyfill must register the
|
||||
provider before any `import` that transitively loads `instruments.ts`.
|
||||
Reference in New Issue
Block a user