5.4.6 Execution Log Graph
extraTwo Bazel logs with similar names answer different questions. The execution log records spawn details for cache and reproducibility investigations. The experimental execution graph log records the actions observed during one invocation, their timing metrics, and selected dependency edges. Use the second only when a trace has identified an important timed chain and you need structural evidence for why its actions could not run independently.
Choose the evidence before choosing the flag
The three nearby data sources are complementary:
| Evidence | Best question | Important boundary |
|---|---|---|
| JSON trace profile | When did work run, overlap, queue, or block completion? | A timeline does not expose every artifact dependency. |
aquery | Which actions did analysis register, with which commands, inputs, and outputs? | It is a planned action graph, not a record of the actions that ran. |
| Execution graph log | Which observed execution nodes were connected, and what duration components did they report? | It is an invocation-specific executed graph, not the complete analyzed action DAG. |
Adjacency ≠ dependency. Sequential-looking trace events may be independent. Require a graph edge and confirm the artifact relationship.
Emitted ≠ computed. Nodes emit edges and duration fields. An analyzer computes critical paths, near-critical paths, slack, and drag.
That last boundary prevents a common misreading. A node missing from the log is
not proof that the action does not exist. It may be outside the requested graph,
reused rather than executed, or omitted by the experimental logger's selected
dependency detail. Use 5.2.3 bazel aquery — Action Graph for the registered action graph and the
trace workflow in 5.4.2 Critical Path for the invocation's timeline.
The ordinary execution log serves another purpose. Its binary, JSON, and compact forms describe executed spawns, including details such as arguments, environment, inputs, outputs, and execution metadata. The compact form uses back-references and compression to avoid repeating large input sets, making cross-invocation comparison practical.1 It is the better artifact for “why was this a cache miss?” The execution graph log is the better raw artifact for “which observed producer must precede this consumer?”
Capture the experimental graph deliberately
The execution graph logger is an experimental, undocumented interface. The exact flags must therefore be checked against the Bazel binary that will produce the data. The following command was verified with Bazel 9.0.0:
bazel build //app:release \
--experimental_enable_execution_graph_log \
--experimental_execution_graph_log_path=execution-graph.proto.zst \
--experimental_execution_graph_log_dep_type=all
The Bazel-9-pinned reproduction runs two
dependent genrule actions with those exact options. Its
source-derived decoder
checks the Zstandard frame and the matching Bazel 9 protobuf field numbers,
then asserts that the consumer's dependent_index list contains the producer's
node index. The captured result is:
zstd frame: yes
decoded schema: Bazel 9.0.0 execution_graph.Node
//:produce mnemonic: Genrule
//:consume mnemonic: Genrule
consumer depends on producer index: yes
The 9.0.0 source declares these options as UNDOCUMENTED, which is why normal
bazel help output does not list them. Newer official documentation instead
shows --experimental_execution_graph_log together with
--experimental_execution_graph_log_dep_type=all. Treat that as version
evolution rather than assuming the newer spelling is a Bazel 9 alias. The
fixture's source evidence
links the exact 9.0.0 option declarations and schema.
dep_type=all requests every inter-action edge available to the logger. The
output is a Zstandard-compressed stream of length-delimited protobuf Node
messages, not JSON, DOT, or a ready-made visualization. Each node can carry a
description, index, target label when available, mnemonic, runner information,
direct dependency indexes, and timing components such as total duration,
processing, setup, queueing, fetching, network transfer, and output processing.
The format itself does not contain a critical_path, near_critical, or drag
annotation.
That distinction reconciles two descriptions often collapsed into one. Bazel's performance guide says the graph data can be used to understand an action's critical-path drag—the potential time saved by removing a node—and to predict the impact of graph changes.2 Those are analyses computed from dependency edges and durations. They are not per-node annotations emitted by the protobuf. A BazelCon case study likewise describes using the data to compare critical and near-critical alternatives, but also describes an internal ingestion and analysis system rather than a bundled command that produces those answers.3
There is currently no stable Bazel command that turns this file into a graph or
critical-path report. Before enabling collection at scale, choose and version a
consumer that can decompress the stream, decode the matching
execution_graph.proto, and calculate the graph metric your decision requires.
Keep the Bazel version, target pattern, flags, cache state, and invocation ID
beside the log. Both the flag surface and protobuf are experimental.
Read edges without inventing causality
An edge says that the logger observed an execution dependency. It supports a structural statement: the consumer could not complete before the producer made the required result available. It does not say that the edge consumed all of the intervening wall time, nor that removing it is correct.
Use this sequence for a defensible investigation:
- Capture a representative JSON trace and locate the chain that gates the user-visible build.
- Capture the execution graph log for the same targets, configuration, cache state, and environment.
- Resolve the trace action and graph node by concrete identity—prefer mnemonic, target label when present, description, and primary output over a transient node index.
- Walk direct dependency indexes backward from the gated node. Confirm the
producer/consumer artifact relationship with
aquerybefore proposing an edge change. - Compute path length or drag in the chosen analyzer. Also inspect paths with little slack. Shortening one route may merely expose another.
- Make one correctness-preserving change, then repeat the same captures and compare end-to-end time.
Node indexes are dense identifiers for one build, not stable action IDs. Do not join logs from two invocations by index. Target labels may also be absent for shared actions, so a production analyzer needs a documented matching policy and must report ambiguous matches instead of silently pairing them.
The graph explains dependency serialization, but not every sequential-looking interval. Independent actions can still run one after another because of CPU, memory, remote queue capacity, execution strategy, or scheduler choices. Read those waits in the trace and node metrics. Conversely, never remove a real input or dependency merely to shorten a computed path: first establish that the edge is unnecessary to the artifact's correctness.
The experimental execution graph log is a compressed protobuf record of
invocation-specific execution nodes, timing metrics, and requested dependency
edges. It complements the JSON trace's timeline and aquery's planned action
graph. It replaces neither. The compact execution log is a different format for
spawn-level cache and reproducibility diagnosis.
Critical path, near-critical paths, and drag are results an analyzer computes
from graph edges and durations, not annotations promised by the emitted node
format. Pin the Bazel version and parser, correlate nodes with trace and
aquery evidence, and validate any graph change with a comparable end-to-end
measurement.
Check your understanding · 4 questions
1.Match each evidence source to the question it is best suited to answer:
Drag each answer onto the matching prompt, or click an answer and then click a prompt
2.Two actions appear one after another in a trace. What evidence is needed before claiming that the first is a dependency of the second?
Select one answer
3.Which values can the execution graph node records emit directly?
Select all that apply
4.Assess these claims about the experimental execution graph log:
Choose True or False for each sentence
Footnotes
-
Bazel's Tracing and Logging Facilities — execution-log spawn content, compact encoding, and comparison workflow ↩
-
Extracting build performance metrics — execution graph logs, inter-action dependencies, and drag as an analysis use case ↩
-
Bazel Build Data: Avoiding Pitfalls in Debugging and Optimizing Builds — structural graph use, action contribution, and near-critical-path analysis in an internal ingestion pipeline ↩