first commit
This commit is contained in:
80
docs/foundation/timing/cron/src/otel/cron-otel.md
Normal file
80
docs/foundation/timing/cron/src/otel/cron-otel.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# cron-otel
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
`cron-otel` is the OpenTelemetry instrumentation surface for the
|
||||
`@suaveplan/cron` package. It centralises every metric emitted by the
|
||||
parser, the next-run engine, and the in-process scheduler so cardinality
|
||||
stays bounded and label semantics stay consistent. Each helper is a thin,
|
||||
no-throw wrapper around the global `metrics.getMeter("@suaveplan/cron")`
|
||||
instruments and is safe to call on every hot-path invocation — the
|
||||
underlying instrument is lazily constructed and then cached.
|
||||
|
||||
## Features
|
||||
|
||||
- Two histograms: `cron.parse.duration_ms` (outcome) and
|
||||
`cron.next_run.duration_ms` (outcome + tz).
|
||||
- Three counters: `cron.parse_total`, `cron.next_run_total`, and
|
||||
`cron.dst_transition_total`.
|
||||
- Closed-enum `outcome` and `kind` attributes to keep cardinality
|
||||
bounded; `tz` is the caller-supplied IANA name pass-through.
|
||||
- Lazy meter construction — no metrics work happens until first record.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```typescript
|
||||
import { recordParse, recordNextRun } from "@suaveplan/cron";
|
||||
|
||||
const t0 = Date.now();
|
||||
try {
|
||||
// …parse cron expression…
|
||||
recordParse(Date.now() - t0, "success");
|
||||
} catch (err) {
|
||||
recordParse(Date.now() - t0, "error");
|
||||
throw err;
|
||||
}
|
||||
|
||||
recordNextRun(0.5, "success", "America/New_York");
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```typescript
|
||||
import { recordDstTransition } from "@suaveplan/cron";
|
||||
|
||||
function instrumentNextRun(detected: "spring-forward" | "fall-back" | null, tz: string) {
|
||||
if (detected !== null) {
|
||||
recordDstTransition(detected, tz);
|
||||
}
|
||||
}
|
||||
|
||||
instrumentNextRun("spring-forward", "America/New_York");
|
||||
instrumentNextRun("fall-back", "Europe/London");
|
||||
instrumentNextRun(null, "UTC"); // no-op
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `recordParse(durationMs: number, outcome: "success" | "error"): void`.
|
||||
- `recordNextRun(durationMs: number, outcome: "success" | "error",
|
||||
tz: string): void`.
|
||||
- `recordDstTransition(kind: "spring-forward" | "fall-back",
|
||||
tz: string): void`.
|
||||
- `type Outcome = "success" | "error"` — exported helper alias.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Each instrument is materialised through `metrics.getMeter(...)` only on
|
||||
the first record call. Subsequent invocations reuse the module-scoped
|
||||
cached handle, so the hot path is a single `record`/`add` call on the
|
||||
shared instrument. The OpenTelemetry global meter provider is read each
|
||||
time — that's a no-op when no provider is installed, which lets the
|
||||
package ship metrics-ready without forcing consumers to wire up an SDK.
|
||||
Attribute cardinality is held below practical limits: `outcome` and
|
||||
`kind` are closed unions, and `tz` is passed through unmodified from the
|
||||
caller (consumers control their own tz vocabulary). The package does not
|
||||
emit logs or spans — those concerns live in higher-tier consumers like
|
||||
`@suaveplan/job-scheduler`.
|
||||
Reference in New Issue
Block a user