Skip to content

Tracing

Test failed. Need to know what happened inside the app, not just at the test boundary. Stove tracing starts an OTLP receiver for the suite, correlates spans with the current test, and prints the captured span tree alongside the failure.

Two steps 1) Apply the stoveTracing Gradle plugin. 2) Call tracing { enableSpanReceiver() } in your Stove().with. For JVM apps launched by Stove, the plugin can attach the OTel Java Agent; for process/container apps, wire your language's OTel SDK to the exposed endpoint. Walk through the full failure loop in When a test fails.

Setup

plugins {
    id("com.trendyol.stove.tracing") version "$stoveVersion"
}

stoveTracing {
    serviceName.set("my-service")
    testTaskNames.set(listOf("e2eTest"))
}

The plugin:

  • attaches the OpenTelemetry Java agent for in-process JVM test tasks
  • boots an OTLP gRPC receiver on a free port
  • exposes OTEL_* values that runners can pass to the AUT
  • handles agent download + caching

2. Enable span receiver in Stove

Stove().with {
    tracing { enableSpanReceiver() }
    // ... your systems + runner
}.run()

For in-process JVM apps, spans from agent-supported libraries such as Spring, JDBC, Kafka, gRPC, HTTP clients, Redis, and MongoDB can show up in the failure report without application code changes. For separate processes or containers, the app must initialize an OTel SDK/exporter and send spans to the receiver.

Why Gradle?

The stoveTracing plugin handles JVM agent attachment and OTLP wiring per test task. Maven can replicate the receiver setup manually, but the agent-attach + per-task port allocation is plugin-only today.

What you get

๐ŸŒฒ
Full call chain on failure

Failure reports include the span tree: controller โ†’ service โ†’ DB โ†’ Kafka, with timings per hop.

๐Ÿš€
No app changes for JVM agent mode

For in-process JVM apps launched by Stove, the OTel agent instruments supported libraries at bytecode level. Non-JVM apps need SDK wiring.

๐Ÿ”—
W3C propagation

traceparent headers and Kafka headers carry context when your clients and consumers propagate them.

๐Ÿงช
Parallel-test safe

Each test gets its own trace ID. Concurrent tests don't blur into one tree.

Assertions on spans

tracing { } exposes a small DSL inside stove { }:

stove {
    http { post<OrderResponse>("/orders", body) { /* ... */ } }

    tracing {
        shouldContainSpan("OrderService.place") {
            attributes["order.amount"] shouldBe "99.99"
        }
        shouldNotHaveFailedSpans()
        executionTimeShouldBeLessThan(2.seconds)
    }
}
Assertion Use for
shouldContainSpan(name) { ... } A specific operation ran with expected attributes
shouldNotHaveFailedSpans() No span ended in error state
shouldHaveSpanCount(n) Span count matches expectation (regression guard)
executionTimeShouldBeLessThan(d) Total trace duration under a budget

Configuration

stoveTracing { } Gradle extension:

Option Default Notes
serviceName project name shown in spans + dashboard
testTaskNames ["test"] tasks the plugin instruments
spanCollectionTimeout 5 seconds how long to wait for late spans after the test ends
maxSpansPerTrace 1000 bounds memory; spans past the cap are dropped
otelAgentVersion latest stable override if you need to pin

tracing { } runtime block options inside Stove().with:

Option Default Notes
enableSpanReceiver() required starts the OTLP receiver
filterSpans { span -> ... } none drop noise (e.g. health checks)

Real-world example

Order placement: HTTP โ†’ service โ†’ inventory check โ†’ DB insert โ†’ Kafka publish. When the test fails (no event published), the span tree shows why:

โ–พ POST /orders                       42ms
  โ”œโ”€ OrderController.create          2ms
  โ”œโ”€ โ–พ OrderService.place           35ms
  โ”‚    โ”œโ”€ InventoryClient.fetch     7ms
  โ”‚    โ”œโ”€ โ–พ StockGuard.check        1ms
  โ”‚    โ”‚    โ””โ”€ returned: INSUFFICIENT
  โ”‚    โ””โ”€ KafkaProducer.send         3ms
  โ”‚         topic = order.failed.v1      โ† !? expected order.created.v1
  โ””โ”€ HTTP 201 returned

Bug found: inventory shows out-of-stock, app published order.failed.v1 instead. Walk the entire flow visually in When a test fails.

Polyglot apps (Go, Python, ...)

For non-JVM AUTs, the plugin still boots the OTLP receiver. Process and container runners can pass the endpoint through env vars or CLI args; your language's OTel SDK must read that endpoint and export spans. Those spans can land in the same trace tree as the test when W3C context propagation is wired. See Polyglot overview.

Pairs well with

  • Dashboard. Interactive span tree, attribute search, timeline view.

  • MCP. stove_trace exposes the tree to agents.

  • Reporting. Console output combines test entries + span summary.

  • When a test fails. The whole loop in one scroll.

Troubleshooting

Symptom Check
No spans in failure report stoveTracing plugin applied? Task name listed in testTaskNames? tracing { enableSpanReceiver() } in Stove().with?
Test task hangs at end Span collection timeout too high; lower spanCollectionTimeout
Span tree too noisy Use filterSpans { ... } to drop health checks and trivial spans
Different agent version needed Pin via otelAgentVersion.set("...")
Custom OTel SDK in app conflicts The plugin's agent takes precedence; remove the in-app SDK or use SDK-only mode (advanced)