RepoPilotOpen in app →

tokio-rs/tracing

Application level tracing for Rust.

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 1w ago
  • 52+ active contributors
  • Distributed ownership (top contributor 32% of recent commits)
Show all 6 evidence items →
  • MIT licensed
  • CI configured
  • Tests present

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/tokio-rs/tracing)](https://repopilot.app/r/tokio-rs/tracing)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/tokio-rs/tracing on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: tokio-rs/tracing

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/tokio-rs/tracing shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 1w ago
  • 52+ active contributors
  • Distributed ownership (top contributor 32% of recent commits)
  • MIT licensed
  • CI configured
  • Tests present

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live tokio-rs/tracing repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/tokio-rs/tracing.

What it runs against: a local clone of tokio-rs/tracing — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in tokio-rs/tracing | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 38 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>tokio-rs/tracing</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of tokio-rs/tracing. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/tokio-rs/tracing.git
#   cd tracing
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of tokio-rs/tracing and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "tokio-rs/tracing(\\.git)?\\b" \\
  && ok "origin remote is tokio-rs/tracing" \\
  || miss "origin remote is not tokio-rs/tracing (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "tracing-core/src/lib.rs" \\
  && ok "tracing-core/src/lib.rs" \\
  || miss "missing critical file: tracing-core/src/lib.rs"
test -f "tracing/src/lib.rs" \\
  && ok "tracing/src/lib.rs" \\
  || miss "missing critical file: tracing/src/lib.rs"
test -f "tracing-subscriber/src/lib.rs" \\
  && ok "tracing-subscriber/src/lib.rs" \\
  || miss "missing critical file: tracing-subscriber/src/lib.rs"
test -f "tracing-attributes/src/lib.rs" \\
  && ok "tracing-attributes/src/lib.rs" \\
  || miss "missing critical file: tracing-attributes/src/lib.rs"
test -f "Cargo.toml" \\
  && ok "Cargo.toml" \\
  || miss "missing critical file: Cargo.toml"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 38 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~8d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/tokio-rs/tracing"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

tokio-rs/tracing is a structured, event-based application-level tracing framework for Rust that enables instrumentation of programs to collect diagnostic information without requiring the Tokio runtime. It provides macros like info!, debug!, span! and a Subscriber trait that allows flexible consumption of trace events (logging, profiling, metrics), making it the de facto standard for observability in Rust beyond simple logging. Monorepo with 14 members: tracing-core provides the low-level API and Subscriber trait; tracing wraps it with ergonomic macros; tracing-attributes provides procedural macro support; tracing-subscriber (largest consumer crate) implements formatters (fmt module) and filters (env-filter); specialized crates like tracing-log (log compatibility), tracing-journald (systemd), tracing-appender (file I/O), tracing-flame (flamegraph export) provide ecosystem integrations. Examples/ demonstrates all patterns with runnable programs.

👥Who it's for

Backend engineers and systems developers building Rust applications who need production observability (structured logging, distributed tracing, profiling) without heavyweight external dependencies. Also library authors who want their crates to be instrumentation-friendly. Contributors are typically Tokio maintainers and community members working on observability infrastructure.

🌱Maturity & risk

This is a mature, actively maintained project with 2.2M+ lines of Rust code and a full monorepo of 14+ crates. It has comprehensive CI via GitHub Actions, security auditing (audit.yml), nextest integration, and structured releases from the main branch. The project maintains two active branches (main for v0.1.x production releases, v0.2.x for unreleased v0.2 work), indicating long-term stability and planned evolution.

Low risk for core adoption: tokio-rs is a well-established organization with robust CI/CD (audit.yml, CI.yml, release.yml). However, as a foundational logging framework, any breaking API changes in core crates (tracing-core, tracing-attributes) cascade through the ecosystem. The main branch is stable but v0.2.x carries unreleased changes; upgrading between versions requires careful coordination. Dependency surface is intentionally minimal by design.

Active areas of work

The project maintains v0.1.x on main (crates.io production) and actively develops v0.2.x as an unreleased branch. Current focus includes new subscriber formatters (json, compact, pretty examples present), structured field handling improvements, and ecosystem crate maintenance. CI runs on PR/push with full audit and nextest integration via .github/workflows and .config/nextest.toml.

🚀Get running

git clone https://github.com/tokio-rs/tracing.git
cd tracing
cargo build
cargo test --workspace
cargo run --example fmt --manifest-path examples/Cargo.toml

Daily commands: No single 'dev server'; this is a framework library. For examples: cargo run --example fmt --manifest-path examples/Cargo.toml or cargo run --example async-fn --manifest-path examples/Cargo.toml. For development: cargo test --workspace runs all tests. For documentation: cargo doc --open (from any crate directory).

🗺️Map of the codebase

  • tracing-core/src/lib.rs — Core primitives for the tracing system—spans, events, and subscriber trait definitions that all other crates depend on.
  • tracing/src/lib.rs — Main public API facade providing macros (trace!, debug!, info!, etc.) and instrument attribute used by most applications.
  • tracing-subscriber/src/lib.rs — Subscriber and layer implementations—the bridge between tracing events and actual output (logging, metrics, traces).
  • tracing-attributes/src/lib.rs — Procedural macro expansion for #[instrument] and related attributes that auto-instrument functions.
  • Cargo.toml — Workspace manifest defining all member crates and shared dependencies for the entire tracing ecosystem.
  • CONTRIBUTING.md — Guidelines for contributing to the tracing project, including design philosophy and maintenance practices.
  • README.md — High-level overview of tracing's purpose, architecture, and links to key resources and community.

🛠️How to make changes

Add a new Subscriber/Layer for custom output backend

  1. Create a new crate (e.g., tracing-mybackend/) with Cargo.toml depending on tracing-core and tracing-subscriber. (Cargo.toml (new crate))
  2. Implement the Layer trait from tracing-subscriber by creating a struct with on_event, on_new_span, and related methods. (tracing-mybackend/src/lib.rs)
  3. Initialize the layer in your subscriber setup (typically in main or app init code) and add it to a Registry using .with(my_layer). (examples/examples/custom-output.rs (create new example))
  4. Add integration tests in tracing-mybackend/tests/ using MockSubscriber to verify event/span handling. (tracing-mybackend/tests/integration.rs (create new))

Instrument a function or future with automatic span creation

  1. Add the #[instrument] attribute from tracing-attributes above your async or sync function. (your_module.rs)
  2. Optionally customize the span (name, level, skip fields) via #[instrument(name = "...", level = "debug", skip(large_arg))]. (your_module.rs)
  3. Call trace!(), debug!(), info!() macros from tracing inside the function body to emit events. (your_module.rs)
  4. Use .instrument(span) on futures if using manual Instrument trait; #[instrument] macro handles this automatically. (tracing-attributes/tests/instrument.rs (reference))

Create a filtered tracing setup (e.g., debug logs only for certain modules)

  1. Set RUST_LOG environment variable or use EnvFilter::try_from_default_env() in your subscriber initialization. (examples/examples/env-filter-explorer.rs (reference))
  2. Add a filter layer using tracing_subscriber::filter::EnvFilter and chain with .with(env_filter). (your_app/src/main.rs)
  3. Optionally compose multiple filter layers with per-layer filtering using FilterExt::and, .or, .not(). (examples/examples/subscriber-filter.rs (reference))
  4. Test filter behavior by running your app with RUST_LOG set to various patterns (e.g., 'debug,myapp::heavy=trace'). (your_app (manual testing))

Add error context and instrumentation to Result types

  1. Depend on tracing-error and import InstrumentResult from tracing_error::ext. (Cargo.toml (your crate))
  2. Call .in_current_span() on Result types to automatically link errors to the current span context. (your_module.rs)
  3. Optionally use #[instrument(err)] on fallible functions to auto-log error events on Err. (your_module.rs)
  4. Render captured error spans in logs/output via SpanTrace in your subscriber's event visitor. (tracing-subscriber/src/fmt/mod.rs (reference))

🔧Why these technologies

  • Procedural macros (tracing-attributes) — Zero-cost span and event instrumentation via compile-time code generation; allows ergonomic #[instrument] without runtime overhead.
  • Trait-based subscriber/layer system — Composable, pluggable architecture allowing independent implementations for different backends (fmt, journald, HTTP, metrics) without coupling.
  • Dynamic filtering (EnvFilter) — Runtime configuration via environment variables allows production debugging without recompilation or conditional code.
  • Async-aware Instrument trait — Propagates span context across async boundaries (futures, tokio tasks) maintaining coherent traces in concurrent code.
  • Lock-free span ID generation — Avoids contention in multi-threaded/async contexts where millions of spans may be created concurrently.

⚖️Trade-offs already made

  • Trait objects for subscribers vs. monomorphized layers

    • Why: Trait objects enable runtime composition and flexibility at the cost of dynamic dispatch overhead.
    • Consequence: Slight performance overhead per event (~microseconds) but gains ability to add/remove layers dynamically without recompilation.
  • String-based span/event metadata lookup vs. compile-time constants

    • Why: String keys enable dynamic filtering and flexible backend integration (e.g., filter by module name at runtime).
    • Consequence: Small hash lookup cost per event, offset by ergonomics and filterability; compile-time optimization difficult.

🪤Traps & gotchas

(1) RUST_LOG environment variable: tracing-subscriber::fmt::init() respects RUST_LOG for filtering (e.g., RUST_LOG=debug); without setting it, only default levels appear. (2) No global state magic: Spans created without a Subscriber installed are dropped silently—subscriber must be initialized first (common mistake in examples). (3) Two active branches: main = v0.1.x production, v0.2.x = unreleased breaking changes; PRs target main unless explicitly for v0.2. (4) Macros expect expressions: info!(x, "msg") requires x to implement Into<Value>, not just Debug; primitives and references work, but complex types need explicit field values like info!(x = ?complex_obj, "msg"). (5) Context is async-aware: Span context in tokio::task::spawn requires explicit .instrument(span) or LocalFutureExt if using non-Send spans.

🏗️Architecture

💡Concepts to learn

  • Subscriber trait — The pluggable interface that decouples span/event production (macros) from consumption (formatters, collectors, exporters); understanding it is essential to customizing tracing behavior
  • Span context propagation — Tracing automatically maintains the 'current' span context (via thread-local or async-aware mechanisms) so child events inherit parent metadata; critical for cross-layer correlation in logs
  • Structured fields and Values — Events and spans accept key-value pairs (e.g., user_id = 42, path = "/api") rather than printf-style strings; this enables rich filtering and JSON serialization without parsing
  • Procedural macros for #[instrument] — The #[instrument] attribute (from tracing-attributes) auto-wraps functions in spans with zero boilerplate; reduces instrumentation friction for library code
  • EnvFilter and filter composition — tracing-subscriber's EnvFilter enables RUST_LOG-based dynamic filtering by target/level/fields at runtime without code changes; essential for production log volume control
  • Async-aware context propagation — Unlike thread-local logging, tracing must preserve span context across await points and task boundaries in async code; .instrument(span) or LocalFutureExt handle this
  • Zero-allocation event recording — Tracing core is designed to minimize allocations in hot paths; disabled spans (below log level) produce no output without evaluation, aiding performance-critical code
  • tokio-rs/tokio — Async runtime that tracing is designed to work with; many examples use tokio::task and Tracing integrates seamlessly for async context propagation
  • slog-rs/slog — Alternative structured logging framework for Rust with similar philosophy; tracing was inspired partly by slog's composable architecture
  • open-telemetry/opentelemetry-rust — OpenTelemetry integration layer for tracing; bridges tracing spans to distributed tracing backends (Jaeger, Datadog, etc.)
  • jaegertracing/jaeger — Popular distributed tracing backend that consumes OpenTelemetry-exported tracing data from this framework in production systems
  • log-rs/log — Legacy Rust logging facade; tracing-log in this workspace converts log crate calls to tracing events for unified observability

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for tracing-appender file rotation

The tracing-appender crate handles critical file I/O operations for log rotation, but there are limited integration tests in the examples/. The appender-multifile.rs example shows usage but there's no dedicated test suite validating edge cases like concurrent writes, file descriptor limits, and rotation timing. This would prevent regressions in a foundational component.

  • [ ] Create tracing-appender/tests/integration/ directory
  • [ ] Add tests for file rotation boundaries, concurrent appending, and cleanup
  • [ ] Test platform-specific behavior (Windows vs Unix) for file locking during rotation
  • [ ] Reference existing examples/examples/appender-multifile.rs patterns in tests

Add CI workflow for MSRV (Minimum Supported Rust Version) validation

The repo has CI.yml, audit.yml, and release.yml workflows, but no dedicated MSRV check. With Cargo.toml referencing workspace resolver 2 and cfg checks for Rust 1.74+, there's no automated verification that the codebase actually compiles on its declared MSRV. New contributors may break MSRV compatibility unknowingly.

  • [ ] Create .github/workflows/msrv.yml workflow file
  • [ ] Use actions-rs/toolchain to test against declared MSRV (likely 1.63+)
  • [ ] Test all workspace members (tracing-core, tracing-subscriber, etc.) with --all-features
  • [ ] Reference clippy.toml and .cargo/audit.toml for linting consistency

Add missing documentation examples for tracing-test procedural macros

The examples/examples/ directory has rich examples for fmt, json, tower, and filters, but no dedicated example showing tracing-test's #[instrument] macro testing capabilities or its assertion utilities. This module is often used by library authors but lacks practical getting-started documentation.

  • [ ] Create examples/examples/tracing-test-example.rs demonstrating #[tokio::test] with traced spans
  • [ ] Show usage of collecting and asserting on traced events/spans
  • [ ] Add an example in examples/README.md linking to the new test example
  • [ ] Include inline comments showing how to test instrumented async functions

🌿Good first issues

  • Add missing documentation examples to tracing-appender/src/lib.rs (file appender patterns are under-documented compared to other crates); add a new example examples/examples/appender-rollup.rs showing time-based log rotation.
  • Expand tracing-journald integration with new structured field formatters—journal metadata fields beyond basic level/target are incomplete; add tests in tracing-journald/src/tests to verify field serialization matches systemd journal schema.
  • Create a quickstart guide in docs/ or CONTRIBUTING.md with runnable copy-paste code for the top 3 subscriber patterns (fmt, json, with filters); examples/ exist but discoverable narrative docs do not.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • f40ccda — tracing: add Instrumented::span_and_inner_pin_mut (#3475) (sepointon)
  • 53e1490 — chore: prepare tracing-appender 0.2.5 (#3522) (hds)
  • 4fb9ca3 — examples: add per-layer filtering example (#3488) (Sim-hu)
  • df05516 — docs: improve assert message to mention a possible cause of hitting cloning a span after it is closed (#3512) (weiznich)
  • 72cf52a — docs: recommend configuring await-holding-invalid-types lint (#3463) (WaterWhisperer)
  • 9545be1 — attributes: silence clippy lints for #[instrument] on async functions for crates that warn on implicit_return (#3485) (mjbshaw)
  • 3160dc1 — subscriber: skip RwLock in EnvFilter span callbacks when no dynamic directives (#3487) (kv-cache)
  • 3af2e54 — appender: fix parsing of date from filename when no time is incuded (#3471) (yhibo)
  • 412986f — appender: fix RollingFileAppender broken links in docs (#3445) (lvkv)
  • bdccf4d — appender: add latest symlink builder option (#3447) (lvkv)

🔒Security observations

The tokio-rs/tracing repository demonstrates a strong security posture with established security policies, audit configuration, and a well-structured Rust project. No critical or high-severity vulnerabilities were identified in the provided file structure and configuration. The project follows Tokio's security policy with a documented reporting mechanism via security@tokio.rs. Recommendations focus on ensuring audit enforcement is strict, maintaining dependency management best practices, and addressing identified flaky tests. The multi-crate workspace design increases complexity but appears to be managed carefully with workspace-level linting configuration.

  • Low · Audit Configuration Present — .cargo/audit.toml, .github/workflows/audit.yml. The repository contains a .cargo/audit.toml configuration file and audit.yml workflow, indicating the project performs dependency auditing. While this is a security best practice, the absence of visible audit results or enforcement in CI/CD could mean vulnerabilities might not be caught before release. Fix: Ensure audit.yml workflow is configured to fail on vulnerabilities found, and that audit results are reviewed before each release.
  • Low · Multiple Workspace Members — Cargo.toml (workspace members). The workspace contains 15 different crates including specialized ones like tracing-appender, tracing-journald, and tracing-flame. Each additional crate increases the dependency attack surface. No lockfile path is visible in the provided structure. Fix: Maintain a Cargo.lock file in version control, regularly audit all workspace dependencies, and keep dependencies up-to-date. Consider reducing unnecessary dependencies where possible.
  • Low · No Visible Dependency Pinning Strategy — Cargo.toml. While the workspace uses resolver = '2', there is no evidence of pinned dependency versions in the provided Cargo.toml content, which could lead to supply chain risks from new versions of dependencies. Fix: Review and document the dependency versioning strategy. Consider pinning critical dependencies or using a MSRV (Minimum Supported Rust Version) policy.
  • Low · Flaky Tests Configuration — Cargo.toml (workspace.lints.rust.unexpected_cfgs). The workspace defines a 'flaky_tests' cfg flag in workspace lints, suggesting the project has known flaky tests. Flaky tests can mask real security issues in the test suite. Fix: Address root causes of flaky tests rather than allowing them via cfg gates. Implement stricter CI/CD testing requirements to catch intermittent failures.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · tokio-rs/tracing — RepoPilot