DataFusion Tracing
DataFusion Tracing is an extension for Apache DataFusion that helps you monitor and debug queries. It uses tracing and OpenTelemetry to gather DataFusion metrics, trace execution steps, and preview partial query results.
Note: This is not an official Apache Software Foundation release.
Overview
When you run queries with DataFusion Tracing enabled, it automatically adds tracing around execution steps, records all native DataFusion metrics such as execution time and output row count, lets you preview partial results for easier debugging, and integrates with OpenTelemetry for distributed tracing. This makes it simpler to understand and improve query performance.
See it in action
Here's what DataFusion Tracing can look like in practice:


Getting Started
Installation
Include DataFusion Tracing in your project's Cargo.toml:
[]
= "50.0.0"
= "50.0.2"
Compatibility note
The ellipsis truncation indicator in pretty_format_compact_batch is disabled in this version
because it requires comfy-table >= 7.1.4, while Apache Arrow currently pins comfy-table to
7.1.2 to preserve its MSRV. Context: comfy-table 7.2.0 bumped MSRV to Rust 1.85 while Arrow
remains at 1.84. See arrow-rs issue #8243
and PR #8244. Arrow used an exact pin rather
than ~7.1, which would also preserve MSRV while allowing 7.1.x (including 7.1.4). We will
re-enable it once Arrow relaxes the pin to allow >= 7.1.4.
Quick Start Example
use ;
use ;
use Arc;
use field;
async
A more complete example can be found in the examples directory.
Optimizer rule ordering (put instrumentation last)
Always register the instrumentation rule last in your physical optimizer chain.
- Many optimizer rules identify nodes using
as_any().downcast_ref::<ConcreteExec>(). Since instrumentation wraps each node in a privateInstrumentedExec, those downcasts won’t match if instrumentation runs first, causing rules to be skipped or, in code that assumes success, to panic. - Some rules may rewrite parts of the plan after instrumentation. While
InstrumentedExecre-wraps many common mutations, placing the rule last guarantees full, consistent coverage regardless of other rules’ behaviors.
Why is InstrumentedExec private?
- To prevent downstream code from downcasting to or unwrapping the wrapper, which would be brittle and force long-term compatibility constraints on its internals. The public contract is the optimizer rule, not the concrete node.
How to ensure it is last:
- When chaining:
builder.with_physical_optimizer_rule(rule_a) .with_physical_optimizer_rule(rule_b) .with_physical_optimizer_rule(instrument_rule) - Or collect:
builder.with_physical_optimizer_rules(vec![..., instrument_rule])
Setting Up a Collector
Before diving into DataFusion Tracing, you'll need to set up an OpenTelemetry collector to receive and process the tracing data. There are several options available:
Jaeger (Local Development)
For local development and testing, Jaeger is a great choice. It's an open-source distributed tracing system that's easy to set up. You can run it with Docker using:
Once running, you can access the Jaeger UI at http://localhost:16686. For more details, check out their getting started guide.
DataDog (Cloud-Native)
For a cloud-native approach, DataDog offers a hosted solution for OpenTelemetry data. You can send your traces directly to their platform by configuring your DataDog API key and endpoint - their OpenTelemetry integration guide has all the details.
Other Collectors
Of course, you can use any OpenTelemetry-compatible collector. The official OpenTelemetry Collector is a good starting point if you want to build a custom setup.
Repository Structure
The repository is organized as follows:
datafusion-tracing/: Core tracing functionality for DataFusioninstrumented-object-store/: Object store instrumentationintegration-utils/: Integration utilities and helpers for examples and tests (not for production use)examples/: Example applications demonstrating the library usagetests/: Integration testsdocs/: Documentation, including logos and screenshots
Building and Testing
Use these commands to build and test:
Test data: generate TPCH Parquet files
Integration tests and examples expect TPCH tables in Parquet format to be present in integration-utils/data (not checked in). Generate them locally with:
This produces all TPCH tables at scale factor 0.1 as single Parquet files in integration-utils/data. CI installs tpchgen-cli and runs the same script automatically before tests. If a required file is missing, the helper library will return a clear error instructing you to run the script.
Contributing
Contributions are welcome. Make sure your code passes all tests, follow existing formatting and coding styles, and include tests and documentation. See CONTRIBUTING.md for detailed guidelines.
License
Licensed under the Apache License, Version 2.0. See LICENSE.
Acknowledgments
This project includes software developed at Datadog (info@datadoghq.com).