Hi Bitbucket Community!
Bitbucket Pipelines now exposes pipeline execution as OpenTelemetry (OTel) traces via webhook events. This lets you stream detailed pipeline spans into your own observability stack and correlate them with the rest of your system.
This post walks through:
Pipelines are critical infrastructure: they gate releases, consume shared compute, and are often the first thing teams blame when deployments slow down. But traditional signals (build status, logs, basic timing) make it hard to answer questions like:
OpenTelemetry traces give you:
Pipeline traces are delivered as Bitbucket webhook events. You enable them on a per‑repository basis:
OTEL Traces as the webhook under pipelines section.Each webhook payload contains a resourceSpans array compatible with OpenTelemetry’s JSON representation. Within that you’ll see several span types that model the pipeline execution.
The trace hierarchy is:
We use bbc.* namespaced span names to distinguish Bitbucket Pipelines spans.
The pipeline run span represents a single execution of a pipeline: its trigger, result, and basic metadata.Sample
Key attributes to care about:
pipeline_run.uuid / pipeline.uuid – stable IDs for the run and pipeline definitionpipeline.build_number, pipeline_run.run_number – the build/run numbers you see in the UIpipeline.state.result.name – COMPLETE, FAILED, etc.pipeline.target.ref_type, pipeline.target.ref_name – branch/tag informationpipeline.trigger.name – MANUAL, SCHEDULED, PUSH, etc.This span gives you the top‑level trace you can correlate with other traces (for example, application deploy traces).
Each pipeline step is represented as a bbc.step span, child of the pipeline run.Sample
With this you can:
step.duration_in_seconds, step.state.result.name)step.uuid across commands and containersWithin each step we emit bbc.command spans for setup, teardown, and user commands. These are the most granular spans and are extremely useful for drill‑down performance analysis.Sample
Notable attributes:
command.command – the shell command that ran (ls /sys, sleep 5s, SETUP, TEARDOWN, etc.)command.duration_in_seconds – execution time per commandcommand.command_id – stable identifier (e.g. MAIN_0, SETUP, TEARDOWN)step.uuid, pipeline_run.uuid, pipeline.uuid – for joining with higher‑level spansThis makes it trivial to answer:
To understand resource behavior, we emit container metrics as attributes grouped by container name (for example docker for service containers and build for the build container).Sample (abbreviated):
Key attributes:
container.name – e.g. build, docker, or service container namescontainer.metrics.* – aggregated CPU and memory (mean, p90, max)step.uuid, pipeline_run.uuid – link back to the relevant step/runYou can use this to:
Because the payload is OpenTelemetry‑compatible, most observability stacks can ingest it with minimal glue code.
At a high level, you’ll:
resourceSpans into your OTel collector or vendor’s ingest API.bbc.pipeline_run for high‑level SLO/SLA viewsbbc.step for per‑stage performancebbc.command for deep debuggingbbc.step.container attributes for resource profilingDepending on your stack you may either:
Once wired up, teams commonly use pipeline traces for:
step.duration_in_seconds and command.duration_in_secondsstep.state.result.name, pipeline.state.result.name)container.metrics.cpu.* and container.metrics.memory.* to understand resource needs per pipelineWhen pipeline activity shows up as OpenTelemetry traces, different teams get the slice of visibility they care about most:
The result is a shared, data‑driven picture of your delivery system, where conversations move from “I think the pipeline is slow” to “we know which part is slow, why, and what it’s costing us.”
Try setting up pipeline traces today, and let us know what you think!
Want to learn more? Check out the docs.
Dan Hom
1 comment