Skip to content
Usage

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).

APIPurpose
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: 0

Signals 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. messaging edges 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 profilesEndpoint is set.

These are driven entirely from the topology. Each operation can declare:

FieldEmits
log_eventsstructured logs (name, severity, condition, body, attributes)
metricscustom counters / gauges / histograms, optionally fault-linked
profilea 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.