first commit
This commit is contained in:
86
docs/foundation/flow/workflow/src/otel/instruments.md
Normal file
86
docs/foundation/flow/workflow/src/otel/instruments.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# otel/instruments
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
This module is the only place in `@suaveplan/workflow` that talks to the
|
||||
OpenTelemetry API directly. Every other module reaches metrics through the
|
||||
`recordStepExecuted` and `recordCompensation` helpers exposed here, which
|
||||
keeps OTel-specific concerns (meter resolution, attribute conventions, unit
|
||||
labels) in a single audit-surface.
|
||||
|
||||
The instruments are registered eagerly at import time against
|
||||
`metrics.getMeter("@suaveplan/workflow")`. When no SDK provider is
|
||||
configured the OTel API resolves to no-op instruments, so importing this
|
||||
module in unit tests is safe — nothing is exported, nothing is exfiltrated,
|
||||
and the helpers degrade to cheap function calls.
|
||||
|
||||
## Features
|
||||
|
||||
- Counter `workflow.step.executed_total` with `{outcome, step_id}`.
|
||||
- Counter `workflow.step.compensated_total` with `{outcome, step_id}`.
|
||||
- Histogram `workflow.step.duration_ms` (unit: ms) with `{step_id}`.
|
||||
- `recordStepExecuted(stepId, outcome, durationMs)` helper that fans the
|
||||
attributes correctly and skips the histogram for `"skipped"` outcomes
|
||||
(durations are meaningless for a guard-rejected step).
|
||||
- `recordCompensation(stepId, outcome)` helper for the compensator and the
|
||||
saga.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { recordStepExecuted } from "@suaveplan/workflow/otel";
|
||||
|
||||
recordStepExecuted("charge", "completed", 42);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { metrics } from "@opentelemetry/api";
|
||||
import { MeterProvider } from "@opentelemetry/sdk-metrics";
|
||||
import { recordStepExecuted, recordCompensation } from "@suaveplan/workflow/otel";
|
||||
|
||||
const reader = new InMemoryMetricReader();
|
||||
const provider = new MeterProvider({ readers: [reader] });
|
||||
metrics.setGlobalMeterProvider(provider);
|
||||
|
||||
await engine.run({ initialData });
|
||||
|
||||
const snapshot = await reader.collect();
|
||||
const stepCounter = snapshot.resourceMetrics.scopeMetrics[0].metrics.find(
|
||||
(m) => m.descriptor.name === "workflow.step.executed_total",
|
||||
);
|
||||
expect(stepCounter?.dataPoints.length).toBeGreaterThan(0);
|
||||
|
||||
// Direct helpers also work outside the engine.
|
||||
recordStepExecuted("custom", "failed", 17);
|
||||
recordCompensation("custom", "compensated");
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `stepExecutedCounter: Counter` — exported for advanced inspection / typed
|
||||
assertions in tests.
|
||||
- `stepCompensatedCounter: Counter` — same.
|
||||
- `stepDurationHistogram: Histogram` — same.
|
||||
- `recordStepExecuted(stepId: string, outcome: "completed" | "failed" | "skipped", durationMs: number): void`
|
||||
— increments the executed counter and records the duration histogram
|
||||
(when the outcome is not `"skipped"`).
|
||||
- `recordCompensation(stepId: string, outcome: "compensated" | "compensation-failed"): void`
|
||||
— increments the compensated counter only.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
We deliberately skip the histogram emit on `"skipped"` outcomes because the
|
||||
guard never enters `execute`, so any duration we recorded would be the wall
|
||||
time of `shouldExecute` — a different signal from "step running time".
|
||||
Consumers who want guard-evaluation timing should add their own histogram
|
||||
inside the guard.
|
||||
|
||||
Attribute keys follow the OpenTelemetry semantic-conventions style
|
||||
(snake_case) so they group cleanly alongside other `@suaveplan/*` metrics
|
||||
(e.g. `step_id` matches `entity_id` in `@suaveplan/ecs`).
|
||||
Reference in New Issue
Block a user