Usage
Import the JS module, configure OTLP, load a topology, and run journeys:
import otelgen from "k6/x/otel-gen";
export function setup() {
otelgen.configure({
endpoint: "localhost:4317",
protocol: "grpc",
insecure: true,
});
}
export default function () {
const topology = otelgen.load("./topology.yaml");
topology.runRandomJourney();
}
export function teardown() {
otelgen.flush();
}Call load() inside default(), not in setup(): k6 JSON-serializes
setup() return values, which strips the handle’s methods. load() parses
and validates the YAML only once per test run and returns the cached handle
on every subsequent call, so calling it per iteration adds no overhead.
Call otelgen.flush() in teardown(). Each trace’s root span ends after all
of its children, so it is the last span to enter the batch queue; without a
final flush it is dropped at process exit and backends report
“root span not yet received”. flush() makes trace, metric, and log delivery
independent of whether the otel-gen output is enabled — it force-flushes the
batch processors without closing the exporters, so it is safe to call with or
without --out otel-gen=... (when the output is enabled, its Stop hook still
performs the final pipeline shutdown).
| API | Purpose |
|---|---|
otelgen.configure(opts) | Configure OTLP endpoint, protocol, TLS, headers, batching |
otelgen.load(path) | Parse and validate one topology YAML file |
handle.runJourney(name) | Execute a named journey |
handle.runRandomJourney() | Pick a journey by YAML weight, execute it, and return its name |
handle.setFaultIntensity(x) | Scale injected-fault intensity for this VU (0 disables faults, 1 is full); drive from k6 stages for burn→recover |
handle.setFaultIntensity(target, x) | Override intensity for one YAML fault target such as operation:payment.authorize_card |
handle.journeyWeights() | Return { name: weight } for custom JS selection |
otelgen.flush() | Force-flush queued telemetry (call in teardown() so root spans are delivered) |
otelgen.stats() | Return exporter success/failure counters |
otelgen.journeys() | List journey names after loading |
handle.journeys() | List journey names from a handle |
Time-varying faults
handle.setFaultIntensity(x) scales injected-fault probability,
error_rate_override values, and latency_inflation amplitude for this VU
(0 disables injected faults, 1 is full intensity). Set it from default()
before each journey call to script a burn→recover timeline from the elapsed
test time:
import otelgen from "k6/x/otel-gen";
import exec from "k6/execution";
export function setup() {
otelgen.configure({
endpoint: "localhost:4317",
protocol: "grpc",
insecure: true,
});
}
export default function () {
const topology = otelgen.load("./topology.yaml");
const t = exec.instance.currentTestRunDuration / 1000; // seconds since test start
const intensity = t < 60 ? 0 : t < 180 ? 1 : 0; // healthy → incident → recovered
topology.setFaultIntensity(intensity);
topology.runRandomJourney();
}
export function teardown() {
otelgen.flush();
}Pass a YAML fault target as the first argument to override one target instead of the whole VU:
topology.setFaultIntensity("operation:payment.authorize_card", 0.5);You can also declare the same kind of burn→recover timeline directly on a
fault. A schedule is evaluated as a step function from engine start; before the
first point, the scheduled fault intensity is 0. A target override from
setFaultIntensity(target, x) takes precedence over the YAML schedule.
faults:
- target: operation:payment.authorize_card
kind: error_rate_override
severity: { probability: 1.0, value: 0.10 }
schedule:
- at: 0s
intensity: 0
- at: 1m
intensity: 1
- at: 3m
intensity: 0Signals and features
Every journey execution produces correlated OpenTelemetry signals that share a trace context:
- Traces — one trace per journey, with a span per operation and call.
messagingedges additionally emit a PRODUCER (publish) and a CONSUMER (receive) span connected by a span link. - Metrics — built-in request/duration instruments plus per-operation custom
metrics (counter / gauge / histogram). Histogram metrics carry exemplars
(
trace_id/span_id) for metrics→traces drill-down. - Logs — a per-operation log plus declarative structured log events with an
event.name. - Profiles — synthetic pprof flamegraphs pushed to Pyroscope when
profilesEndpointis set.
These are driven entirely from the topology. Each operation can declare:
| Field | Emits |
|---|---|
log_events | structured logs (name, severity, condition, body, attributes) |
metrics | custom counters / gauges / histograms, optionally fault-linked |
profile | a baseline / incident flamegraph for diff profiling, fault-linked |
See the Topology YAML Reference for the full syntax. Custom metrics and profiles can react to active faults, so an incident changes the emitted values and stacks deterministically.
See the minimal and astroshop examples for complete scripts.