Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# `otel` — host instrument registry
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`createHostInstruments` builds the frozen bundle of every OpenTelemetry counter and histogram the host emits on a production path. The instrument list mirrors design doc §12.3 exactly — every name is a published surface and removing one is a breaking change. The package never installs an OTel SDK; the meter-provider source is, in priority order, the explicit `meterProvider` override and then the OTel global provider (which falls back to a no-op when no SDK is wired). This keeps SDK initialisation an operator concern, not a library concern.
|
||||
|
||||
The registry also vends per-plugin meters via `forPlugin(name)` — each call returns a cached meter namespaced under `@suaveplan/api-host/plugin/<name>` with the plugin label pre-attached. Stage-4 packages plug their plugin-declared `manifest.telemetry` instruments onto these meters.
|
||||
|
||||
## Features
|
||||
|
||||
- Twelve counters (`HOST_COUNTER_NAMES`) and four histograms (`HOST_HISTOGRAM_NAMES`) covering the full §12.3 metric surface.
|
||||
- Pre-tagged host meter with `host.id` + `host.version` attributes.
|
||||
- Histogram units (`ms`, `By`) set at construction time.
|
||||
- Cached per-plugin meters with `plugin.name` pre-attached.
|
||||
- `tenantLabelOptIn` flag — defaults to `false` to bound cardinality.
|
||||
- `dispose()` clears the per-plugin meter cache for graceful teardown.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createHostInstruments } from "@suaveplan/api-host/otel";
|
||||
|
||||
const instruments = createHostInstruments({
|
||||
hostId: "host-1",
|
||||
hostVersion: "0.1.0",
|
||||
});
|
||||
|
||||
instruments.counters["api.requests_total"].add(1, { route: "/billing/invoices" });
|
||||
instruments.histograms["api.request_duration_ms"].record(42, {
|
||||
route: "/billing/invoices",
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Plug an explicit meter-provider (test harness or operator-supplied SDK):
|
||||
|
||||
```ts
|
||||
import {
|
||||
HOST_COUNTER_NAMES,
|
||||
createHostInstruments,
|
||||
} from "@suaveplan/api-host/otel";
|
||||
import { MeterProvider } from "@opentelemetry/sdk-metrics";
|
||||
|
||||
const provider = new MeterProvider({
|
||||
/* readers / views configured by the operator */
|
||||
});
|
||||
|
||||
const instruments = createHostInstruments({
|
||||
hostId: "host-1",
|
||||
hostVersion: "0.1.0",
|
||||
tenantLabelOptIn: true,
|
||||
meterProvider: provider,
|
||||
});
|
||||
|
||||
// Per-plugin meter — caches per `pluginName`.
|
||||
const billingMeter = instruments.forPlugin("billing").meter;
|
||||
const errorsByReason = billingMeter.createCounter("billing.errors_total");
|
||||
|
||||
// Verify the surface is complete.
|
||||
for (const name of HOST_COUNTER_NAMES) {
|
||||
instruments.counters[name]; // present.
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `createHostInstruments(config: HostInstrumentsConfig): HostInstruments`
|
||||
- `HOST_COUNTER_NAMES` — `readonly` tuple of every counter name.
|
||||
- `HOST_HISTOGRAM_NAMES` — `readonly` tuple of every histogram name.
|
||||
- `HostInstruments`:
|
||||
- `meter: Meter`
|
||||
- `tenantLabelOptIn: boolean`
|
||||
- `counters: Readonly<Record<HostCounterName, Counter>>`
|
||||
- `histograms: Readonly<Record<HostHistogramName, Histogram>>`
|
||||
- `forPlugin(name): PluginInstruments`
|
||||
- `dispose(): void`
|
||||
- `PluginInstruments`: `{ meter: Meter; pluginName: string }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The counter / histogram lists are exported as `readonly` tuples so consumers can iterate and assert against them in tests — a missing instrument shows up as a test failure, not a runtime no-op. Per-plugin meters are cached by name to avoid leaking meter objects on every reload (one meter per plugin is the design invariant — disposal happens at uninstall, mirrored by `dispose()` here clearing the whole cache). Tenant-label opt-in is gated at the call site rather than the registry level: the registry exposes the flag and the request pipeline (Chunk B) decides whether to attach `tenant` to a given measurement. This keeps the cardinality story explicit at every emit site rather than hidden behind a registry policy.
|
||||
Reference in New Issue
Block a user