Search before asking
Description
The Zipkin query API has no way to ask for the cold stage, so Zipkin traces cannot be read once they have aged out of hot+warm — even on a deployment where zipkinTrace has a cold stage configured and the data is demonstrably there.
The native query protocol has carried Duration.coldStage since BanyanDB's lifecycle stages landed, and bydb.yml exposes enableColdStage for the zipkinTrace group alongside trace, recordsLog and the metrics tiers. So the storage side is complete: Zipkin spans migrate into the cold stage exactly like native traces. Only the query surface is missing.
The practical effect is that a deployment ageing Zipkin traces into cold storage can write them and never read them back. For a UI it is worse than a gap, because the two trace sources answer differently under the same switch: a "cold only" selection returns cold native traces beside hot Zipkin traces, with nothing to indicate that one of the two ignored the request.
Use case
An operator investigating an incident older than the hot+warm window switches their UI to cold-stage reads. Native traces answer from cold. Zipkin traces answer from hot — which for that window is empty, or worse, is a different set of traces than the ones being compared against.
Apache SkyWalking Horizon UI (apache/skywalking-horizon-ui) exposes a cold-stage toggle that maps onto Duration.coldStage. Because the Zipkin branch cannot carry the flag, the UI has to either exclude the Zipkin trace source from the toggle — which makes the feature inconsistent between two views of the same concept — or show hot Zipkin results under a cold-only label. Neither is good, and both are worked around rather than solved.
Proposal
Add an optional coldStage query parameter to the Zipkin query endpoints, defaulting to false.
GET /api/v2/traces?...&coldStage=true
GET /api/v2/trace/{traceId}?coldStage=true
GET /api/v2/traceMany?traceIds=...&coldStage=true
GET /api/v2/autocompleteKeys?coldStage=true
GET /api/v2/autocompleteValues?key=...&coldStage=true
Why this shape:
-
Same name as the native protocol. The query-protocol field is Duration.coldStage; keeping the name identical means one term for one concept across both query surfaces, which matters for documentation, for translations, and for anyone grepping.
-
Compatible with Zipkin clients by construction. The parameter is not part of the Zipkin OpenAPI spec, so no existing client sends it, and the default preserves today's behaviour exactly. A server that ignores an unknown parameter and a server that defaults it to false are indistinguishable to those clients.
-
It reaches the existing plumbing. ZipkinQueryHandler already builds a Duration for every one of these endpoints before delegating to ZipkinQueryService — for example in getTraces:
Duration duration = new Duration();
duration.setStep(Step.SECOND);
duration.setStart(startTime.toString("yyyy-MM-dd HHmmss"));
duration.setEnd(endTime.toString("yyyy-MM-dd HHmmss"));
List<List<Span>> traces = zipkinQueryService.getTraces(queryRequest, duration);
so the change is to accept the parameter and call duration.setColdStage(...) on the object that already exists. No new plumbing, and non-BanyanDB storage keeps ignoring the resulting flag as it does today.
Two points worth settling in review:
- Which endpoints take it. The trace reads clearly should. The two autocomplete endpoints also build a
Duration, so they can — though tag keys and values may be considered stage-independent, in which case leaving them hot is a defensible answer as long as it is deliberate rather than accidental.
- Behaviour when the group has no cold stage. The native protocol returns empty, which is consistent and honest; the Zipkin endpoints should do the same rather than silently falling back to hot, since a silent fallback is precisely what makes the current situation hard to diagnose.
Related code
oap-server/server-query-plugin/zipkin-query-plugin/src/main/java/org/apache/skywalking/oap/query/zipkin/handler/ZipkinQueryHandler.java
oap-server/server-starter/src/main/resources/bydb.yml — the zipkinTrace group and its enableColdStage
Are you willing to submit a pull request to implement this on your own?
Search before asking
Description
The Zipkin query API has no way to ask for the cold stage, so Zipkin traces cannot be read once they have aged out of hot+warm — even on a deployment where
zipkinTracehas a cold stage configured and the data is demonstrably there.The native query protocol has carried
Duration.coldStagesince BanyanDB's lifecycle stages landed, andbydb.ymlexposesenableColdStagefor thezipkinTracegroup alongsidetrace,recordsLogand the metrics tiers. So the storage side is complete: Zipkin spans migrate into the cold stage exactly like native traces. Only the query surface is missing.The practical effect is that a deployment ageing Zipkin traces into cold storage can write them and never read them back. For a UI it is worse than a gap, because the two trace sources answer differently under the same switch: a "cold only" selection returns cold native traces beside hot Zipkin traces, with nothing to indicate that one of the two ignored the request.
Use case
An operator investigating an incident older than the hot+warm window switches their UI to cold-stage reads. Native traces answer from cold. Zipkin traces answer from hot — which for that window is empty, or worse, is a different set of traces than the ones being compared against.
Apache SkyWalking Horizon UI (apache/skywalking-horizon-ui) exposes a cold-stage toggle that maps onto
Duration.coldStage. Because the Zipkin branch cannot carry the flag, the UI has to either exclude the Zipkin trace source from the toggle — which makes the feature inconsistent between two views of the same concept — or show hot Zipkin results under a cold-only label. Neither is good, and both are worked around rather than solved.Proposal
Add an optional
coldStagequery parameter to the Zipkin query endpoints, defaulting tofalse.Why this shape:
Same name as the native protocol. The query-protocol field is
Duration.coldStage; keeping the name identical means one term for one concept across both query surfaces, which matters for documentation, for translations, and for anyone grepping.Compatible with Zipkin clients by construction. The parameter is not part of the Zipkin OpenAPI spec, so no existing client sends it, and the default preserves today's behaviour exactly. A server that ignores an unknown parameter and a server that defaults it to
falseare indistinguishable to those clients.It reaches the existing plumbing.
ZipkinQueryHandleralready builds aDurationfor every one of these endpoints before delegating toZipkinQueryService— for example ingetTraces:so the change is to accept the parameter and call
duration.setColdStage(...)on the object that already exists. No new plumbing, and non-BanyanDB storage keeps ignoring the resulting flag as it does today.Two points worth settling in review:
Duration, so they can — though tag keys and values may be considered stage-independent, in which case leaving them hot is a defensible answer as long as it is deliberate rather than accidental.Related code
oap-server/server-query-plugin/zipkin-query-plugin/src/main/java/org/apache/skywalking/oap/query/zipkin/handler/ZipkinQueryHandler.javaoap-server/server-starter/src/main/resources/bydb.yml— thezipkinTracegroup and itsenableColdStageAre you willing to submit a pull request to implement this on your own?