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¶
1. Gradle plugin (recommended)¶
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¶
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¶
Failure reports include the span tree: controller โ service โ DB โ Kafka, with timings per hop.
For in-process JVM apps launched by Stove, the OTel agent instruments supported libraries at bytecode level. Non-JVM apps need SDK wiring.
traceparent headers and Kafka headers carry context when your clients and consumers propagate them.
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_traceexposes 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) |