├── .cargo └── audit.toml ├── .config └── nextest.toml ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── labeler.yml └── workflows │ ├── CI.yml │ ├── audit.yml │ └── release.yml ├── .gitignore ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE ├── README.md ├── SECURITY.md ├── assets ├── logo-type.png ├── logo.svg └── splash.svg ├── bin └── publish ├── clippy.toml ├── examples ├── Cargo.toml ├── README.md └── examples │ ├── all-levels.rs │ ├── appender-multifile.rs │ ├── async-fn.rs │ ├── attrs-args.rs │ ├── attrs-basic.rs │ ├── attrs-literal-field-names.rs │ ├── counters.rs │ ├── custom-error.rs │ ├── echo.rs │ ├── env-filter-explorer.rs │ ├── fmt-compact.rs │ ├── fmt-custom-event.rs │ ├── fmt-custom-field.rs │ ├── fmt-json.rs │ ├── fmt-multiple-writers.rs │ ├── fmt-pretty.rs │ ├── fmt-source-locations.rs │ ├── fmt-stderr.rs │ ├── fmt.rs │ ├── fmt │ └── yak_shave.rs │ ├── futures-proxy-server.rs │ ├── hyper-echo.rs │ ├── inferno-flame.rs │ ├── instrumented-error.rs │ ├── journald.rs │ ├── log.rs │ ├── panic_hook.rs │ ├── serde-yak-shave.rs │ ├── sloggish │ ├── main.rs │ └── sloggish_subscriber.rs │ ├── spawny-thing.rs │ ├── subscriber-filter.rs │ ├── thread-info.rs │ ├── toggle-layers.rs │ ├── tokio-spawny-thing.rs │ ├── tokio_panic_hook.rs │ ├── tower-client.rs │ ├── tower-load.rs │ ├── tower-server.rs │ ├── valuable.rs │ ├── valuable_instrument.rs │ └── valuable_json.rs ├── netlify.toml ├── tracing-appender ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── benches │ └── bench.rs └── src │ ├── lib.rs │ ├── non_blocking.rs │ ├── rolling.rs │ ├── rolling │ └── builder.rs │ ├── sync.rs │ └── worker.rs ├── tracing-attributes ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── src │ ├── attr.rs │ ├── expand.rs │ └── lib.rs └── tests │ ├── async_fn.rs │ ├── dead_code.rs │ ├── destructuring.rs │ ├── err.rs │ ├── fields.rs │ ├── follows_from.rs │ ├── instrument.rs │ ├── levels.rs │ ├── names.rs │ ├── parents.rs │ ├── ret.rs │ ├── targets.rs │ ├── ui.rs │ └── ui │ ├── async_instrument.rs │ ├── async_instrument.stderr │ ├── const_instrument.rs │ └── const_instrument.stderr ├── tracing-core ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── src │ ├── callsite.rs │ ├── dispatcher.rs │ ├── event.rs │ ├── field.rs │ ├── lazy.rs │ ├── lib.rs │ ├── metadata.rs │ ├── parent.rs │ ├── span.rs │ ├── spin │ │ ├── LICENSE │ │ ├── mod.rs │ │ ├── mutex.rs │ │ └── once.rs │ ├── stdlib.rs │ └── subscriber.rs └── tests │ ├── common │ └── mod.rs │ ├── dispatch.rs │ ├── global_dispatch.rs │ ├── local_dispatch_before_init.rs │ ├── macros.rs │ └── missed_register_callsite.rs ├── tracing-error ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md └── src │ ├── backtrace.rs │ ├── error.rs │ ├── layer.rs │ └── lib.rs ├── tracing-flame ├── Cargo.toml ├── LICENSE ├── README.md ├── src │ ├── error.rs │ └── lib.rs └── tests │ ├── collapsed.rs │ └── concurrent.rs ├── tracing-futures ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── src │ ├── executor │ │ ├── futures_01.rs │ │ ├── futures_03.rs │ │ └── mod.rs │ ├── lib.rs │ └── stdlib.rs └── tests │ └── std_future.rs ├── tracing-journald ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── src │ ├── lib.rs │ ├── memfd.rs │ └── socket.rs └── tests │ └── journal.rs ├── tracing-log ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── benches │ └── logging.rs ├── src │ ├── interest_cache.rs │ ├── lib.rs │ └── log_tracer.rs └── tests │ ├── log_tracer.rs │ └── reexport_log_crate.rs ├── tracing-macros ├── Cargo.toml ├── LICENSE ├── examples │ └── factorial.rs └── src │ └── lib.rs ├── tracing-mock ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── src │ ├── ancestry.rs │ ├── event.rs │ ├── expect.rs │ ├── field.rs │ ├── layer.rs │ ├── lib.rs │ ├── metadata.rs │ ├── span.rs │ └── subscriber.rs └── tests │ ├── event_ancestry.rs │ └── span_ancestry.rs ├── tracing-serde ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md └── src │ ├── fields.rs │ └── lib.rs ├── tracing-subscriber ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── benches │ ├── enter.rs │ ├── filter.rs │ ├── filter_log.rs │ ├── fmt.rs │ └── support │ │ └── mod.rs ├── src │ ├── field │ │ ├── debug.rs │ │ ├── delimited.rs │ │ ├── display.rs │ │ └── mod.rs │ ├── filter │ │ ├── directive.rs │ │ ├── env │ │ │ ├── builder.rs │ │ │ ├── directive.rs │ │ │ ├── field.rs │ │ │ └── mod.rs │ │ ├── filter_fn.rs │ │ ├── layer_filters │ │ │ ├── combinator.rs │ │ │ └── mod.rs │ │ ├── level.rs │ │ ├── mod.rs │ │ └── targets.rs │ ├── fmt │ │ ├── fmt_layer.rs │ │ ├── format │ │ │ ├── json.rs │ │ │ ├── mod.rs │ │ │ └── pretty.rs │ │ ├── mod.rs │ │ ├── time │ │ │ ├── chrono_crate.rs │ │ │ ├── datetime.rs │ │ │ ├── mod.rs │ │ │ └── time_crate.rs │ │ └── writer.rs │ ├── layer │ │ ├── context.rs │ │ ├── layered.rs │ │ ├── mod.rs │ │ └── tests.rs │ ├── lib.rs │ ├── macros.rs │ ├── prelude.rs │ ├── registry │ │ ├── extensions.rs │ │ ├── mod.rs │ │ ├── sharded.rs │ │ └── stack.rs │ ├── reload.rs │ ├── sync.rs │ └── util.rs └── tests │ ├── cached_layer_filters_dont_break_other_layers.rs │ ├── duplicate_spans.rs │ ├── env_filter │ ├── main.rs │ └── per_layer.rs │ ├── event_enabling.rs │ ├── field_filter.rs │ ├── filter_log.rs │ ├── fmt_max_level_hint.rs │ ├── hinted_layer_filters_dont_break_other_layers.rs │ ├── layer_filter_interests_are_cached.rs │ ├── layer_filters │ ├── boxed.rs │ ├── combinators.rs │ ├── downcast_raw.rs │ ├── filter_scopes.rs │ ├── main.rs │ ├── option.rs │ ├── per_event.rs │ ├── targets.rs │ ├── trees.rs │ └── vec.rs │ ├── multiple_layer_filter_interests_cached.rs │ ├── option.rs │ ├── option_filter_interest_caching.rs │ ├── registry_max_level_hint.rs │ ├── registry_with_subscriber.rs │ ├── reload.rs │ ├── reload_max_log_level.rs │ ├── same_len_filters.rs │ ├── unhinted_layer_filters_dont_break_other_layers.rs │ ├── utils.rs │ ├── vec.rs │ └── vec_subscriber_filter_interests_cached.rs ├── tracing-test ├── Cargo.toml ├── LICENSE ├── README.md └── src │ └── lib.rs ├── tracing-tower ├── Cargo.toml ├── LICENSE └── src │ ├── http.rs │ ├── lib.rs │ ├── request_span.rs │ └── service_span.rs └── tracing ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── benches ├── baseline.rs ├── dispatch_get_clone.rs ├── dispatch_get_ref.rs ├── empty_span.rs ├── enter_span.rs ├── event.rs ├── shared.rs ├── span_fields.rs ├── span_no_fields.rs └── span_repeated.rs ├── src ├── dispatcher.rs ├── field.rs ├── instrument.rs ├── level_filters.rs ├── lib.rs ├── macros.rs ├── span.rs ├── stdlib.rs └── subscriber.rs ├── test-log-support ├── Cargo.toml ├── src │ └── lib.rs └── tests │ ├── log_move_arg.rs │ ├── log_no_trace.rs │ ├── log_with_trace.rs │ ├── span_activity_filtered_separately.rs │ ├── span_lifecycle_can_be_enabled.rs │ ├── span_lifecycle_defaults_off.rs │ └── span_lifecycle_is_trace.rs ├── test_static_max_level_features ├── Cargo.toml └── tests │ └── test.rs └── tests ├── enabled.rs ├── event.rs ├── filter_caching_is_lexically_scoped.rs ├── filters_are_not_reevaluated_for_the_same_span.rs ├── filters_are_reevaluated_for_different_call_sites.rs ├── filters_dont_leak.rs ├── future_send.rs ├── instrument.rs ├── macro_imports.rs ├── macros.rs ├── macros_incompatible_concat.rs ├── max_level_hint.rs ├── missed_register_callsite.rs ├── multiple_max_level_hints.rs ├── no_subscriber.rs ├── register_callsite_deadlock.rs ├── scoped_clobbers_default.rs ├── span.rs └── subscriber.rs /.cargo/audit.toml: -------------------------------------------------------------------------------- 1 | [advisories] 2 | ignore = [ 3 | # Unmaintained advisory for the `net2` crate. 4 | # 5 | # We ignore this, because `net2` is a transitive dependency of older 6 | # versions of `mio`, which we depend on via `tokio` 0.1. `tokio` 0.1 won't 7 | # be updated, so as long as `tracing-futures` supports tokio 0.1, we can't 8 | # really get rid of the `net2` dependency. 9 | # 10 | # So, just ignore the warning. It only effects users who are using 11 | # compatibility features for *other* unmaintained libraries, anyway. 12 | # 13 | # TODO: when `tracing-futures` drops support for `tokio` 0.1, we can remove 14 | # the `ignore` for this warning, as we will no longer pull `net2`. 15 | "RUSTSEC-2020-0016" 16 | ] -------------------------------------------------------------------------------- /.config/nextest.toml: -------------------------------------------------------------------------------- 1 | # recommended nextest profile for CI jobs (from 2 | # https://nexte.st/book/configuration.html#profiles) 3 | [profile.ci] 4 | # Print out output for failing tests as soon as they fail, and also at the end 5 | # of the run (for easy scrollability). 6 | failure-output = "immediate-final" 7 | # Do not cancel the test run on the first failure. 8 | fail-fast = false 9 | 10 | # TODO(eliza): uncomment this when we can get nicer JUnit output from nextest... 11 | # [profile.ci.junit] 12 | # path = "junit.xml" -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Eliza should review everything unassigned. 2 | * @hawkw @tokio-rs/tracing 3 | 4 | # tracing-error and tracing-flame were contributed by Jane. 5 | /tracing-error/ @yaahc @tokio-rs/tracing 6 | /tracing-flame/ @yaahc @tokio-rs/tracing 7 | 8 | # David contributed the Registry implementation. 9 | /tracing-subscriber/registry @davidbarsky @hawkw @tokio-rs/tracing 10 | 11 | # Zeki contributed the TracingAppender implementation 12 | /tracing-appender/ @zekisherif @tokio-rs/tracing 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug Report 3 | about: If something isn't working as expected 🤔. 4 | 5 | --- 6 | 7 | ## Bug Report 8 | 13 | 14 | ### Version 15 | 16 | 27 | 28 | ### Platform 29 | 30 | 33 | 34 | ### Crates 35 | 36 | 40 | 41 | ### Description 42 | 43 | 59 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💡 Feature Request 3 | about: I have a suggestion (and may want to implement it 🙂)! 4 | 5 | --- 6 | 7 | ## Feature Request 8 | 9 | ### Crates 10 | 11 | 15 | 16 | ### Motivation 17 | 18 | 21 | 22 | ### Proposal 23 | 24 | 28 | 29 | ### Alternatives 30 | 31 | 36 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | ## Motivation 11 | 12 | 17 | 18 | ## Solution 19 | 20 | 24 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | crate/tracing: tracing/** 2 | crate/core: tracing-core/** 3 | crate/proc-macros: 4 | - tracing-attributes/** 5 | - tracing-macros/** 6 | crate/futures: tracing-futures/** 7 | crate/log: tracing-log/** 8 | crate/subscriber: tracing-subscriber/** 9 | kind/docs: README.md 10 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: Security audit 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | env: 8 | # Disable incremental compilation. 9 | # 10 | # Incremental compilation is useful as part of an edit-build-test-edit cycle, 11 | # as it lets the compiler avoid recompiling code that hasn't changed. However, 12 | # on CI, we're not making small edits; we're almost always building the entire 13 | # project from scratch. Thus, incremental compilation on CI actually 14 | # introduces *additional* overhead to support making future builds 15 | # faster...but no future builds will ever occur in any given CI environment. 16 | # 17 | # See https://matklad.github.io/2021/09/04/fast-rust-builds.html#ci-workflow 18 | # for details. 19 | CARGO_INCREMENTAL: 0 20 | # Allow more retries for network requests in cargo (downloading crates) and 21 | # rustup (installing toolchains). This should help to reduce flaky CI failures 22 | # from transient network timeouts or other issues. 23 | CARGO_NET_RETRY: 10 24 | RUSTUP_MAX_RETRIES: 10 25 | # Don't emit giant backtraces in the CI logs. 26 | RUST_BACKTRACE: short 27 | 28 | jobs: 29 | security_audit: 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v4 33 | - uses: actions-rs/audit-check@v1 34 | with: 35 | token: ${{ secrets.GITHUB_TOKEN }} 36 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - tracing-[0-9]+.* 7 | - tracing-[a-z]+-[0-9]+.* 8 | 9 | jobs: 10 | create-release: 11 | name: Create GitHub release 12 | # only publish from the origin repository 13 | if: github.repository_owner == 'tokio-rs' 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: taiki-e/create-gh-release-action@v1 18 | with: 19 | prefix: tracing(-[a-z]+)? 20 | changelog: "$prefix/CHANGELOG.md" 21 | title: "$prefix $version" 22 | branch: main 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/rust,macos,visualstudiocode 3 | 4 | ### macOS ### 5 | # General 6 | .DS_Store 7 | .AppleDouble 8 | .LSOverride 9 | 10 | # Icon must end with two \r 11 | Icon 12 | 13 | # Thumbnails 14 | ._* 15 | 16 | # Files that might appear in the root of a volume 17 | .DocumentRevisions-V100 18 | .fseventsd 19 | .Spotlight-V100 20 | .TemporaryItems 21 | .Trashes 22 | .VolumeIcon.icns 23 | .com.apple.timemachine.donotpresent 24 | 25 | # Directories potentially created on remote AFP share 26 | .AppleDB 27 | .AppleDesktop 28 | Network Trash Folder 29 | Temporary Items 30 | .apdisk 31 | 32 | ### Rust ### 33 | # Generated by Cargo 34 | # will have compiled files and executables 35 | target/ 36 | 37 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 38 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 39 | Cargo.lock 40 | 41 | # These are backup files generated by rustfmt 42 | **/*.rs.bk 43 | 44 | ### VisualStudioCode ### 45 | .vscode/* 46 | !.vscode/settings.json 47 | !.vscode/tasks.json 48 | !.vscode/launch.json 49 | !.vscode/extensions.json 50 | 51 | 52 | # End of https://www.gitignore.io/api/rust,macos,visualstudiocode 53 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "tracing", 5 | "tracing-core", 6 | "tracing-attributes", 7 | "tracing-error", 8 | "tracing-flame", 9 | "tracing-futures", 10 | "tracing-tower", 11 | "tracing-log", 12 | "tracing-macros", 13 | "tracing-mock", 14 | "tracing-subscriber", 15 | "tracing-serde", 16 | "tracing-test", 17 | "tracing-appender", 18 | "tracing-journald", 19 | "examples" 20 | ] 21 | 22 | # This will be ignored with Rust older than 1.74, but for now that's okay; 23 | # we're only using it to fix check-cfg issues that first appeared in Rust 1.80. 24 | [workspace.lints.rust] 25 | unexpected_cfgs = { level = "warn", check-cfg = ["cfg(flaky_tests)", "cfg(tracing_unstable)", "cfg(unsound_local_offset)"] } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | Tracing is part of the Tokio project and uses the same security policy as [Tokio][tokio-security]. 4 | 5 | ## Report a security issue 6 | 7 | The process for reporting an issue is the same as for [Tokio][tokio-security]. This includes private reporting via security@tokio.rs. 8 | 9 | [tokio-security]: https://github.com/tokio-rs/tokio/security/policy 10 | -------------------------------------------------------------------------------- /assets/logo-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tokio-rs/tracing/e4df76127538aa8370d7dee32a6f84bbec6bbf10/assets/logo-type.png -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | disallowed-names = [] 2 | cognitive-complexity-threshold = 100 3 | too-many-arguments-threshold = 8 4 | type-complexity-threshold = 375 5 | -------------------------------------------------------------------------------- /examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-examples" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2018" 6 | rust-version = "1.64.0" 7 | 8 | [features] 9 | default = [] 10 | 11 | [dev-dependencies] 12 | 13 | # tracing crates 14 | tracing = { path = "../tracing", version = "0.1.35" } 15 | tracing-core = { path = "../tracing-core", version = "0.1.28" } 16 | tracing-error = { path = "../tracing-error" } 17 | tracing-flame = { path = "../tracing-flame" } 18 | tracing-tower = { version = "0.1.0", path = "../tracing-tower" } 19 | tracing-subscriber = { path = "../tracing-subscriber", version = "0.3.0", features = ["json", "env-filter"] } 20 | tracing-futures = { version = "0.2.1", path = "../tracing-futures", features = ["futures-01"] } 21 | tracing-attributes = { path = "../tracing-attributes", version = "0.1.22" } 22 | tracing-serde = { path = "../tracing-serde" } 23 | tracing-appender = { path = "../tracing-appender", version = "0.2.0" } 24 | tracing-journald = { path = "../tracing-journald" } 25 | 26 | # serde example 27 | serde_json = "1.0.82" 28 | 29 | futures = "0.3.21" 30 | tokio = { version = "1.20.1", features = ["full"] } 31 | 32 | # tower examples 33 | tower = { version = "0.4.13", features = ["full"] } 34 | http = "0.2.8" 35 | hyper = { version = "0.14.20", features = ["full"] } 36 | rand = "0.7.3" 37 | bytes = "1" 38 | argh = "0.1.8" 39 | 40 | # sloggish example 41 | nu-ansi-term = "0.50.0" 42 | humantime = "2.1.0" 43 | log = "0.4.17" 44 | 45 | # inferno example 46 | inferno = "0.11.6" 47 | tempfile = "3" 48 | 49 | # fmt examples 50 | snafu = "0.6.10" 51 | thiserror = "2" 52 | 53 | # env-filter-explorer example 54 | ansi-to-tui = "7.0.0" 55 | ratatui = "0.29.0" 56 | crossterm = "0.28.1" 57 | tui-textarea = "0.7.0" 58 | 59 | # valuable examples 60 | valuable = { version = "0.1.0", features = ["derive"] } 61 | 62 | [target.'cfg(tracing_unstable)'.dependencies] 63 | tracing-core = { path = "../tracing-core", version = "0.1.28", features = ["valuable"]} 64 | tracing-subscriber = { path = "../tracing-subscriber", version = "0.3.0", features = ["json", "env-filter", "valuable"]} 65 | 66 | [lints] 67 | workspace = true 68 | -------------------------------------------------------------------------------- /examples/examples/all-levels.rs: -------------------------------------------------------------------------------- 1 | use tracing::Level; 2 | 3 | fn main() { 4 | tracing_subscriber::fmt() 5 | // all spans/events with a level higher than TRACE (e.g, info, warn, etc.) 6 | // will be written to stdout. 7 | .with_max_level(Level::TRACE) 8 | // sets this to be the default, global subscriber for this application. 9 | .init(); 10 | 11 | tracing::error!("SOMETHING IS SERIOUSLY WRONG!!!"); 12 | tracing::warn!("important informational messages; might indicate an error"); 13 | tracing::info!("general informational messages relevant to users"); 14 | tracing::debug!("diagnostics used for internal debugging of a library or application"); 15 | tracing::trace!("very verbose diagnostic events"); 16 | } 17 | -------------------------------------------------------------------------------- /examples/examples/appender-multifile.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates the use of multiple files with 2 | //! `tracing-appender`'s `RollingFileAppender` 3 | //! 4 | use tracing_appender::rolling; 5 | use tracing_subscriber::fmt::writer::MakeWriterExt; 6 | 7 | #[path = "fmt/yak_shave.rs"] 8 | mod yak_shave; 9 | 10 | fn main() { 11 | // Log all `tracing` events to files prefixed with `debug`. Since these 12 | // files will be written to very frequently, roll the log file every minute. 13 | let debug_file = rolling::minutely("./logs", "debug"); 14 | // Log warnings and errors to a separate file. Since we expect these events 15 | // to occur less frequently, roll that file on a daily basis instead. 16 | let warn_file = rolling::daily("./logs", "warnings").with_max_level(tracing::Level::WARN); 17 | let all_files = debug_file.and(warn_file); 18 | 19 | tracing_subscriber::fmt() 20 | .with_writer(all_files) 21 | .with_ansi(false) 22 | .with_max_level(tracing::Level::TRACE) 23 | .init(); 24 | 25 | yak_shave::shave_all(6); 26 | tracing::info!("sleeping for a minute..."); 27 | 28 | std::thread::sleep(std::time::Duration::from_secs(60)); 29 | 30 | tracing::info!("okay, time to shave some more yaks!"); 31 | yak_shave::shave_all(10); 32 | } 33 | -------------------------------------------------------------------------------- /examples/examples/async-fn.rs: -------------------------------------------------------------------------------- 1 | //! Demonstrates using the `trace` attribute macro to instrument `async` 2 | //! functions. 3 | //! 4 | //! This is based on the [`hello_world`] example from `tokio`. and implements a 5 | //! simple client that opens a TCP stream, writes "hello world\n", and closes 6 | //! the connection. 7 | //! 8 | //! You can test this out by running: 9 | //! 10 | //! ncat -l 6142 11 | //! 12 | //! And then in another terminal run: 13 | //! 14 | //! cargo +nightly run --example async_fn 15 | //! 16 | //! [`hello_world`]: https://github.com/tokio-rs/tokio/blob/132e9f1da5965530b63554d7a1c59824c3de4e30/tokio/examples/hello_world.rs 17 | #![deny(rust_2018_idioms)] 18 | 19 | use tokio::io::AsyncWriteExt; 20 | use tokio::net::TcpStream; 21 | 22 | use tracing::info; 23 | use tracing_attributes::instrument; 24 | 25 | use std::{error::Error, io, net::SocketAddr}; 26 | 27 | #[instrument] 28 | async fn connect(addr: &SocketAddr) -> io::Result { 29 | let stream = TcpStream::connect(&addr).await; 30 | tracing::info!("created stream"); 31 | stream 32 | } 33 | 34 | #[instrument] 35 | async fn write(stream: &mut TcpStream) -> io::Result { 36 | let result = stream.write(b"hello world\n").await; 37 | info!("wrote to stream; success={:?}", result.is_ok()); 38 | result 39 | } 40 | 41 | #[tokio::main] 42 | pub async fn main() -> Result<(), Box> { 43 | let addr = "127.0.0.1:6142".parse()?; 44 | 45 | tracing_subscriber::fmt() 46 | .with_env_filter("async_fn=trace") 47 | .try_init()?; 48 | 49 | // Open a TCP stream to the socket address. 50 | // 51 | // Note that this is the Tokio TcpStream, which is fully async. 52 | let mut stream = connect(&addr).await?; 53 | 54 | write(&mut stream).await?; 55 | 56 | Ok(()) 57 | } 58 | -------------------------------------------------------------------------------- /examples/examples/attrs-args.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | 3 | use tracing::{debug, info}; 4 | use tracing_attributes::instrument; 5 | 6 | #[instrument] 7 | fn nth_fibonacci(n: u64) -> u64 { 8 | if n == 0 || n == 1 { 9 | debug!("Base case"); 10 | 1 11 | } else { 12 | debug!("Recursing"); 13 | nth_fibonacci(n - 1) + nth_fibonacci(n - 2) 14 | } 15 | } 16 | 17 | #[instrument] 18 | fn fibonacci_seq(to: u64) -> Vec { 19 | let mut sequence = vec![]; 20 | 21 | for n in 0..=to { 22 | debug!("Pushing {n} fibonacci", n = n); 23 | sequence.push(nth_fibonacci(n)); 24 | } 25 | 26 | sequence 27 | } 28 | 29 | fn main() { 30 | let subscriber = tracing_subscriber::fmt() 31 | .with_env_filter("attrs_args=trace") 32 | .finish(); 33 | 34 | tracing::subscriber::with_default(subscriber, || { 35 | let n = 5; 36 | let sequence = fibonacci_seq(n); 37 | info!("The first {} fibonacci numbers are {:?}", n, sequence); 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /examples/examples/attrs-basic.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | 3 | use tracing::{debug, info, span, Level}; 4 | use tracing_attributes::instrument; 5 | 6 | #[instrument] 7 | #[inline] 8 | fn suggest_band() -> String { 9 | debug!("Suggesting a band."); 10 | String::from("Wild Pink") 11 | } 12 | 13 | fn main() { 14 | let subscriber = tracing_subscriber::fmt() 15 | .with_env_filter("attrs_basic=trace") 16 | .finish(); 17 | tracing::subscriber::with_default(subscriber, || { 18 | let num_recs = 1; 19 | 20 | let span = span!(Level::TRACE, "get_band_rec", ?num_recs); 21 | let _enter = span.enter(); 22 | let band = suggest_band(); 23 | info!(message = "Got a recommendation!", %band); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /examples/examples/attrs-literal-field-names.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | 3 | use tracing::{debug, span, Level}; 4 | use tracing_attributes::instrument; 5 | 6 | #[instrument] 7 | #[inline] 8 | fn suggest_band() -> String { 9 | debug!("Suggesting a band."); 10 | String::from("Wild Pink") 11 | } 12 | 13 | fn main() { 14 | let subscriber = tracing_subscriber::fmt() 15 | .with_env_filter("attrs_literal_field_names=trace") 16 | .finish(); 17 | tracing::subscriber::with_default(subscriber, || { 18 | let span = span!(Level::TRACE, "get_band_rec", "guid:x-request-id" = "abcdef"); 19 | let _enter = span.enter(); 20 | suggest_band(); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /examples/examples/custom-error.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates using the `tracing-error` crate's `SpanTrace` type 2 | //! to attach a trace context to a custom error type. 3 | #![deny(rust_2018_idioms)] 4 | use std::error::Error; 5 | use std::fmt; 6 | use tracing_error::{ErrorLayer, SpanTrace}; 7 | use tracing_subscriber::prelude::*; 8 | #[derive(Debug)] 9 | struct FooError { 10 | message: &'static str, 11 | // This struct captures the current `tracing` span context when it is 12 | // constructed. Later, when we display this error, we will format this 13 | // captured span trace. 14 | context: SpanTrace, 15 | } 16 | 17 | impl FooError { 18 | fn new(message: &'static str) -> Self { 19 | Self { 20 | message, 21 | context: SpanTrace::capture(), 22 | } 23 | } 24 | } 25 | 26 | impl Error for FooError {} 27 | 28 | impl fmt::Display for FooError { 29 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 30 | f.pad(self.message)?; 31 | write!(f, "\n\nspan backtrace:\n{}", self.context)?; 32 | write!(f, "\n\ndebug span backtrace: {:?}", self.context)?; 33 | write!(f, "\n\nalt debug span backtrace: {:#?}", self.context)?; 34 | Ok(()) 35 | } 36 | } 37 | 38 | #[tracing::instrument] 39 | fn do_something(foo: &str) -> Result<&'static str, impl Error + Send + Sync + 'static> { 40 | do_another_thing(42, false) 41 | } 42 | 43 | #[tracing::instrument] 44 | fn do_another_thing( 45 | answer: usize, 46 | will_succeed: bool, 47 | ) -> Result<&'static str, impl Error + Send + Sync + 'static> { 48 | Err(FooError::new("something broke, lol")) 49 | } 50 | 51 | #[tracing::instrument] 52 | fn main() { 53 | tracing_subscriber::registry() 54 | .with(tracing_subscriber::fmt::layer()) 55 | // The `ErrorLayer` subscriber layer enables the use of `SpanTrace`. 56 | .with(ErrorLayer::default()) 57 | .init(); 58 | match do_something("hello world") { 59 | Ok(result) => println!("did something successfully: {}", result), 60 | Err(e) => eprintln!("error: {}", e), 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /examples/examples/fmt-compact.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | #[path = "fmt/yak_shave.rs"] 3 | mod yak_shave; 4 | 5 | fn main() { 6 | tracing_subscriber::fmt() 7 | .compact() 8 | // enable everything 9 | .with_max_level(tracing::Level::TRACE) 10 | // sets this to be the default, global subscriber for this application. 11 | .init(); 12 | 13 | let number_of_yaks = 3; 14 | // this creates a new event, outside of any spans. 15 | tracing::info!(number_of_yaks, "preparing to shave yaks"); 16 | 17 | let number_shaved = yak_shave::shave_all(number_of_yaks); 18 | tracing::info!( 19 | all_yaks_shaved = number_shaved == number_of_yaks, 20 | "yak shaving completed" 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /examples/examples/fmt-custom-event.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | #[path = "fmt/yak_shave.rs"] 3 | mod yak_shave; 4 | 5 | fn main() { 6 | use tracing_subscriber::fmt; 7 | 8 | // Configure a custom event formatter 9 | let format = fmt::format() 10 | .compact() // use an abbreviated format for logging spans 11 | .with_level(false) // don't include levels in formatted output 12 | .with_target(false); // don't include targets 13 | 14 | // Create a `fmt` subscriber that uses our custom event format, and set it 15 | // as the default. 16 | tracing_subscriber::fmt().event_format(format).init(); 17 | 18 | // Shave some yaks! 19 | let number_of_yaks = 3; 20 | // this creates a new event, outside of any spans. 21 | tracing::info!(number_of_yaks, "preparing to shave yaks"); 22 | 23 | let number_shaved = yak_shave::shave_all(number_of_yaks); 24 | tracing::info!( 25 | all_yaks_shaved = number_shaved == number_of_yaks, 26 | "yak shaving completed." 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /examples/examples/fmt-custom-field.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates overriding the way `tracing-subscriber`'s 2 | //! `FmtSubscriber` formats fields on spans and events, using a closure. 3 | //! 4 | //! We'll create a custom format that prints key-value pairs separated by 5 | //! colons rather than equals signs, and separates fields with commas. 6 | //! 7 | //! For an event like 8 | //! ```rust 9 | //! tracing::info!(hello = "world", answer = 42); 10 | //! ``` 11 | //! 12 | //! the default formatter will format the fields like this: 13 | //! ```not_rust 14 | //! hello="world" answer=42 15 | //! ``` 16 | //! while our custom formatter will output 17 | //! ```not_rust 18 | //! hello: "world", answer: 42 19 | //! ``` 20 | #![deny(rust_2018_idioms)] 21 | 22 | #[path = "fmt/yak_shave.rs"] 23 | mod yak_shave; 24 | 25 | fn main() { 26 | use tracing_subscriber::{fmt::format, prelude::*}; 27 | 28 | // Format fields using the provided closure. 29 | let format = format::debug_fn(|writer, field, value| { 30 | // We'll format the field name and value separated with a colon. 31 | write!(writer, "{}: {:?}", field, value) 32 | }) 33 | // Separate each field with a comma. 34 | // This method is provided by an extension trait in the 35 | // `tracing-subscriber` prelude. 36 | .delimited(", "); 37 | 38 | // Create a `fmt` subscriber that uses our custom event format, and set it 39 | // as the default. 40 | tracing_subscriber::fmt().fmt_fields(format).init(); 41 | 42 | // Shave some yaks! 43 | let number_of_yaks = 3; 44 | // this creates a new event, outside of any spans. 45 | tracing::info!(number_of_yaks, "preparing to shave yaks"); 46 | 47 | let number_shaved = yak_shave::shave_all(number_of_yaks); 48 | tracing::info!( 49 | all_yaks_shaved = number_shaved == number_of_yaks, 50 | "yak shaving completed." 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /examples/examples/fmt-json.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | #[path = "fmt/yak_shave.rs"] 3 | mod yak_shave; 4 | 5 | fn main() { 6 | tracing_subscriber::fmt() 7 | .json() 8 | .with_max_level(tracing::Level::TRACE) 9 | .with_current_span(false) 10 | .init(); 11 | 12 | let number_of_yaks = 3; 13 | // this creates a new event, outside of any spans. 14 | tracing::info!(number_of_yaks, "preparing to shave yaks"); 15 | 16 | let number_shaved = yak_shave::shave_all(number_of_yaks); 17 | tracing::info!( 18 | all_yaks_shaved = number_shaved == number_of_yaks, 19 | "yak shaving completed" 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /examples/examples/fmt-multiple-writers.rs: -------------------------------------------------------------------------------- 1 | //! An example demonstrating how `fmt::Layer` can write to multiple 2 | //! destinations (in this instance, `stdout` and a file) simultaneously. 3 | 4 | #[path = "fmt/yak_shave.rs"] 5 | mod yak_shave; 6 | 7 | use std::io; 8 | use tracing_subscriber::{fmt, layer::SubscriberExt, EnvFilter}; 9 | 10 | fn main() { 11 | let dir = tempfile::tempdir().expect("Failed to create tempdir"); 12 | 13 | let file_appender = tracing_appender::rolling::hourly(dir, "example.log"); 14 | let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender); 15 | 16 | let subscriber = tracing_subscriber::registry() 17 | .with(EnvFilter::from_default_env().add_directive(tracing::Level::TRACE.into())) 18 | .with(fmt::Layer::new().with_writer(io::stdout)) 19 | .with(fmt::Layer::new().with_writer(non_blocking)); 20 | tracing::subscriber::set_global_default(subscriber).expect("Unable to set a global subscriber"); 21 | 22 | let number_of_yaks = 3; 23 | // this creates a new event, outside of any spans. 24 | tracing::info!(number_of_yaks, "preparing to shave yaks"); 25 | 26 | let number_shaved = yak_shave::shave_all(number_of_yaks); 27 | tracing::info!( 28 | all_yaks_shaved = number_shaved == number_of_yaks, 29 | "yak shaving completed." 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /examples/examples/fmt-pretty.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | #[path = "fmt/yak_shave.rs"] 3 | mod yak_shave; 4 | 5 | fn main() { 6 | tracing_subscriber::fmt() 7 | .pretty() 8 | .with_thread_names(true) 9 | // enable everything 10 | .with_max_level(tracing::Level::TRACE) 11 | // sets this to be the default, global subscriber for this application. 12 | .init(); 13 | 14 | let number_of_yaks = 3; 15 | // this creates a new event, outside of any spans. 16 | tracing::info!(number_of_yaks, "preparing to shave yaks"); 17 | 18 | let number_shaved = yak_shave::shave_all(number_of_yaks); 19 | tracing::info!( 20 | all_yaks_shaved = number_shaved == number_of_yaks, 21 | "yak shaving completed" 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /examples/examples/fmt-source-locations.rs: -------------------------------------------------------------------------------- 1 | //! Demonstrates displaying events' source code locations with the `fmt` 2 | //! subscriber. 3 | #![deny(rust_2018_idioms)] 4 | #[path = "fmt/yak_shave.rs"] 5 | mod yak_shave; 6 | 7 | fn main() { 8 | tracing_subscriber::fmt() 9 | // enable everything 10 | .with_max_level(tracing::Level::TRACE) 11 | // display source code file paths 12 | .with_file(true) 13 | // display source code line numbers 14 | .with_line_number(true) 15 | // disable targets 16 | .with_target(false) 17 | // sets this to be the default, global subscriber for this application. 18 | .init(); 19 | 20 | let number_of_yaks = 3; 21 | // this creates a new event, outside of any spans. 22 | tracing::info!(number_of_yaks, "preparing to shave yaks"); 23 | 24 | let number_shaved = yak_shave::shave_all(number_of_yaks); 25 | tracing::info!( 26 | all_yaks_shaved = number_shaved == number_of_yaks, 27 | "yak shaving completed." 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /examples/examples/fmt-stderr.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | use std::io; 3 | use tracing::error; 4 | 5 | fn main() { 6 | let subscriber = tracing_subscriber::fmt().with_writer(io::stderr).finish(); 7 | 8 | tracing::subscriber::with_default(subscriber, || { 9 | error!("This event will be printed to `stderr`."); 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /examples/examples/fmt.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | #[path = "fmt/yak_shave.rs"] 3 | mod yak_shave; 4 | 5 | fn main() { 6 | tracing_subscriber::fmt() 7 | // enable everything 8 | .with_max_level(tracing::Level::TRACE) 9 | // sets this to be the default, global subscriber for this application. 10 | .init(); 11 | 12 | let number_of_yaks = 3; 13 | // this creates a new event, outside of any spans. 14 | tracing::info!(number_of_yaks, "preparing to shave yaks"); 15 | 16 | let number_shaved = yak_shave::shave_all(number_of_yaks); 17 | tracing::info!( 18 | all_yaks_shaved = number_shaved == number_of_yaks, 19 | "yak shaving completed." 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /examples/examples/inferno-flame.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | env, 3 | fs::File, 4 | io::{BufReader, BufWriter}, 5 | path::{Path, PathBuf}, 6 | thread::sleep, 7 | time::Duration, 8 | }; 9 | use tracing::{span, Level}; 10 | use tracing_flame::FlameLayer; 11 | use tracing_subscriber::{prelude::*, registry::Registry}; 12 | 13 | static PATH: &str = "flame.folded"; 14 | 15 | fn setup_global_subscriber(dir: &Path) -> impl Drop { 16 | let (flame_layer, _guard) = FlameLayer::with_file(dir.join(PATH)).unwrap(); 17 | 18 | let subscriber = Registry::default().with(flame_layer); 19 | 20 | tracing::subscriber::set_global_default(subscriber).unwrap(); 21 | 22 | _guard 23 | } 24 | 25 | fn make_flamegraph(tmpdir: &Path, out: &Path) { 26 | println!("outputting flamegraph to {}", out.display()); 27 | let inf = File::open(tmpdir.join(PATH)).unwrap(); 28 | let reader = BufReader::new(inf); 29 | 30 | let out = File::create(out).unwrap(); 31 | let writer = BufWriter::new(out); 32 | 33 | let mut opts = inferno::flamegraph::Options::default(); 34 | inferno::flamegraph::from_reader(&mut opts, reader, writer).unwrap(); 35 | } 36 | 37 | fn main() { 38 | let out = if let Some(arg) = env::args().nth(1) { 39 | PathBuf::from(arg) 40 | } else { 41 | let mut path = env::current_dir().expect("failed to read current directory"); 42 | path.push("tracing-flame-inferno.svg"); 43 | path 44 | }; 45 | 46 | // setup the flame layer 47 | let tmp_dir = tempfile::Builder::new() 48 | .prefix("flamegraphs") 49 | .tempdir() 50 | .expect("failed to create temporary directory"); 51 | let guard = setup_global_subscriber(tmp_dir.path()); 52 | 53 | // do a bunch of span entering and exiting to simulate a program running 54 | span!(Level::ERROR, "outer").in_scope(|| { 55 | sleep(Duration::from_millis(10)); 56 | span!(Level::ERROR, "Inner").in_scope(|| { 57 | sleep(Duration::from_millis(50)); 58 | span!(Level::ERROR, "Innermost").in_scope(|| { 59 | sleep(Duration::from_millis(50)); 60 | }); 61 | }); 62 | sleep(Duration::from_millis(5)); 63 | }); 64 | sleep(Duration::from_millis(500)); 65 | 66 | // drop the guard to make sure the layer flushes its output then read the 67 | // output to create the flamegraph 68 | drop(guard); 69 | make_flamegraph(tmp_dir.path(), out.as_ref()); 70 | } 71 | -------------------------------------------------------------------------------- /examples/examples/journald.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | use tracing::{error, info}; 3 | use tracing_subscriber::prelude::*; 4 | 5 | #[path = "fmt/yak_shave.rs"] 6 | mod yak_shave; 7 | 8 | fn main() { 9 | let registry = 10 | tracing_subscriber::registry().with(tracing_subscriber::fmt::layer().with_target(false)); 11 | match tracing_journald::layer() { 12 | Ok(layer) => { 13 | registry.with(layer).init(); 14 | } 15 | // journald is typically available on Linux systems, but nowhere else. Portable software 16 | // should handle its absence gracefully. 17 | Err(e) => { 18 | registry.init(); 19 | error!("couldn't connect to journald: {}", e); 20 | } 21 | } 22 | 23 | let number_of_yaks = 3; 24 | // this creates a new event, outside of any spans. 25 | info!(number_of_yaks, "preparing to shave yaks"); 26 | 27 | let number_shaved = yak_shave::shave_all(number_of_yaks); 28 | info!( 29 | all_yaks_shaved = number_shaved == number_of_yaks, 30 | "yak shaving completed." 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /examples/examples/log.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tracing_subscriber::fmt() 3 | .with_max_level(tracing::Level::TRACE) 4 | .init(); 5 | 6 | log::debug!("this is a log line"); 7 | tracing::debug!("this is a tracing line"); 8 | } 9 | -------------------------------------------------------------------------------- /examples/examples/panic_hook.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how `tracing` events can be recorded from within a 2 | //! panic hook, capturing the span context in which the program panicked. 3 | //! 4 | //! A custom panic hook can also be used to record panics that are captured 5 | //! using `catch_unwind`, such as when Tokio catches panics in spawned async 6 | //! tasks. See the `tokio_panic_hook.rs` example for an example of this. 7 | 8 | fn main() { 9 | let subscriber = tracing_subscriber::fmt() 10 | .with_max_level(tracing::Level::TRACE) 11 | .finish(); 12 | 13 | // NOTE: Using `tracing` in a panic hook requires the use of the *global* 14 | // trace dispatcher (`tracing::subscriber::set_global_default`), rather than 15 | // the per-thread scoped dispatcher 16 | // (`tracing::subscriber::with_default`/`set_default`). With the scoped trace 17 | // dispatcher, the subscriber's thread-local context may already have been 18 | // torn down by unwinding by the time the panic handler is reached. 19 | tracing::subscriber::set_global_default(subscriber).unwrap(); 20 | 21 | // Set a panic hook that records the panic as a `tracing` event at the 22 | // `ERROR` verbosity level. 23 | // 24 | // If we are currently in a span when the panic occurred, the logged event 25 | // will include the current span, allowing the context in which the panic 26 | // occurred to be recorded. 27 | std::panic::set_hook(Box::new(|panic| { 28 | // If the panic has a source location, record it as structured fields. 29 | if let Some(location) = panic.location() { 30 | // On nightly Rust, where the `PanicInfo` type also exposes a 31 | // `message()` method returning just the message, we could record 32 | // just the message instead of the entire `fmt::Display` 33 | // implementation, avoiding the duplicated location 34 | tracing::error!( 35 | message = %panic, 36 | panic.file = location.file(), 37 | panic.line = location.line(), 38 | panic.column = location.column(), 39 | ); 40 | } else { 41 | tracing::error!(message = %panic); 42 | } 43 | })); 44 | 45 | for i in 0..10 { 46 | check_number(i); 47 | } 48 | } 49 | 50 | #[tracing::instrument] 51 | fn check_number(x: i32) { 52 | if x % 2 == 0 { 53 | panic!("I don't work with even numbers!"); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/examples/sloggish/main.rs: -------------------------------------------------------------------------------- 1 | //! A simple example demonstrating how one might implement a custom 2 | //! subscriber. 3 | //! 4 | //! This subscriber implements a tree-structured logger similar to 5 | //! the "compact" formatter in [`slog-term`]. The demo mimics the 6 | //! example output in the screenshot in the [`slog` README]. 7 | //! 8 | //! Note that this logger isn't ready for actual production use. 9 | //! Several corners were cut to make the example simple. 10 | //! 11 | //! [`slog-term`]: https://docs.rs/slog-term/2.4.0/slog_term/ 12 | //! [`slog` README]: https://github.com/slog-rs/slog#terminal-output-example 13 | #![deny(rust_2018_idioms)] 14 | 15 | use tracing::{debug, info, span, warn, Level}; 16 | 17 | mod sloggish_subscriber; 18 | use self::sloggish_subscriber::SloggishSubscriber; 19 | 20 | fn main() { 21 | let subscriber = SloggishSubscriber::new(2); 22 | tracing::subscriber::set_global_default(subscriber).unwrap(); 23 | 24 | let app_span = span!(Level::TRACE, "", version = %5.0); 25 | let _e = app_span.enter(); 26 | 27 | let server_span = span!(Level::TRACE, "server", host = "localhost", port = 8080); 28 | let _e2 = server_span.enter(); 29 | info!("starting"); 30 | info!("listening"); 31 | let peer1 = span!(Level::TRACE, "conn", peer_addr = "82.9.9.9", port = 42381); 32 | peer1.in_scope(|| { 33 | debug!("connected"); 34 | debug!(length = 2, "message received"); 35 | }); 36 | let peer2 = span!(Level::TRACE, "conn", peer_addr = "8.8.8.8", port = 18230); 37 | peer2.in_scope(|| { 38 | debug!("connected"); 39 | }); 40 | peer1.in_scope(|| { 41 | warn!(algo = "xor", "weak encryption requested"); 42 | debug!(length = 8, "response sent"); 43 | debug!("disconnected"); 44 | }); 45 | peer2.in_scope(|| { 46 | debug!(length = 5, "message received"); 47 | debug!(length = 8, "response sent"); 48 | debug!("disconnected"); 49 | }); 50 | warn!("internal error"); 51 | info!("exit"); 52 | } 53 | -------------------------------------------------------------------------------- /examples/examples/spawny-thing.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | 3 | /// This is a example showing how information is scoped. 4 | /// 5 | /// You can run this example by running the following command in a terminal 6 | /// 7 | /// ``` 8 | /// cargo run --example spawny_thing 9 | /// ``` 10 | use futures::future::join_all; 11 | use std::error::Error; 12 | use tracing::{debug, info}; 13 | use tracing_attributes::instrument; 14 | 15 | #[instrument] 16 | async fn parent_task(subtasks: usize) { 17 | info!("spawning subtasks..."); 18 | let subtasks = (1..=subtasks) 19 | .map(|number| { 20 | debug!(message = "creating subtask;", number); 21 | subtask(number) 22 | }) 23 | .collect::>(); 24 | 25 | let result = join_all(subtasks).await; 26 | 27 | debug!("all subtasks completed"); 28 | let sum: usize = result.into_iter().sum(); 29 | info!(sum); 30 | } 31 | 32 | #[instrument] 33 | async fn subtask(number: usize) -> usize { 34 | info!("polling subtask..."); 35 | number 36 | } 37 | 38 | #[tokio::main] 39 | async fn main() -> Result<(), Box> { 40 | tracing_subscriber::fmt() 41 | .with_max_level(tracing::Level::DEBUG) 42 | .try_init()?; 43 | parent_task(10).await; 44 | Ok(()) 45 | } 46 | -------------------------------------------------------------------------------- /examples/examples/subscriber-filter.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | #[path = "fmt/yak_shave.rs"] 3 | mod yak_shave; 4 | 5 | fn main() { 6 | use tracing_subscriber::{fmt, EnvFilter}; 7 | 8 | let subscriber = fmt::Subscriber::builder() 9 | .with_env_filter(EnvFilter::from_default_env()) 10 | .finish(); 11 | 12 | tracing::subscriber::with_default(subscriber, || { 13 | let number_of_yaks = 3; 14 | tracing::debug!("preparing to shave {} yaks", number_of_yaks); 15 | 16 | let number_shaved = yak_shave::shave_all(number_of_yaks); 17 | 18 | tracing::debug!( 19 | message = "yak shaving completed.", 20 | all_yaks_shaved = number_shaved == number_of_yaks, 21 | ); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /examples/examples/thread-info.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | /// This is a example showing how thread info can be displayed when 3 | /// formatting events with `tracing_subscriber::fmt`. This is useful 4 | /// as `tracing` spans can be entered by multicple threads concurrently, 5 | /// or move across threads freely. 6 | /// 7 | /// You can run this example by running the following command in a terminal 8 | /// 9 | /// ``` 10 | /// cargo run --example thread-info 11 | /// ``` 12 | /// 13 | /// Example output: 14 | /// 15 | /// ```not_rust 16 | /// Jul 17 00:38:07.177 INFO ThreadId(02) thread_info: i=9 17 | /// Jul 17 00:38:07.177 INFO thread 1 ThreadId(03) thread_info: i=9 18 | /// Jul 17 00:38:07.177 INFO large name thread 2 ThreadId(04) thread_info: i=9 19 | /// ``` 20 | use std::thread; 21 | use std::time::Duration; 22 | use tracing::info; 23 | 24 | fn main() { 25 | tracing_subscriber::fmt() 26 | .with_max_level(tracing::Level::DEBUG) 27 | // enable thread id to be emitted 28 | .with_thread_ids(true) 29 | // enabled thread name to be emitted 30 | .with_thread_names(true) 31 | .init(); 32 | 33 | let do_work = || { 34 | for i in 1..10 { 35 | info!(i); 36 | thread::sleep(Duration::from_millis(1)); 37 | } 38 | }; 39 | 40 | let thread_with_no_name = thread::spawn(do_work); 41 | let thread_one = thread::Builder::new() 42 | .name("thread 1".to_string()) 43 | .spawn(do_work) 44 | .expect("could not spawn a new thread"); 45 | let thread_two = thread::Builder::new() 46 | .name("large name thread 2".to_string()) 47 | .spawn(do_work) 48 | .expect("could not spawn a new thread"); 49 | 50 | thread_with_no_name 51 | .join() 52 | .expect("could not wait for a thread"); 53 | thread_one.join().expect("could not wait for a thread"); 54 | thread_two.join().expect("could not wait for a thread"); 55 | } 56 | -------------------------------------------------------------------------------- /examples/examples/toggle-layers.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | /// This is a example showing how `Layer` can be enabled or disabled by 3 | /// by wrapping them with an `Option`. This example shows `fmt` and `json` 4 | /// being toggled based on the `json` command line flag. 5 | /// 6 | /// You can run this example by running the following command in a terminal 7 | /// 8 | /// ``` 9 | /// cargo run --example toggle-subscribers -- --json 10 | /// ``` 11 | /// 12 | use argh::FromArgs; 13 | use tracing::info; 14 | use tracing_subscriber::{prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt}; 15 | 16 | #[path = "fmt/yak_shave.rs"] 17 | mod yak_shave; 18 | 19 | #[derive(FromArgs)] 20 | /// Subscriber toggling example. 21 | struct Args { 22 | /// enable JSON log format 23 | #[argh(switch, short = 'j')] 24 | json: bool, 25 | } 26 | 27 | fn main() { 28 | let args: Args = argh::from_env(); 29 | 30 | let (json, plain) = if args.json { 31 | (Some(tracing_subscriber::fmt::layer().json()), None) 32 | } else { 33 | (None, Some(tracing_subscriber::fmt::layer())) 34 | }; 35 | 36 | tracing_subscriber::registry().with(json).with(plain).init(); 37 | 38 | let number_of_yaks = 3; 39 | // this creates a new event, outside of any spans. 40 | info!(number_of_yaks, "preparing to shave yaks"); 41 | 42 | let number_shaved = yak_shave::shave_all(number_of_yaks); 43 | info!( 44 | all_yaks_shaved = number_shaved == number_of_yaks, 45 | "yak shaving completed." 46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /examples/examples/tokio-spawny-thing.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms)] 2 | /// This is a example showing how information is scoped with tokio's 3 | /// `task::spawn`. 4 | /// 5 | /// You can run this example by running the following command in a terminal 6 | /// 7 | /// ``` 8 | /// cargo run --example tokio-spawny-thing 9 | /// ``` 10 | use futures::future::try_join_all; 11 | use tracing::{debug, info, instrument, span, Instrument as _, Level}; 12 | 13 | type Error = Box; 14 | 15 | #[instrument] 16 | async fn parent_task(subtasks: usize) -> Result<(), Error> { 17 | info!("spawning subtasks..."); 18 | let subtasks = (1..=subtasks) 19 | .map(|number| { 20 | let span = span!(Level::INFO, "subtask", %number); 21 | debug!(message = "creating subtask;", number); 22 | tokio::spawn(subtask(number).instrument(span)) 23 | }) 24 | .collect::>(); 25 | 26 | // the returnable error would be if one of the subtasks panicked. 27 | let sum: usize = try_join_all(subtasks).await?.iter().sum(); 28 | info!(%sum, "all subtasks completed; calculated sum"); 29 | Ok(()) 30 | } 31 | 32 | async fn subtask(number: usize) -> usize { 33 | info!(%number, "polling subtask"); 34 | number 35 | } 36 | 37 | #[tokio::main] 38 | async fn main() -> Result<(), Error> { 39 | tracing_subscriber::fmt() 40 | .with_max_level(tracing::Level::DEBUG) 41 | .try_init()?; 42 | parent_task(10).await?; 43 | Ok(()) 44 | } 45 | -------------------------------------------------------------------------------- /examples/examples/tokio_panic_hook.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates that a custom panic hook can be used to log panic 2 | //! messages even when panics are captured (such as when a Tokio task panics). 3 | //! 4 | //! This is essentially the same as the `panic_hook.rs` example, but modified to 5 | //! spawn async tasks using the Tokio runtime rather than panicking in a 6 | //! synchronous function. See the `panic_hook.rs` example for details on using 7 | //! custom panic hooks. 8 | #[tokio::main] 9 | async fn main() { 10 | let subscriber = tracing_subscriber::fmt() 11 | .with_max_level(tracing::Level::TRACE) 12 | .finish(); 13 | 14 | // NOTE: Using `tracing` in a panic hook requires the use of the *global* 15 | // trace dispatcher (`tracing::subscriber::set_global_default`), rather than 16 | // the per-thread scoped dispatcher 17 | // (`tracing::subscriber::with_default`/`set_default`). With the scoped trace 18 | // dispatcher, the subscriber's thread-local context may already have been 19 | // torn down by unwinding by the time the panic handler is reached. 20 | tracing::subscriber::set_global_default(subscriber).unwrap(); 21 | 22 | std::panic::set_hook(Box::new(|panic| { 23 | if let Some(location) = panic.location() { 24 | tracing::error!( 25 | message = %panic, 26 | panic.file = location.file(), 27 | panic.line = location.line(), 28 | panic.column = location.column(), 29 | ); 30 | } else { 31 | tracing::error!(message = %panic); 32 | } 33 | })); 34 | 35 | // Spawn tasks to check the numbers from 1-10. 36 | let tasks = (0..10) 37 | .map(|i| tokio::spawn(check_number(i))) 38 | .collect::>(); 39 | futures::future::join_all(tasks).await; 40 | 41 | tracing::trace!("all tasks done"); 42 | } 43 | 44 | #[tracing::instrument] 45 | async fn check_number(x: i32) { 46 | tracing::trace!("checking number..."); 47 | tokio::task::yield_now().await; 48 | 49 | if x % 2 == 0 { 50 | panic!("I don't work with even numbers!"); 51 | } 52 | 53 | tracing::info!("number checks out!") 54 | } 55 | -------------------------------------------------------------------------------- /examples/examples/tower-client.rs: -------------------------------------------------------------------------------- 1 | use http::{Method, Request, Uri}; 2 | use hyper::{client::Client, Body}; 3 | use std::time::Duration; 4 | use tower::{Service, ServiceBuilder}; 5 | use tracing::info; 6 | use tracing_tower::request_span; 7 | 8 | type Err = Box; 9 | 10 | fn req_span(req: &Request) -> tracing::Span { 11 | let span = tracing::info_span!( 12 | "request", 13 | req.method = ?req.method(), 14 | req.uri = ?req.uri(), 15 | req.version = ?req.version(), 16 | headers = ?req.headers() 17 | ); 18 | tracing::info!(parent: &span, "sending request"); 19 | span 20 | } 21 | 22 | #[tokio::main] 23 | async fn main() -> Result<(), Err> { 24 | tracing_subscriber::fmt() 25 | .with_env_filter("tower=trace") 26 | .try_init()?; 27 | 28 | let mut svc = ServiceBuilder::new() 29 | .timeout(Duration::from_millis(250)) 30 | .layer(request_span::layer(req_span)) 31 | .service(Client::new()); 32 | 33 | let uri = Uri::from_static("http://httpbin.org"); 34 | 35 | let req = Request::builder() 36 | .method(Method::GET) 37 | .uri(uri) 38 | .body(Body::empty()) 39 | .expect("Unable to build request; this is a bug."); 40 | 41 | let res = svc.call(req).await?; 42 | info!(message = "got a response", res.headers = ?res.headers()); 43 | 44 | Ok(()) 45 | } 46 | -------------------------------------------------------------------------------- /examples/examples/valuable.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | //! This example shows how a field value may be recorded using the `valuable` 3 | //! crate (https://crates.io/crates/valuable). 4 | //! 5 | //! `valuable` provides a lightweight but flexible way to record structured data, allowing 6 | //! visitors to extract individual fields or elements of structs, maps, arrays, and other 7 | //! nested structures. 8 | //! 9 | //! `tracing`'s support for `valuable` is currently feature flagged. Additionally, `valuable` 10 | //! support is considered an *unstable feature*: in order to use `valuable` with `tracing`, 11 | //! the project must be built with `RUSTFLAGS="--cfg tracing_unstable`. 12 | //! 13 | //! Therefore, when `valuable` support is not enabled, this example falls back to using 14 | //! `fmt::Debug` to record fields that implement `valuable::Valuable`. 15 | use tracing::{info, info_span}; 16 | use valuable::Valuable; 17 | 18 | #[derive(Clone, Debug, Valuable)] 19 | struct User { 20 | name: String, 21 | age: u32, 22 | address: Address, 23 | } 24 | 25 | #[derive(Clone, Debug, Valuable)] 26 | struct Address { 27 | country: String, 28 | city: String, 29 | street: String, 30 | } 31 | 32 | fn main() { 33 | tracing_subscriber::fmt() 34 | .with_max_level(tracing::Level::TRACE) 35 | .init(); 36 | 37 | let user = User { 38 | name: "Arwen Undomiel".to_string(), 39 | age: 3000, 40 | address: Address { 41 | country: "Middle Earth".to_string(), 42 | city: "Rivendell".to_string(), 43 | street: "leafy lane".to_string(), 44 | }, 45 | }; 46 | 47 | // If the `valuable` feature is enabled, record `user` using its' 48 | // `valuable::Valuable` implementation: 49 | #[cfg(tracing_unstable)] 50 | let span = info_span!("Processing", user = user.as_value()); 51 | 52 | // Otherwise, record `user` using its `fmt::Debug` implementation: 53 | #[cfg(not(tracing_unstable))] 54 | let span = info_span!("Processing", user = ?user); 55 | 56 | let _handle = span.enter(); 57 | info!("Nothing to do"); 58 | } 59 | -------------------------------------------------------------------------------- /examples/examples/valuable_instrument.rs: -------------------------------------------------------------------------------- 1 | #[cfg(tracing_unstable)] 2 | mod app { 3 | use std::collections::HashMap; 4 | use tracing::field::valuable; 5 | use tracing::{info, instrument}; 6 | use valuable::Valuable; 7 | 8 | #[derive(Valuable)] 9 | struct Headers<'a> { 10 | headers: HashMap<&'a str, &'a str>, 11 | } 12 | 13 | // Current there's no way to automatically apply valuable to a type, so we need to make use of 14 | // the fields argument for instrument 15 | #[instrument(fields(headers=valuable(&headers)))] 16 | fn process(headers: Headers) { 17 | info!("Handle request") 18 | } 19 | 20 | pub fn run() { 21 | let headers = [ 22 | ("content-type", "application/json"), 23 | ("content-length", "568"), 24 | ("server", "github.com"), 25 | ] 26 | .iter() 27 | .cloned() 28 | .collect::>(); 29 | 30 | let http_headers = Headers { headers }; 31 | 32 | process(http_headers); 33 | } 34 | } 35 | 36 | fn main() { 37 | tracing_subscriber::fmt() 38 | .with_max_level(tracing::Level::TRACE) 39 | .init(); 40 | 41 | #[cfg(tracing_unstable)] 42 | app::run(); 43 | #[cfg(not(tracing_unstable))] 44 | println!("Nothing to do, this example needs --cfg=tracing_unstable to run"); 45 | } 46 | -------------------------------------------------------------------------------- /examples/examples/valuable_json.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | //! This example shows how a field value may be recorded using the `valuable` 3 | //! crate (https://crates.io/crates/valuable). 4 | //! 5 | //! `valuable` provides a lightweight but flexible way to record structured data, allowing 6 | //! visitors to extract individual fields or elements of structs, maps, arrays, and other 7 | //! nested structures. 8 | //! 9 | //! `tracing`'s support for `valuable` is currently feature flagged. Additionally, `valuable` 10 | //! support is considered an *unstable feature*: in order to use `valuable` with `tracing`, 11 | //! the project must be built with `RUSTFLAGS="--cfg tracing_unstable`. 12 | //! 13 | //! Therefore, when `valuable` support is not enabled, this example falls back to using 14 | //! `fmt::Debug` to record fields that implement `valuable::Valuable`. 15 | #[cfg(tracing_unstable)] 16 | use tracing::field::valuable; 17 | use valuable::Valuable; 18 | 19 | #[derive(Clone, Debug, Valuable)] 20 | struct User { 21 | name: String, 22 | age: u32, 23 | address: Address, 24 | } 25 | 26 | #[derive(Clone, Debug, Valuable)] 27 | struct Address { 28 | country: String, 29 | city: String, 30 | street: String, 31 | } 32 | 33 | fn main() { 34 | tracing_subscriber::fmt() 35 | .with_max_level(tracing::Level::TRACE) 36 | .json() 37 | .init(); 38 | 39 | let user = User { 40 | name: "Arwen Undomiel".to_string(), 41 | age: 3000, 42 | address: Address { 43 | country: "Middle Earth".to_string(), 44 | city: "Rivendell".to_string(), 45 | street: "leafy lane".to_string(), 46 | }, 47 | }; 48 | 49 | // for comparison, record `user` without using its `Valuable` 50 | // implementation: 51 | tracing::info!(valuable = false, user = ?user); 52 | 53 | // If the `valuable` feature is enabled, record `user` using its' 54 | // `valuable::Valuable` implementation: 55 | #[cfg(tracing_unstable)] 56 | tracing::info!(valuable = true, user = valuable(&user)); 57 | 58 | #[cfg(not(tracing_unstable))] 59 | tracing::warn!( 60 | "note: this example was run without `valuable` support enabled!\n\ 61 | rerun with `RUSTFLAGS=\"--cfg tracing_unstable\" to enable `valuable`", 62 | ); 63 | } 64 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = """ 3 | rustup install nightly --profile minimal \ 4 | && cargo doc --no-deps --all-features 5 | """ 6 | publish = "target/doc" 7 | 8 | [build.environment] 9 | RUSTDOCFLAGS=""" 10 | -D warnings \ 11 | --force-warn rustdoc::redundant-explicit-links \ 12 | --force-warn renamed-and-removed-lints \ 13 | --cfg docsrs \ 14 | --cfg tracing_unstable 15 | """ 16 | RUSTFLAGS="--cfg tracing_unstable" 17 | 18 | [[redirects]] 19 | from = "/" 20 | to = "/tracing" 21 | -------------------------------------------------------------------------------- /tracing-appender/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-appender" 3 | version = "0.2.3" 4 | authors = [ 5 | "Zeki Sherif ", 6 | "Tokio Contributors " 7 | ] 8 | license = "MIT" 9 | readme = "README.md" 10 | repository = "https://github.com/tokio-rs/tracing" 11 | homepage = "https://tokio.rs" 12 | description = """ 13 | Provides utilities for file appenders and making non-blocking writers. 14 | """ 15 | categories = [ 16 | "development-tools::debugging", 17 | "asynchronous", 18 | ] 19 | keywords = ["logging", "tracing", "file-appender", "non-blocking-writer"] 20 | edition = "2018" 21 | rust-version = "1.63.0" 22 | 23 | [dependencies] 24 | crossbeam-channel = "0.5.6" 25 | time = { version = "0.3.2", default-features = false, features = ["formatting", "parsing"] } 26 | parking_lot = { optional = true, version = "0.12.1" } 27 | thiserror = "2" 28 | 29 | [dependencies.tracing-subscriber] 30 | path = "../tracing-subscriber" 31 | version = "0.3.18" 32 | default-features = false 33 | features = ["fmt", "std"] 34 | 35 | [dev-dependencies] 36 | criterion = { version = "0.3.6", default-features = false } 37 | tracing = { path = "../tracing", version = "0.1.35" } 38 | tempfile = "3" 39 | 40 | [[bench]] 41 | name = "bench" 42 | harness = false 43 | -------------------------------------------------------------------------------- /tracing-appender/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-appender/src/sync.rs: -------------------------------------------------------------------------------- 1 | //! Abstracts over sync primitive implementations. 2 | //! 3 | //! Optionally, we allow the Rust standard library's `RwLock` to be replaced 4 | //! with the `parking_lot` crate's implementation. This may provide improved 5 | //! performance in some cases. However, the `parking_lot` dependency is an 6 | //! opt-in feature flag. Because `parking_lot::RwLock` has a slightly different 7 | //! API than `std::sync::RwLock` (it does not support poisoning on panics), we 8 | //! wrap the `std::sync` version to ignore poisoning. 9 | 10 | #[allow(unused_imports)] // may be used later; 11 | #[cfg(feature = "parking_lot")] 12 | pub(crate) use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; 13 | 14 | #[cfg(not(feature = "parking_lot"))] 15 | pub(crate) use self::std_impl::*; 16 | 17 | #[cfg(not(feature = "parking_lot"))] 18 | mod std_impl { 19 | use std::sync::{self, PoisonError, TryLockError}; 20 | pub(crate) use std::sync::{RwLockReadGuard, RwLockWriteGuard}; 21 | 22 | #[derive(Debug)] 23 | pub(crate) struct RwLock { 24 | inner: sync::RwLock, 25 | } 26 | 27 | impl RwLock { 28 | pub(crate) fn new(val: T) -> Self { 29 | Self { 30 | inner: sync::RwLock::new(val), 31 | } 32 | } 33 | 34 | #[inline] 35 | pub(crate) fn get_mut(&mut self) -> &mut T { 36 | self.inner.get_mut().unwrap_or_else(PoisonError::into_inner) 37 | } 38 | 39 | #[inline] 40 | pub(crate) fn read(&self) -> RwLockReadGuard<'_, T> { 41 | self.inner.read().unwrap_or_else(PoisonError::into_inner) 42 | } 43 | 44 | #[inline] 45 | #[allow(dead_code)] // may be used later; 46 | pub(crate) fn try_read(&self) -> Option> { 47 | match self.inner.try_read() { 48 | Ok(guard) => Some(guard), 49 | Err(TryLockError::Poisoned(e)) => Some(e.into_inner()), 50 | Err(TryLockError::WouldBlock) => None, 51 | } 52 | } 53 | 54 | #[inline] 55 | pub(crate) fn write(&self) -> RwLockWriteGuard<'_, T> { 56 | self.inner.write().unwrap_or_else(PoisonError::into_inner) 57 | } 58 | 59 | #[inline] 60 | #[allow(dead_code)] // may be used later; 61 | pub(crate) fn try_write(&self) -> Option> { 62 | match self.inner.try_write() { 63 | Ok(guard) => Some(guard), 64 | Err(TryLockError::Poisoned(e)) => Some(e.into_inner()), 65 | Err(TryLockError::WouldBlock) => None, 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tracing-attributes/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-attributes" 3 | # When releasing to crates.io: 4 | # - Remove path dependencies 5 | # - Update doc url in README.md. 6 | # - Update CHANGELOG.md. 7 | # - Create "tracing-attributes-0.1.x" git tag. 8 | version = "0.1.29" 9 | authors = [ 10 | "Tokio Contributors ", 11 | "Eliza Weisman ", 12 | "David Barsky ", 13 | ] 14 | repository = "https://github.com/tokio-rs/tracing" 15 | homepage = "https://tokio.rs" 16 | description = """ 17 | Procedural macro attributes for automatically instrumenting functions. 18 | """ 19 | categories = [ 20 | "development-tools::debugging", 21 | "development-tools::profiling", 22 | "asynchronous", 23 | ] 24 | keywords = ["logging", "tracing", "macro", "instrument", "log"] 25 | license = "MIT" 26 | readme = "README.md" 27 | edition = "2018" 28 | rust-version = "1.65.0" 29 | 30 | [lib] 31 | proc-macro = true 32 | 33 | [features] 34 | 35 | # This feature flag is no longer necessary. 36 | async-await = [] 37 | 38 | [dependencies] 39 | proc-macro2 = "1.0.60" 40 | syn = { version = "2.0", default-features = false, features = [ 41 | "full", 42 | "parsing", 43 | "printing", 44 | "visit-mut", 45 | "clone-impls", 46 | "extra-traits", 47 | "proc-macro", 48 | ] } 49 | quote = "1.0.20" 50 | 51 | [dev-dependencies] 52 | tracing = { path = "../tracing", version = "0.1.35" } 53 | tracing-mock = { path = "../tracing-mock" } 54 | tokio-test = "0.4.2" 55 | tracing-subscriber = { path = "../tracing-subscriber", version = "0.3.0", features = [ 56 | "env-filter", 57 | ] } 58 | tracing-test = { path = "../tracing-test" } 59 | async-trait = "0.1.67" 60 | trybuild = "1.0.64" 61 | rustversion = "1.0.9" 62 | 63 | [badges] 64 | maintenance = { status = "experimental" } 65 | 66 | [lints] 67 | workspace = true 68 | -------------------------------------------------------------------------------- /tracing-attributes/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-attributes/tests/dead_code.rs: -------------------------------------------------------------------------------- 1 | use tracing_attributes::instrument; 2 | 3 | #[deny(unfulfilled_lint_expectations)] 4 | #[expect(dead_code)] 5 | #[instrument] 6 | fn unused() {} 7 | 8 | #[expect(dead_code)] 9 | #[instrument] 10 | async fn unused_async() {} 11 | -------------------------------------------------------------------------------- /tracing-attributes/tests/names.rs: -------------------------------------------------------------------------------- 1 | use tracing::subscriber::with_default; 2 | use tracing_attributes::instrument; 3 | use tracing_mock::*; 4 | 5 | #[instrument] 6 | fn default_name() {} 7 | 8 | #[instrument(name = "my_name")] 9 | fn custom_name() {} 10 | 11 | // XXX: it's weird that we support both of these forms, but apparently we 12 | // managed to release a version that accepts both syntax, so now we have to 13 | // support it! yay! 14 | #[instrument("my_other_name")] 15 | fn custom_name_no_equals() {} 16 | 17 | #[test] 18 | fn default_name_test() { 19 | let (subscriber, handle) = subscriber::mock() 20 | .new_span(expect::span().named("default_name")) 21 | .enter(expect::span().named("default_name")) 22 | .exit(expect::span().named("default_name")) 23 | .only() 24 | .run_with_handle(); 25 | 26 | with_default(subscriber, || { 27 | default_name(); 28 | }); 29 | 30 | handle.assert_finished(); 31 | } 32 | 33 | #[test] 34 | fn custom_name_test() { 35 | let (subscriber, handle) = subscriber::mock() 36 | .new_span(expect::span().named("my_name")) 37 | .enter(expect::span().named("my_name")) 38 | .exit(expect::span().named("my_name")) 39 | .only() 40 | .run_with_handle(); 41 | 42 | with_default(subscriber, || { 43 | custom_name(); 44 | }); 45 | 46 | handle.assert_finished(); 47 | } 48 | 49 | #[test] 50 | fn custom_name_no_equals_test() { 51 | let (subscriber, handle) = subscriber::mock() 52 | .new_span(expect::span().named("my_other_name")) 53 | .enter(expect::span().named("my_other_name")) 54 | .exit(expect::span().named("my_other_name")) 55 | .only() 56 | .run_with_handle(); 57 | 58 | with_default(subscriber, || { 59 | custom_name_no_equals(); 60 | }); 61 | 62 | handle.assert_finished(); 63 | } 64 | -------------------------------------------------------------------------------- /tracing-attributes/tests/ui.rs: -------------------------------------------------------------------------------- 1 | // Only test on nightly, since UI tests are bound to change over time 2 | #[rustversion::stable] 3 | #[test] 4 | fn async_instrument() { 5 | let t = trybuild::TestCases::new(); 6 | t.compile_fail("tests/ui/async_instrument.rs"); 7 | } 8 | 9 | #[rustversion::stable] 10 | #[test] 11 | fn const_instrument() { 12 | let t = trybuild::TestCases::new(); 13 | t.compile_fail("tests/ui/const_instrument.rs"); 14 | } 15 | -------------------------------------------------------------------------------- /tracing-attributes/tests/ui/async_instrument.rs: -------------------------------------------------------------------------------- 1 | #![allow(unreachable_code)] 2 | 3 | #[tracing::instrument] 4 | async fn unit() { 5 | "" 6 | } 7 | 8 | #[tracing::instrument] 9 | async fn simple_mismatch() -> String { 10 | "" 11 | } 12 | 13 | #[tracing::instrument] 14 | async fn opaque_unsatisfied() -> impl std::fmt::Display { 15 | ("",) 16 | } 17 | 18 | struct Wrapper(T); 19 | 20 | #[tracing::instrument] 21 | async fn mismatch_with_opaque() -> Wrapper { 22 | "" 23 | } 24 | 25 | #[tracing::instrument] 26 | async fn early_return_unit() { 27 | if true { 28 | return ""; 29 | } 30 | } 31 | 32 | #[tracing::instrument] 33 | async fn early_return() -> String { 34 | if true { 35 | return ""; 36 | } 37 | String::new() 38 | } 39 | 40 | #[tracing::instrument] 41 | async fn extra_semicolon() -> i32 { 42 | 1; 43 | } 44 | 45 | fn main() {} 46 | -------------------------------------------------------------------------------- /tracing-attributes/tests/ui/const_instrument.rs: -------------------------------------------------------------------------------- 1 | #![allow(unreachable_code)] 2 | 3 | #[tracing::instrument] 4 | const fn unit() { 5 | "" 6 | } 7 | 8 | fn main() {} 9 | -------------------------------------------------------------------------------- /tracing-attributes/tests/ui/const_instrument.stderr: -------------------------------------------------------------------------------- 1 | error: macros that expand to items must be delimited with braces or followed by a semicolon 2 | --> tests/ui/const_instrument.rs:3:1 3 | | 4 | 3 | #[tracing::instrument] 5 | | ^^^^^^^^^^^^^^^^^^^^^^ 6 | | 7 | = note: this error originates in the attribute macro `tracing::instrument` (in Nightly builds, run with -Z macro-backtrace for more info) 8 | 9 | error: the `#[instrument]` attribute may not be used with `const fn`s 10 | --> tests/ui/const_instrument.rs:3:1 11 | | 12 | 3 | #[tracing::instrument] 13 | | ^^^^^^^^^^^^^^^^^^^^^^ 14 | | 15 | = note: this error originates in the attribute macro `tracing::instrument` (in Nightly builds, run with -Z macro-backtrace for more info) 16 | -------------------------------------------------------------------------------- /tracing-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-core" 3 | # When releasing to crates.io: 4 | # - Remove path dependencies 5 | # - Update html_root_url. 6 | # - Update doc url in README.md. 7 | # - Update CHANGELOG.md. 8 | # - Create "tracing-core-0.1.x" git tag. 9 | version = "0.1.34" 10 | authors = ["Tokio Contributors "] 11 | license = "MIT" 12 | readme = "README.md" 13 | repository = "https://github.com/tokio-rs/tracing" 14 | homepage = "https://tokio.rs" 15 | description = """ 16 | Core primitives for application-level tracing. 17 | """ 18 | categories = [ 19 | "development-tools::debugging", 20 | "development-tools::profiling", 21 | "asynchronous", 22 | ] 23 | keywords = ["logging", "tracing", "profiling"] 24 | edition = "2018" 25 | rust-version = "1.65.0" 26 | 27 | [features] 28 | default = ["std", "valuable?/std"] 29 | std = ["once_cell"] 30 | 31 | [badges] 32 | maintenance = { status = "actively-developed" } 33 | 34 | [dependencies] 35 | once_cell = { version = "1.13.0", optional = true } 36 | 37 | [target.'cfg(tracing_unstable)'.dependencies] 38 | valuable = { version = "0.1.0", optional = true, default-features = false } 39 | 40 | [package.metadata.docs.rs] 41 | all-features = true 42 | # enable unstable features in the documentation 43 | rustdoc-args = ["--cfg", "docsrs", "--cfg", "tracing_unstable"] 44 | # it's necessary to _also_ pass `--cfg tracing_unstable` to rustc, or else 45 | # dependencies will not be enabled, and the docs build will fail. 46 | rustc-args = ["--cfg", "tracing_unstable"] 47 | 48 | [lints] 49 | workspace = true 50 | -------------------------------------------------------------------------------- /tracing-core/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-core/src/parent.rs: -------------------------------------------------------------------------------- 1 | use crate::span::Id; 2 | 3 | #[derive(Debug)] 4 | pub(crate) enum Parent { 5 | /// The new span will be a root span. 6 | Root, 7 | /// The new span will be rooted in the current span. 8 | Current, 9 | /// The new span has an explicitly-specified parent. 10 | Explicit(Id), 11 | } 12 | -------------------------------------------------------------------------------- /tracing-core/src/spin/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Mathijs van de Nes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tracing-core/src/spin/mod.rs: -------------------------------------------------------------------------------- 1 | //! Synchronization primitives based on spinning 2 | 3 | pub(crate) use mutex::*; 4 | pub(crate) use once::Once; 5 | 6 | mod mutex; 7 | mod once; 8 | -------------------------------------------------------------------------------- /tracing-core/tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | use tracing_core::{metadata::Metadata, span, subscriber::Subscriber, Event}; 2 | 3 | pub struct TestSubscriberA; 4 | impl Subscriber for TestSubscriberA { 5 | fn enabled(&self, _: &Metadata<'_>) -> bool { 6 | true 7 | } 8 | fn new_span(&self, _: &span::Attributes<'_>) -> span::Id { 9 | span::Id::from_u64(1) 10 | } 11 | fn record(&self, _: &span::Id, _: &span::Record<'_>) {} 12 | fn record_follows_from(&self, _: &span::Id, _: &span::Id) {} 13 | fn event(&self, _: &Event<'_>) {} 14 | fn enter(&self, _: &span::Id) {} 15 | fn exit(&self, _: &span::Id) {} 16 | } 17 | pub struct TestSubscriberB; 18 | impl Subscriber for TestSubscriberB { 19 | fn enabled(&self, _: &Metadata<'_>) -> bool { 20 | true 21 | } 22 | fn new_span(&self, _: &span::Attributes<'_>) -> span::Id { 23 | span::Id::from_u64(1) 24 | } 25 | fn record(&self, _: &span::Id, _: &span::Record<'_>) {} 26 | fn record_follows_from(&self, _: &span::Id, _: &span::Id) {} 27 | fn event(&self, _: &Event<'_>) {} 28 | fn enter(&self, _: &span::Id) {} 29 | fn exit(&self, _: &span::Id) {} 30 | } 31 | -------------------------------------------------------------------------------- /tracing-core/tests/dispatch.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "std")] 2 | mod common; 3 | 4 | use common::*; 5 | use tracing_core::dispatcher::*; 6 | 7 | #[test] 8 | fn set_default_dispatch() { 9 | set_global_default(Dispatch::new(TestSubscriberA)).expect("global dispatch set failed"); 10 | get_default(|current| { 11 | assert!( 12 | current.is::(), 13 | "global dispatch get failed" 14 | ) 15 | }); 16 | 17 | let guard = set_default(&Dispatch::new(TestSubscriberB)); 18 | get_default(|current| assert!(current.is::(), "set_default get failed")); 19 | 20 | // Drop the guard, setting the dispatch back to the global dispatch 21 | drop(guard); 22 | 23 | get_default(|current| { 24 | assert!( 25 | current.is::(), 26 | "global dispatch get failed" 27 | ) 28 | }); 29 | } 30 | 31 | #[test] 32 | fn nested_set_default() { 33 | let _guard = set_default(&Dispatch::new(TestSubscriberA)); 34 | get_default(|current| { 35 | assert!( 36 | current.is::(), 37 | "set_default for outer subscriber failed" 38 | ) 39 | }); 40 | 41 | let inner_guard = set_default(&Dispatch::new(TestSubscriberB)); 42 | get_default(|current| { 43 | assert!( 44 | current.is::(), 45 | "set_default inner subscriber failed" 46 | ) 47 | }); 48 | 49 | drop(inner_guard); 50 | get_default(|current| { 51 | assert!( 52 | current.is::(), 53 | "set_default outer subscriber failed" 54 | ) 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /tracing-core/tests/global_dispatch.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use common::*; 4 | use tracing_core::dispatcher::*; 5 | #[test] 6 | fn global_dispatch() { 7 | set_global_default(Dispatch::new(TestSubscriberA)).expect("global dispatch set failed"); 8 | get_default(|current| { 9 | assert!( 10 | current.is::(), 11 | "global dispatch get failed" 12 | ) 13 | }); 14 | 15 | #[cfg(feature = "std")] 16 | with_default(&Dispatch::new(TestSubscriberB), || { 17 | get_default(|current| { 18 | assert!( 19 | current.is::(), 20 | "thread-local override of global dispatch failed" 21 | ) 22 | }); 23 | }); 24 | 25 | get_default(|current| { 26 | assert!( 27 | current.is::(), 28 | "reset to global override failed" 29 | ) 30 | }); 31 | 32 | set_global_default(Dispatch::new(TestSubscriberA)) 33 | .expect_err("double global dispatch set succeeded"); 34 | } 35 | -------------------------------------------------------------------------------- /tracing-core/tests/local_dispatch_before_init.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use common::*; 4 | use tracing_core::{ 5 | dispatcher::{self, Dispatch}, 6 | subscriber::NoSubscriber, 7 | }; 8 | 9 | /// This test reproduces the following issues: 10 | /// - https://github.com/tokio-rs/tracing/issues/2587 11 | /// - https://github.com/tokio-rs/tracing/issues/2411 12 | /// - https://github.com/tokio-rs/tracing/issues/2436 13 | #[test] 14 | fn local_dispatch_before_init() { 15 | dispatcher::get_default(|current| assert!(dbg!(current).is::())); 16 | 17 | // Temporarily override the default dispatcher with a scoped dispatcher. 18 | // Using a scoped dispatcher makes the thread local state attempt to cache 19 | // the scoped default. 20 | #[cfg(feature = "std")] 21 | { 22 | dispatcher::with_default(&Dispatch::new(TestSubscriberB), || { 23 | dispatcher::get_default(|current| { 24 | assert!( 25 | dbg!(current).is::(), 26 | "overriden subscriber not set", 27 | ); 28 | }) 29 | }) 30 | } 31 | 32 | dispatcher::get_default(|current| assert!(current.is::())); 33 | 34 | dispatcher::set_global_default(Dispatch::new(TestSubscriberA)) 35 | .expect("set global dispatch failed"); 36 | 37 | dispatcher::get_default(|current| { 38 | assert!( 39 | dbg!(current).is::(), 40 | "default subscriber not set" 41 | ); 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /tracing-core/tests/macros.rs: -------------------------------------------------------------------------------- 1 | use tracing_core::{ 2 | callsite::Callsite, 3 | metadata, 4 | metadata::{Kind, Level, Metadata}, 5 | subscriber::Interest, 6 | }; 7 | 8 | #[test] 9 | fn metadata_macro_api() { 10 | // This test should catch any inadvertent breaking changes 11 | // caused by changes to the macro. 12 | struct TestCallsite; 13 | 14 | impl Callsite for TestCallsite { 15 | fn set_interest(&self, _: Interest) { 16 | unimplemented!("test") 17 | } 18 | fn metadata(&self) -> &Metadata<'_> { 19 | unimplemented!("test") 20 | } 21 | } 22 | 23 | static CALLSITE: TestCallsite = TestCallsite; 24 | let _metadata = metadata! { 25 | name: "test_metadata", 26 | target: "test_target", 27 | level: Level::DEBUG, 28 | fields: &["foo", "bar", "baz"], 29 | callsite: &CALLSITE, 30 | kind: Kind::SPAN, 31 | }; 32 | let _metadata = metadata! { 33 | name: "test_metadata", 34 | target: "test_target", 35 | level: Level::TRACE, 36 | fields: &[], 37 | callsite: &CALLSITE, 38 | kind: Kind::EVENT, 39 | }; 40 | let _metadata = metadata! { 41 | name: "test_metadata", 42 | target: "test_target", 43 | level: Level::INFO, 44 | fields: &[], 45 | callsite: &CALLSITE, 46 | kind: Kind::EVENT 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /tracing-error/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.2.1 (November 29, 2024) 2 | 3 | [ [crates.io][crate-0.2.1] ] | [ [docs.rs][docs-0.2.1] ] 4 | 5 | ### Changed 6 | 7 | - Bump MSRV to 1.63 ([#2793]) 8 | 9 | ### Documented 10 | 11 | - Use intra-doc links instead of relative file paths ([#2068]) 12 | - More intra-doc links ([#2077]) 13 | - Add missing backtick to `prelude` docs ([#2120]) 14 | 15 | [#2068]: https://github.com/tokio-rs/tracing/pull/2068 16 | [#2077]: https://github.com/tokio-rs/tracing/pull/2077 17 | [#2120]: https://github.com/tokio-rs/tracing/pull/2120 18 | [#2793]: https://github.com/tokio-rs/tracing/pull/2793 19 | [docs-0.2.1]: https://docs.rs/tracing-error/0.2.1/tracing_error/ 20 | [crate-0.2.1]: https://crates.io/crates/tracing-error/0.2.1 21 | 22 | # 0.2.0 (October 23, 2021) 23 | 24 | This is a breaking change release in order to update the `tracing-subscriber` 25 | dependency version to [the v0.3.x release series][v03]. 26 | 27 | ### Changed 28 | 29 | - Updated `tracing-subscriber` dependency to [v0.3.0][v03] ([#1677]) 30 | 31 | ### Fixed 32 | 33 | - Disabled default features of the `tracing` dependency so that proc-macro 34 | dependencies are not enabled ([#1144]) 35 | - Documentation fixes and improvements ([#635], [#695]) 36 | 37 | ### Added 38 | 39 | - **SpanTrace**: Added `SpanTrace::new` constructor for constructing a 40 | `SpanTrace` from a `Span` passed as an argument (rather than capturing the 41 | current span) ([#1492]) 42 | 43 | Thanks to @CAD97 for contributing to this release! 44 | 45 | [v03]: https://github.com/tokio-rs/tracing/releases/tag/tracing-subscriber-0.3.0 46 | [#635]: https://github.com/tokio-rs/tracing/pull/635 47 | [#695]: https://github.com/tokio-rs/tracing/pull/695 48 | [#1144]: https://github.com/tokio-rs/tracing/pull/1144 49 | [#1492]: https://github.com/tokio-rs/tracing/pull/1492 50 | [#1677]: https://github.com/tokio-rs/tracing/pull/1677 51 | 52 | # 0.1.2 (March 3, 2020) 53 | 54 | ### Added 55 | 56 | - **TracedError**: `TracedError`, an error type wrapper that annotates an error 57 | with the current span. 58 | - **SpanTrace**:`SpanTrace::status` method and `SpanTraceStatus` type for 59 | determining whether a `SpanTrace` was successfully captured (#614) 60 | 61 | ### Changed 62 | 63 | - **SpanTrace**: Made backtrace formatting more consistent with upstream changes 64 | to `std::backtrace` (#584) 65 | 66 | # 0.1.1 (February 5, 2020) 67 | 68 | ### Fixed 69 | 70 | - Fixed a typo in the crate description 71 | 72 | ### Changed 73 | 74 | - the maintenance badge from active to experimental 75 | 76 | # 0.1.0 (February 5, 2020) 77 | 78 | - Initial release 79 | -------------------------------------------------------------------------------- /tracing-error/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-error" 3 | # When releasing to crates.io: 4 | # - Remove path dependencies 5 | # - Update doc url in README.md. 6 | # - Update CHANGELOG.md. 7 | # - Create "v0.2.x" git tag 8 | version = "0.2.1" 9 | authors = [ 10 | "Eliza Weisman ", 11 | "Jane Lusby ", 12 | "Tokio Contributors " 13 | ] 14 | license = "MIT" 15 | readme = "README.md" 16 | repository = "https://github.com/tokio-rs/tracing" 17 | homepage = "https://tokio.rs" 18 | description = """ 19 | Utilities for enriching errors with `tracing`. 20 | """ 21 | categories = [ 22 | "development-tools::debugging", 23 | "rust-patterns" 24 | ] 25 | keywords = [ 26 | "tracing", 27 | "error-handling", 28 | "exception-reporting", 29 | "backtrace" 30 | ] 31 | edition = "2018" 32 | rust-version = "1.65.0" 33 | 34 | [features] 35 | default = ["traced-error"] 36 | traced-error = [] 37 | 38 | [dependencies] 39 | tracing-subscriber = { path = "../tracing-subscriber", version = "0.3.0", default-features = false, features = ["registry", "fmt"] } 40 | tracing = { path = "../tracing", version = "0.1.35", default-features = false, features = ["std"] } 41 | 42 | [badges] 43 | maintenance = { status = "experimental" } 44 | 45 | [package.metadata.docs.rs] 46 | all-features = true 47 | rustdoc-args = ["--cfg", "docsrs"] 48 | -------------------------------------------------------------------------------- /tracing-error/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-flame/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-flame" 3 | version = "0.2.0" 4 | authors = [ 5 | "Jane Lusby ", 6 | "Tokio Contributors " 7 | ] 8 | edition = "2018" 9 | license = "MIT" 10 | readme = "README.md" 11 | repository = "https://github.com/tokio-rs/tracing" 12 | homepage = "https://tokio.rs" 13 | description = """ 14 | Tracing layer for creating flamegraphs from span timings 15 | """ 16 | categories = [ 17 | "development-tools::debugging", 18 | "development-tools::profiling", 19 | "asynchronous", 20 | ] 21 | keywords = ["tracing", "subscriber", "flamegraph", "profiling"] 22 | rust-version = "1.65.0" 23 | 24 | [features] 25 | default = ["smallvec"] 26 | smallvec = ["tracing-subscriber/smallvec"] 27 | 28 | [dependencies] 29 | tracing-subscriber = { path = "../tracing-subscriber", version = "0.3.0", default-features = false, features = ["registry", "fmt"] } 30 | tracing = { path = "../tracing", version = "0.1.35", default-features = false, features = ["std"] } 31 | once_cell = "1.13.0" 32 | 33 | 34 | [dev-dependencies] 35 | tempfile = "3" 36 | -------------------------------------------------------------------------------- /tracing-flame/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-flame/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::path::PathBuf; 3 | 4 | /// The error type for `tracing-flame` 5 | #[derive(Debug)] 6 | pub struct Error(pub(crate) Kind); 7 | 8 | impl Error { 9 | pub(crate) fn report(&self) { 10 | let current_error: &dyn std::error::Error = self; 11 | let mut current_error = Some(current_error); 12 | let mut ind = 0; 13 | 14 | eprintln!("Error:"); 15 | 16 | while let Some(error) = current_error { 17 | eprintln!(" {}: {}", ind, error); 18 | ind += 1; 19 | current_error = error.source(); 20 | } 21 | } 22 | } 23 | 24 | impl fmt::Display for Error { 25 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 26 | fmt::Display::fmt(&self.0, f) 27 | } 28 | } 29 | 30 | impl std::error::Error for Error { 31 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 32 | match &self.0 { 33 | Kind::CreateFile { ref source, .. } => Some(source), 34 | Kind::FlushFile(ref source) => Some(source), 35 | } 36 | } 37 | } 38 | 39 | #[derive(Debug)] 40 | pub(crate) enum Kind { 41 | CreateFile { 42 | source: std::io::Error, 43 | path: PathBuf, 44 | }, 45 | FlushFile(std::io::Error), 46 | } 47 | 48 | impl fmt::Display for Kind { 49 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 50 | match self { 51 | Self::CreateFile { path, .. } => { 52 | write!(f, "cannot create output file. path={}", path.display()) 53 | } 54 | Self::FlushFile { .. } => write!(f, "cannot flush output buffer"), 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tracing-flame/tests/collapsed.rs: -------------------------------------------------------------------------------- 1 | use std::thread::sleep; 2 | use std::time::Duration; 3 | use tracing::{span, Level}; 4 | use tracing_flame::FlameLayer; 5 | use tracing_subscriber::{prelude::*, registry::Registry}; 6 | 7 | #[test] 8 | fn capture_supported() { 9 | { 10 | let tmp_dir = tempfile::Builder::new() 11 | .prefix("tracing-flamegraph-test-") 12 | .tempdir() 13 | .expect("failed to create tempdir"); 14 | let (flame_layer, _guard) = 15 | FlameLayer::with_file(tmp_dir.path().join("tracing.folded")).unwrap(); 16 | 17 | let subscriber = Registry::default().with(flame_layer); 18 | 19 | tracing::subscriber::set_global_default(subscriber).expect("Could not set global default"); 20 | 21 | { 22 | let span = span!(Level::ERROR, "outer"); 23 | let _guard = span.enter(); 24 | sleep(Duration::from_millis(10)); 25 | 26 | { 27 | let span = span!(Level::ERROR, "Inner"); 28 | let _guard = span.enter(); 29 | sleep(Duration::from_millis(50)); 30 | 31 | { 32 | let span = span!(Level::ERROR, "Innermost"); 33 | let _guard = span.enter(); 34 | sleep(Duration::from_millis(50)); 35 | } 36 | } 37 | 38 | sleep(Duration::from_millis(5)); 39 | } 40 | 41 | sleep(Duration::from_millis(500)); 42 | 43 | tmp_dir.close().expect("failed to delete tempdir"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tracing-flame/tests/concurrent.rs: -------------------------------------------------------------------------------- 1 | use std::thread::sleep; 2 | use std::time::Duration; 3 | use tracing::{span, Level}; 4 | use tracing_flame::FlameLayer; 5 | use tracing_subscriber::{prelude::*, registry::Registry}; 6 | 7 | #[test] 8 | fn capture_supported() { 9 | let tmp_dir = tempfile::Builder::new() 10 | .prefix("tracing-flamegraph-test-") 11 | .tempdir() 12 | .expect("failed to create tempdir"); 13 | let path = tmp_dir.path().join("tracing.folded"); 14 | let (flame_layer, flame_guard) = FlameLayer::with_file(&path).unwrap(); 15 | 16 | let subscriber = Registry::default().with(flame_layer); 17 | 18 | tracing::subscriber::set_global_default(subscriber).expect("Could not set global default"); 19 | let span = span!(Level::ERROR, "main"); 20 | let _guard = span.enter(); 21 | 22 | let thread = span!(Level::ERROR, "outer").in_scope(|| { 23 | sleep(Duration::from_millis(10)); 24 | let span = span!(Level::ERROR, "Inner"); 25 | let thread = std::thread::spawn(move || { 26 | span.in_scope(|| { 27 | sleep(Duration::from_millis(50)); 28 | }); 29 | }); 30 | sleep(Duration::from_millis(20)); 31 | thread 32 | }); 33 | 34 | sleep(Duration::from_millis(100)); 35 | 36 | thread.join().unwrap(); 37 | flame_guard.flush().unwrap(); 38 | 39 | let traces = std::fs::read_to_string(&path).unwrap(); 40 | println!("{}", traces); 41 | assert_eq!(5, traces.lines().count()); 42 | 43 | tmp_dir.close().expect("failed to delete tempdir"); 44 | } 45 | -------------------------------------------------------------------------------- /tracing-futures/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.2.5 (February 16, 2021) 2 | 3 | ### Changed 4 | 5 | - Updated `pin-project` dependency to 1.0 ([#1038]) 6 | 7 | ### Fixed 8 | 9 | - Several documentation fixes and improvements ([#832], [#911], [#913], [#941], 10 | [#953], [#981]) 11 | 12 | [#1038]: https://github.com/tokio-rs/tracing/pulls/1038 13 | [#832]: https://github.com/tokio-rs/tracing/pulls/832 14 | [#911]: https://github.com/tokio-rs/tracing/pulls/911 15 | [#913]: https://github.com/tokio-rs/tracing/pulls/913 16 | [#941]: https://github.com/tokio-rs/tracing/pulls/941 17 | [#953]: https://github.com/tokio-rs/tracing/pulls/953 18 | [#981]: https://github.com/tokio-rs/tracing/pulls/981 19 | # 0.2.4 (April 21, 2020) 20 | 21 | ### Fixed 22 | 23 | - docs.rs build failures (#618) 24 | - Spelling in documentation skins -> sinks (#643) 25 | 26 | # 0.2.3 (Feb 26, 2020) 27 | 28 | ### Added 29 | 30 | - `WithDispatch::inner` and `WithDispatch::inner_mut` methods to allow borrowing 31 | the wrapped type (#589) 32 | - `WithDispatch::with_dispatch` method, to propagate the subscriber to another 33 | type (#589) 34 | - `inner_pin_ref` and `inner_pin_mut` methods to `Instrumented` and 35 | `WithDispatch` to project to the inner future when pinned (#590) 36 | 37 | # 0.2.2 (Feb 14, 2020) 38 | 39 | ### Added 40 | 41 | - Support for `futures` 0.3 `Stream`s and `Sink`s (#544) 42 | 43 | ### Fixed 44 | 45 | - Compilation errors when using the `futures-03` feature (#576) 46 | 47 | Thanks to @obergner and @najamelan for their contributions to this release! 48 | 49 | # 0.2.1 (Jan 15, 2020) 50 | 51 | ### Added 52 | 53 | - API documentation now shows which features are required by feature-flagged items (#523) 54 | - `no_std` support (#498) 55 | 56 | # 0.2.0 (Dec 3, 2019) 57 | 58 | ### Changed 59 | 60 | - **Breaking Change**: the default `Future` implementation comes from the `std-future` feature. 61 | Compatibility with futures v0.1 is available via the `futures-01` feature. 62 | 63 | # 0.1.1 (Oct 25, 2019) 64 | 65 | ### Added 66 | 67 | - `Instrumented::inner` and `inner_mut` methods that expose access to the 68 | instrumented future (#386) 69 | 70 | # 0.1.0 (Oct 8, 2019) 71 | 72 | - Initial release 73 | -------------------------------------------------------------------------------- /tracing-futures/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-futures" 3 | version = "0.2.5" 4 | authors = ["Eliza Weisman ", "Tokio Contributors "] 5 | edition = "2018" 6 | repository = "https://github.com/tokio-rs/tracing" 7 | readme = "README.md" 8 | homepage = "https://tokio.rs" 9 | description = """ 10 | Utilities for instrumenting `futures` with `tracing`. 11 | """ 12 | categories = [ 13 | "development-tools::debugging", 14 | "development-tools::profiling", 15 | "asynchronous", 16 | ] 17 | keywords = ["logging", "profiling", "tracing", "futures", "async"] 18 | license = "MIT" 19 | rust-version = "1.65.0" 20 | 21 | [features] 22 | default = ["std-future", "std"] 23 | futures-01 = ["futures_01", "std"] 24 | futures-03 = ["std-future", "futures", "futures-task", "std"] 25 | std-future = ["pin-project-lite"] 26 | tokio = ["tokio_01"] 27 | std = ["tracing/std"] 28 | 29 | [dependencies] 30 | futures_01 = { package = "futures", version = "0.1.31", optional = true } 31 | futures = { version = "0.3.21", optional = true } 32 | futures-task = { version = "0.3.21", optional = true } 33 | pin-project-lite = { version = "0.2.9", optional = true } 34 | tracing = { path = "../tracing", version = "0.1.35", default-features = false } 35 | tokio-executor = { version = "0.1.10", optional = true } 36 | tokio_01 = { package = "tokio", version = "0.1.22", optional = true } 37 | 38 | # Fix minimal-versions 39 | tokio-threadpool = { version = "0.1.18", optional = true } 40 | mio = { version = "0.6.23", optional = true } 41 | 42 | [dev-dependencies] 43 | futures = "0.3.21" 44 | tokio-test = "0.4.2" 45 | tracing-core = { path = "../tracing-core", version = "0.1.28" } 46 | tracing-mock = { path = "../tracing-mock" } 47 | tracing-test = { path = "../tracing-test" } 48 | 49 | [badges] 50 | maintenance = { status = "actively-developed" } 51 | 52 | [package.metadata.docs.rs] 53 | all-features = true 54 | rustdoc-args = ["--cfg", "docsrs"] 55 | 56 | [lints] 57 | workspace = true 58 | -------------------------------------------------------------------------------- /tracing-futures/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-futures/src/executor/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "futures-01")] 2 | mod futures_01; 3 | 4 | #[cfg(feature = "futures-03")] 5 | mod futures_03; 6 | #[allow(unreachable_pub, unused_imports)] 7 | #[cfg(feature = "futures-03")] 8 | pub use futures_03::*; 9 | -------------------------------------------------------------------------------- /tracing-futures/src/stdlib.rs: -------------------------------------------------------------------------------- 1 | //! Re-exports either the Rust `std` library or `core` and `alloc` when `std` is 2 | //! disabled. 3 | //! 4 | //! `crate::stdlib::...` should be used rather than `std::` when adding code that 5 | //! will be available with the standard library disabled. 6 | //! 7 | //! Note that this module is called `stdlib` rather than `std`, as Rust 1.34.0 8 | //! does not permit redefining the name `stdlib` (although this works on the 9 | //! latest stable Rust). 10 | #[cfg(feature = "std")] 11 | pub(crate) use std::*; 12 | 13 | #[cfg(not(feature = "std"))] 14 | pub(crate) use self::no_std::*; 15 | 16 | #[cfg(not(feature = "std"))] 17 | mod no_std { 18 | // We pre-emptively export everything from libcore/liballoc, (even modules 19 | // we aren't using currently) to make adding new code easier. Therefore, 20 | // some of these imports will be unused. 21 | #![allow(unused_imports)] 22 | 23 | pub(crate) use core::{ 24 | any, array, ascii, cell, char, clone, cmp, convert, default, f32, f64, ffi, future, hash, 25 | hint, i128, i16, i8, isize, iter, marker, mem, num, ops, option, pin, ptr, result, task, 26 | time, u128, u16, u32, u8, usize, 27 | }; 28 | 29 | pub(crate) mod borrow { 30 | pub(crate) use core::borrow::*; 31 | } 32 | 33 | pub(crate) mod fmt { 34 | pub(crate) use core::fmt::*; 35 | } 36 | 37 | pub(crate) mod slice { 38 | pub(crate) use core::slice::*; 39 | } 40 | 41 | pub(crate) mod str { 42 | pub(crate) use core::str::*; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tracing-journald/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-journald" 3 | version = "0.3.1" 4 | authors = ["Benjamin Saunders "] 5 | edition = "2018" 6 | license = "MIT" 7 | readme = "README.md" 8 | repository = "https://github.com/tokio-rs/tracing" 9 | homepage = "https://tokio.rs" 10 | description = "rich journald subscriber for `tracing`" 11 | categories = [ 12 | "development-tools::debugging", 13 | "development-tools::profiling", 14 | ] 15 | keywords = ["tracing", "journald"] 16 | rust-version = "1.65.0" 17 | 18 | [dependencies] 19 | libc = "0.2.126" 20 | tracing-core = { path = "../tracing-core", version = "0.1.28" } 21 | tracing-subscriber = { path = "../tracing-subscriber", version = "0.3.0", default-features = false, features = ["registry"] } 22 | 23 | [dev-dependencies] 24 | serde_json = "1.0.82" 25 | serde = { version = "1.0.140", features = ["derive"] } 26 | tracing = { path = "../tracing", version = "0.1.35" } 27 | 28 | [lints] 29 | workspace = true 30 | -------------------------------------------------------------------------------- /tracing-journald/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-journald/src/memfd.rs: -------------------------------------------------------------------------------- 1 | //! memfd helpers. 2 | 3 | use libc::*; 4 | use std::fs::File; 5 | use std::io::Error; 6 | use std::io::Result; 7 | use std::os::raw::c_uint; 8 | use std::os::unix::prelude::{FromRawFd, RawFd}; 9 | 10 | fn create(flags: c_uint) -> Result { 11 | let fd = memfd_create_syscall(flags); 12 | if fd < 0 { 13 | Err(Error::last_os_error()) 14 | } else { 15 | Ok(unsafe { File::from_raw_fd(fd as RawFd) }) 16 | } 17 | } 18 | 19 | /// Make the `memfd_create` syscall ourself instead of going through `libc`; 20 | /// `memfd_create` isn't supported on `glibc<2.27` so this allows us to 21 | /// support old-but-still-used distros like Ubuntu Xenial, Debian Stretch, 22 | /// RHEL 7, etc. 23 | /// 24 | /// See: https://github.com/tokio-rs/tracing/issues/1879 25 | fn memfd_create_syscall(flags: c_uint) -> c_int { 26 | unsafe { 27 | syscall( 28 | SYS_memfd_create, 29 | "tracing-journald\0".as_ptr() as *const c_char, 30 | flags, 31 | ) as c_int 32 | } 33 | } 34 | 35 | pub fn create_sealable() -> Result { 36 | create(MFD_ALLOW_SEALING | MFD_CLOEXEC) 37 | } 38 | 39 | pub fn seal_fully(fd: RawFd) -> Result<()> { 40 | let all_seals = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL; 41 | let result = unsafe { fcntl(fd, F_ADD_SEALS, all_seals) }; 42 | if result < 0 { 43 | Err(Error::last_os_error()) 44 | } else { 45 | Ok(()) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tracing-log/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-log" 3 | version = "0.2.0" 4 | authors = ["Tokio Contributors "] 5 | edition = "2018" 6 | repository = "https://github.com/tokio-rs/tracing" 7 | homepage = "https://tokio.rs" 8 | description = """ 9 | Provides compatibility between `tracing` and the `log` crate. 10 | """ 11 | categories = [ 12 | "development-tools::debugging", 13 | "asynchronous", 14 | ] 15 | keywords = ["logging", "tracing", "log"] 16 | license = "MIT" 17 | readme = "README.md" 18 | rust-version = "1.65.0" 19 | 20 | [features] 21 | default = ["log-tracer", "std"] 22 | std = ["log/std"] 23 | log-tracer = [] 24 | interest-cache = ["lru", "ahash"] 25 | 26 | [dependencies] 27 | tracing-core = { path = "../tracing-core", version = "0.1.28"} 28 | log = { version = "0.4.17" } 29 | once_cell = "1.13.0" 30 | lru = { version = "0.7.7", optional = true } 31 | ahash = { version = "0.7.7", optional = true } 32 | 33 | [dev-dependencies] 34 | tracing = { path = "../tracing", version = "0.1.35"} 35 | tracing-subscriber = { path = "../tracing-subscriber" } 36 | criterion = { version = "0.3.6", default-features = false } 37 | 38 | [badges] 39 | maintenance = { status = "actively-maintained" } 40 | 41 | [package.metadata.docs.rs] 42 | all-features = true 43 | rustdoc-args = ["--cfg", "docsrs"] 44 | 45 | [[bench]] 46 | name = "logging" 47 | harness = false 48 | 49 | [lints] 50 | workspace = true 51 | -------------------------------------------------------------------------------- /tracing-log/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-log/tests/reexport_log_crate.rs: -------------------------------------------------------------------------------- 1 | use tracing_log::{log::LevelFilter, LogTracer}; 2 | 3 | /// This test makes sure we can access `log::LevelFilter` through the `tracing_log` crate and don't 4 | /// have to depend on `log` separately. 5 | /// 6 | /// See https://github.com/tokio-rs/tracing/issues/552. 7 | #[test] 8 | fn can_initialize_log_tracer_with_level() { 9 | LogTracer::init_with_filter(LevelFilter::Error).unwrap(); 10 | } 11 | -------------------------------------------------------------------------------- /tracing-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-macros" 3 | version = "0.1.0" 4 | authors = ["Eliza Weisman "] 5 | edition = "2018" 6 | repository = "https://github.com/tokio-rs/tracing" 7 | homepage = "https://tokio.rs" 8 | description = """ 9 | Macros for emitting trace events 10 | """ 11 | categories = [ 12 | "development-tools::debugging", 13 | "development-tools::profiling", 14 | "asynchronous", 15 | ] 16 | keywords = ["logging", "tracing"] 17 | license = "MIT" 18 | rust-version = "1.65.0" 19 | 20 | [dependencies] 21 | tracing = { path = "../tracing", version = "0.1.35" } 22 | 23 | [dev-dependencies] 24 | tracing-subscriber = { path = "../tracing-subscriber", version = "0.3.0", features = ["env-filter"] } 25 | 26 | [badges] 27 | maintenance = { status = "experimental" } 28 | 29 | [lints] 30 | workspace = true 31 | -------------------------------------------------------------------------------- /tracing-macros/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-macros/examples/factorial.rs: -------------------------------------------------------------------------------- 1 | //! Compare to the example given in the documentation for the `std::dbg` macro. 2 | #![deny(rust_2018_idioms)] 3 | 4 | use tracing_macros::dbg; 5 | use tracing_subscriber::{fmt, layer::SubscriberExt, EnvFilter}; 6 | 7 | fn factorial(n: u32) -> u32 { 8 | if dbg!(n <= 1) { 9 | dbg!(1) 10 | } else { 11 | dbg!(n * factorial(n - 1)) 12 | } 13 | } 14 | 15 | fn main() { 16 | let subscriber = tracing_subscriber::registry() 17 | .with(EnvFilter::from_default_env().add_directive(tracing::Level::TRACE.into())) 18 | .with(fmt::Layer::new()); 19 | 20 | tracing::subscriber::set_global_default(subscriber).expect("Unable to set a global subscriber"); 21 | dbg!(factorial(4)); 22 | } 23 | -------------------------------------------------------------------------------- /tracing-macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))] 2 | #[doc(hidden)] 3 | pub use tracing; 4 | 5 | /// Alias of `dbg!` for avoiding conflicts with the `std::dbg!` macro. 6 | #[macro_export] 7 | macro_rules! trace_dbg { 8 | (target: $target:expr, level: $level:expr, $ex:expr) => { 9 | $crate::dbg!(target: $target, level: $level, $ex) 10 | }; 11 | (level: $level:expr, $ex:expr) => { 12 | $crate::dbg!(target: module_path!(), level: $level, $ex) 13 | }; 14 | (target: $target:expr, $ex:expr) => { 15 | $crate::dbg!(target: $target, level: $crate::tracing::Level::DEBUG, $ex) 16 | }; 17 | ($ex:expr) => { 18 | $crate::dbg!(level: $crate::tracing::Level::DEBUG, $ex) 19 | }; 20 | } 21 | 22 | /// Similar to the `std::dbg!` macro, but generates `tracing` events rather 23 | /// than printing to stdout. 24 | /// 25 | /// By default, the verbosity level for the generated events is `DEBUG`, but 26 | /// this can be customized. 27 | #[macro_export] 28 | macro_rules! dbg { 29 | (target: $target:expr, level: $level:expr, $ex:expr) => {{ 30 | match $ex { 31 | value => { 32 | $crate::tracing::event!(target: $target, $level, ?value, stringify!($ex)); 33 | value 34 | } 35 | } 36 | }}; 37 | (level: $level:expr, $ex:expr) => { 38 | $crate::dbg!(target: module_path!(), level: $level, $ex) 39 | }; 40 | (target: $target:expr, $ex:expr) => { 41 | $crate::dbg!(target: $target, level: $crate::tracing::Level::DEBUG, $ex) 42 | }; 43 | ($ex:expr) => { 44 | $crate::dbg!(level: $crate::tracing::Level::DEBUG, $ex) 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /tracing-mock/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.0-beta.1 (November 29, 2024) 2 | 3 | [ [crates.io][crate-0.1.0-beta.1] ] | [ [docs.rs][docs-0.1.0-beta.1] ] 4 | 5 | `tracing-mock` provides tools for making assertions about what `tracing` 6 | diagnostics are emitted by code under test. 7 | 8 | - Initial beta release 9 | 10 | [docs-0.1.0-beta.1]: https://docs.rs/tracing-mock/0.1.0-beta.1 11 | [crate-0.1.0-beta.1]: https://crates.io/crates/tracing-mock/0.1.0-beta.1 12 | -------------------------------------------------------------------------------- /tracing-mock/Cargo.toml: -------------------------------------------------------------------------------- 1 | ## BIG SCARY NOTE 2 | # This Cargo.toml does not match the repo conventions YET 3 | # Before releasing to crates.io: make it so! 4 | 5 | [package] 6 | name = "tracing-mock" 7 | version = "0.1.0-beta.1" 8 | authors = [ 9 | "Eliza Weisman ", 10 | "Hayden Stainsby ", 11 | "Tokio Contributors ", 12 | ] 13 | license = "MIT" 14 | readme = "README.md" 15 | repository = "https://github.com/tokio-rs/tracing" 16 | homepage = "https://tokio.rs" 17 | description = """ 18 | Utilities for testing `tracing` and crates that uses it. 19 | """ 20 | categories = [ 21 | "development-tools::testing" 22 | ] 23 | keywords = [ 24 | "tracing", 25 | "mock", 26 | "testing" 27 | ] 28 | edition = "2018" 29 | rust-version = "1.65.0" 30 | 31 | [dependencies] 32 | tracing = { path = "../tracing", version = "0.1.41", features = ["std", "attributes"], default-features = false } 33 | tracing-core = { path = "../tracing-core", version = "0.1.28", default-features = false } 34 | tracing-subscriber = { path = "../tracing-subscriber", version = "0.3", default-features = false, features = ["registry"], optional = true } 35 | 36 | # Fix minimal-versions; tokio-test fails with otherwise acceptable 0.1.0 37 | tokio-stream = { version = "0.1.9", optional = true } 38 | 39 | [package.metadata.docs.rs] 40 | all-features = true 41 | rustdoc-args = ["--cfg", "docsrs"] 42 | 43 | [lints] 44 | workspace = true 45 | -------------------------------------------------------------------------------- /tracing-mock/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-mock/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![cfg_attr( 3 | docsrs, 4 | // Allows displaying cfgs/feature flags in the documentation. 5 | feature(doc_cfg), 6 | // Fail the docs build if any intra-docs links are broken 7 | deny(rustdoc::broken_intra_doc_links), 8 | )] 9 | #![doc( 10 | html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/main/assets/logo-type.png", 11 | html_favicon_url = "https://raw.githubusercontent.com/tokio-rs/tracing/main/assets/favicon.ico", 12 | issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/" 13 | )] 14 | #![warn( 15 | missing_debug_implementations, 16 | missing_docs, 17 | rust_2018_idioms, 18 | unreachable_pub, 19 | bad_style, 20 | dead_code, 21 | improper_ctypes, 22 | non_shorthand_field_patterns, 23 | no_mangle_generic_items, 24 | overflowing_literals, 25 | path_statements, 26 | patterns_in_fns_without_body, 27 | private_interfaces, 28 | private_bounds, 29 | unconditional_recursion, 30 | unused, 31 | unused_allocation, 32 | unused_comparisons, 33 | unused_parens, 34 | while_true 35 | )] 36 | 37 | pub mod ancestry; 38 | pub mod event; 39 | pub mod expect; 40 | pub mod field; 41 | mod metadata; 42 | pub mod span; 43 | pub mod subscriber; 44 | 45 | #[cfg(feature = "tracing-subscriber")] 46 | pub mod layer; 47 | -------------------------------------------------------------------------------- /tracing-serde/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.2.0 (November 27, 2024) 2 | 3 | [ [crates.io][crate-0.2.0] ] | [ [docs.rs][docs-0.2.0] ] 4 | 5 | 6 | ### Breaking Changes 7 | 8 | - Correct SerializeField definition and doc formatting ([#3040]) 9 | `SerializeField` has gained a generic lifetime parameter. 10 | 11 | ### Fixed 12 | 13 | - Implement `AsSerde` for `FieldSet` ([#2241]) 14 | - [**breaking**](#0.2.0-breaking) Correct SerializeField definition and doc formatting ([#3040]) 15 | 16 | ### Changed 17 | 18 | - Bump MSRV to 1.63 ([#2793]) 19 | 20 | [#2241]: https://github.com/tokio-rs/tracing/pull/2241 21 | [#3040]: https://github.com/tokio-rs/tracing/pull/3040 22 | [docs-0.2.0]: https://docs.rs/tracing-serde/0.2.0/tracing-serde/ 23 | [crate-0.2.0]: https://crates.io/crates/tracing-serde/0.2.0 24 | 25 | # 0.1.3 (February 4, 2022) 26 | 27 | This release adds *experimental* support for recording structured field 28 | values using the [`valuable`] crate. See [this blog post][post] for 29 | details on `valuable`. 30 | 31 | Note that `valuable` support currently requires `--cfg 32 | tracing_unstable`. See the documentation for details. 33 | 34 | ### Added 35 | 36 | - **valuable**: Experimental support for serializing user-defined types using 37 | [`valuable`] and [`valuable-serde`] ([#1862]) 38 | - Support for serializing `f64` values ([#1507]) 39 | 40 | ### Fixed 41 | 42 | - Fixed incorrect size hint in `SerializeFieldSet` ([#1333]) 43 | - A number of documentation fixes 44 | 45 | Thanks to @akinnane and @maxburke for contributing to this release! 46 | 47 | [`valuable`]: https://crates.io/crates/valuable 48 | [`valuable-serde`]: https://crates.io/crates/valuable-serde 49 | [post]: https://tokio.rs/blog/2021-05-valuable 50 | [#1862]: https://github.com/tokio-rs/tracing/pull/1862 51 | [#1507]: https://github.com/tokio-rs/tracing/pull/1507 52 | [#1333]: https://github.com/tokio-rs/tracing/pull/1333 53 | 54 | # 0.1.2 (September 11, 2020) 55 | 56 | ### Added 57 | 58 | - `SerdeMapVisitor::finish` to complete serializing the visited objects 59 | (#892) 60 | - `SerdeMapVisitor::take_serializer` to return the serializer wrapped by 61 | a `SerdeMapVisitor` (#892) 62 | 63 | # 0.1.1 (February 27, 2020) 64 | 65 | ### Added 66 | 67 | - Made `SerdeMapVisitor` public (#599) 68 | - Made `SerdeStructVisitor` public (#599) 69 | 70 | # 0.1.0 (November 18, 2019) 71 | 72 | - Initial release 73 | -------------------------------------------------------------------------------- /tracing-serde/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-serde" 3 | version = "0.2.0" 4 | authors = ["Tokio Contributors "] 5 | license = "MIT" 6 | edition = "2018" 7 | repository = "https://github.com/tokio-rs/tracing" 8 | homepage = "https://tokio.rs" 9 | description = """ 10 | A compatibility layer for serializing trace data with `serde` 11 | """ 12 | categories = [ 13 | "development-tools::debugging", 14 | "development-tools::profiling", 15 | "asynchronous", 16 | "encoding", 17 | ] 18 | keywords = ["logging", "tracing", "serialization"] 19 | rust-version = "1.65.0" 20 | 21 | [features] 22 | valuable = ["valuable_crate", "valuable-serde", "tracing-core/valuable"] 23 | 24 | [dependencies] 25 | serde = "1" 26 | tracing-core = { path = "../tracing-core", version = "0.1.28"} 27 | 28 | [dev-dependencies] 29 | serde_json = "1" 30 | 31 | [target.'cfg(tracing_unstable)'.dependencies] 32 | valuable_crate = { package = "valuable", version = "0.1.0", optional = true, default-features = false } 33 | valuable-serde = { version = "0.1.0", optional = true, default-features = false } 34 | 35 | [badges] 36 | maintenance = { status = "experimental" } 37 | 38 | [lints] 39 | workspace = true 40 | -------------------------------------------------------------------------------- /tracing-serde/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-serde/src/fields.rs: -------------------------------------------------------------------------------- 1 | //! Support for serializing fields as `serde` structs or maps. 2 | use super::*; 3 | 4 | #[derive(Debug)] 5 | pub struct SerializeFieldMap<'a, T>(&'a T); 6 | 7 | pub trait AsMap: Sized + sealed::Sealed { 8 | fn field_map(&self) -> SerializeFieldMap<'_, Self> { 9 | SerializeFieldMap(self) 10 | } 11 | } 12 | 13 | impl AsMap for Event<'_> {} 14 | impl AsMap for Attributes<'_> {} 15 | impl AsMap for Record<'_> {} 16 | 17 | // === impl SerializeFieldMap === 18 | 19 | impl Serialize for SerializeFieldMap<'_, Event<'_>> { 20 | fn serialize(&self, serializer: S) -> Result 21 | where 22 | S: Serializer, 23 | { 24 | let len = self.0.fields().count(); 25 | let serializer = serializer.serialize_map(Some(len))?; 26 | let mut visitor = SerdeMapVisitor::new(serializer); 27 | self.0.record(&mut visitor); 28 | visitor.finish() 29 | } 30 | } 31 | 32 | impl Serialize for SerializeFieldMap<'_, Attributes<'_>> { 33 | fn serialize(&self, serializer: S) -> Result 34 | where 35 | S: Serializer, 36 | { 37 | let len = self.0.metadata().fields().len(); 38 | let serializer = serializer.serialize_map(Some(len))?; 39 | let mut visitor = SerdeMapVisitor::new(serializer); 40 | self.0.record(&mut visitor); 41 | visitor.finish() 42 | } 43 | } 44 | 45 | impl Serialize for SerializeFieldMap<'_, Record<'_>> { 46 | fn serialize(&self, serializer: S) -> Result 47 | where 48 | S: Serializer, 49 | { 50 | let serializer = serializer.serialize_map(None)?; 51 | let mut visitor = SerdeMapVisitor::new(serializer); 52 | self.0.record(&mut visitor); 53 | visitor.finish() 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tracing-subscriber/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-subscriber/benches/enter.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | use tracing_subscriber::prelude::*; 3 | 4 | fn enter(c: &mut Criterion) { 5 | let mut group = c.benchmark_group("enter"); 6 | let _subscriber = tracing_subscriber::fmt() 7 | .with_max_level(tracing::Level::INFO) 8 | .finish() 9 | .set_default(); 10 | group.bench_function("enabled", |b| { 11 | let span = tracing::info_span!("foo"); 12 | b.iter_with_large_drop(|| span.enter()) 13 | }); 14 | group.bench_function("disabled", |b| { 15 | let span = tracing::debug_span!("foo"); 16 | b.iter_with_large_drop(|| span.enter()) 17 | }); 18 | } 19 | 20 | fn enter_exit(c: &mut Criterion) { 21 | let mut group = c.benchmark_group("enter_exit"); 22 | let _subscriber = tracing_subscriber::fmt() 23 | .with_max_level(tracing::Level::INFO) 24 | .finish() 25 | .set_default(); 26 | group.bench_function("enabled", |b| { 27 | let span = tracing::info_span!("foo"); 28 | b.iter(|| span.enter()) 29 | }); 30 | group.bench_function("disabled", |b| { 31 | let span = tracing::debug_span!("foo"); 32 | b.iter(|| span.enter()) 33 | }); 34 | } 35 | 36 | fn enter_many(c: &mut Criterion) { 37 | let mut group = c.benchmark_group("enter_many"); 38 | let _subscriber = tracing_subscriber::fmt() 39 | .with_max_level(tracing::Level::INFO) 40 | .finish() 41 | .set_default(); 42 | group.bench_function("enabled", |b| { 43 | let span1 = tracing::info_span!("span1"); 44 | let _e1 = span1.enter(); 45 | let span2 = tracing::info_span!("span2"); 46 | let _e2 = span2.enter(); 47 | let span3 = tracing::info_span!("span3"); 48 | let _e3 = span3.enter(); 49 | let span = tracing::info_span!("foo"); 50 | b.iter_with_large_drop(|| span.enter()) 51 | }); 52 | group.bench_function("disabled", |b| { 53 | let span1 = tracing::info_span!("span1"); 54 | let _e1 = span1.enter(); 55 | let span2 = tracing::info_span!("span2"); 56 | let _e2 = span2.enter(); 57 | let span3 = tracing::info_span!("span3"); 58 | let _e3 = span3.enter(); 59 | let span = tracing::debug_span!("foo"); 60 | b.iter_with_large_drop(|| span.enter()) 61 | }); 62 | } 63 | criterion_group!(benches, enter, enter_exit, enter_many); 64 | criterion_main!(benches); 65 | -------------------------------------------------------------------------------- /tracing-subscriber/benches/support/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | sync::{Arc, Barrier}, 3 | thread, 4 | time::{Duration, Instant}, 5 | }; 6 | use tracing::dispatcher::Dispatch; 7 | 8 | #[derive(Clone)] 9 | pub(super) struct MultithreadedBench { 10 | start: Arc, 11 | end: Arc, 12 | dispatch: Dispatch, 13 | } 14 | 15 | impl MultithreadedBench { 16 | pub(super) fn new(dispatch: Dispatch) -> Self { 17 | Self { 18 | start: Arc::new(Barrier::new(5)), 19 | end: Arc::new(Barrier::new(5)), 20 | dispatch, 21 | } 22 | } 23 | 24 | pub(super) fn thread(&self, f: impl FnOnce() + Send + 'static) -> &Self { 25 | self.thread_with_setup(|start| { 26 | start.wait(); 27 | f() 28 | }) 29 | } 30 | 31 | pub(super) fn thread_with_setup(&self, f: impl FnOnce(&Barrier) + Send + 'static) -> &Self { 32 | let this = self.clone(); 33 | thread::spawn(move || { 34 | let dispatch = this.dispatch.clone(); 35 | tracing::dispatcher::with_default(&dispatch, move || { 36 | f(&this.start); 37 | this.end.wait(); 38 | }) 39 | }); 40 | self 41 | } 42 | 43 | pub(super) fn run(&self) -> Duration { 44 | self.start.wait(); 45 | let t0 = Instant::now(); 46 | self.end.wait(); 47 | t0.elapsed() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tracing-subscriber/src/filter/level.rs: -------------------------------------------------------------------------------- 1 | use tracing_core::{ 2 | subscriber::{Interest, Subscriber}, 3 | Metadata, 4 | }; 5 | 6 | #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 7 | pub use tracing_core::metadata::{LevelFilter, ParseLevelFilterError as ParseError}; 8 | 9 | // === impl LevelFilter === 10 | 11 | impl crate::Layer for LevelFilter { 12 | fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest { 13 | if self >= metadata.level() { 14 | Interest::always() 15 | } else { 16 | Interest::never() 17 | } 18 | } 19 | 20 | fn enabled(&self, metadata: &Metadata<'_>, _: crate::layer::Context<'_, S>) -> bool { 21 | self >= metadata.level() 22 | } 23 | 24 | fn max_level_hint(&self) -> Option { 25 | Some(*self) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tracing-subscriber/src/filter/mod.rs: -------------------------------------------------------------------------------- 1 | //! [`Layer`]s that control which spans and events are enabled by the wrapped 2 | //! subscriber. 3 | //! 4 | //! This module contains a number of types that provide implementations of 5 | //! various strategies for filtering which spans and events are enabled. For 6 | //! details on filtering spans and events using [`Layer`]s, see the 7 | //! [`layer` module's documentation]. 8 | //! 9 | //! [`layer` module's documentation]: crate::layer#filtering-with-layers 10 | //! [`Layer`]: crate::layer 11 | mod filter_fn; 12 | 13 | feature! { 14 | #![all(feature = "env-filter", feature = "std")] 15 | mod env; 16 | pub use self::env::*; 17 | } 18 | 19 | feature! { 20 | #![all(feature = "registry", feature = "std")] 21 | mod layer_filters; 22 | pub use self::layer_filters::*; 23 | } 24 | 25 | mod level; 26 | 27 | pub use self::filter_fn::*; 28 | pub use self::level::{LevelFilter, ParseError as LevelParseError}; 29 | 30 | #[cfg(not(all(feature = "registry", feature = "std")))] 31 | pub(crate) use self::has_plf_stubs::*; 32 | 33 | feature! { 34 | #![any(feature = "std", feature = "alloc")] 35 | pub mod targets; 36 | pub use self::targets::Targets; 37 | 38 | mod directive; 39 | pub use self::directive::ParseError; 40 | } 41 | 42 | /// Stub implementations of the per-layer-filter detection functions for when the 43 | /// `registry` feature is disabled. 44 | #[cfg(not(all(feature = "registry", feature = "std")))] 45 | mod has_plf_stubs { 46 | pub(crate) fn is_plf_downcast_marker(_: core::any::TypeId) -> bool { 47 | false 48 | } 49 | 50 | /// Does a type implementing `Subscriber` contain any per-layer filters? 51 | pub(crate) fn subscriber_has_plf(_: &S) -> bool 52 | where 53 | S: tracing_core::Subscriber, 54 | { 55 | false 56 | } 57 | 58 | /// Does a type implementing `Layer` contain any per-layer filters? 59 | pub(crate) fn layer_has_plf(_: &L) -> bool 60 | where 61 | L: crate::Layer, 62 | S: tracing_core::Subscriber, 63 | { 64 | false 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tracing-subscriber/src/macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "std")] 2 | macro_rules! try_lock { 3 | ($lock:expr) => { 4 | try_lock!($lock, else return) 5 | }; 6 | ($lock:expr, else $els:expr) => { 7 | if let ::core::result::Result::Ok(l) = $lock { 8 | l 9 | } else if std::thread::panicking() { 10 | $els 11 | } else { 12 | panic!("lock poisoned") 13 | } 14 | }; 15 | } 16 | 17 | macro_rules! feature { 18 | ( 19 | #![$meta:meta] 20 | $($item:item)* 21 | ) => { 22 | $( 23 | #[cfg($meta)] 24 | #[cfg_attr(docsrs, doc(cfg($meta)))] 25 | $item 26 | )* 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tracing-subscriber/src/prelude.rs: -------------------------------------------------------------------------------- 1 | //! The `tracing-subscriber` prelude. 2 | //! 3 | //! This brings into scope a number of extension traits that define methods on 4 | //! types defined here and in other crates. 5 | 6 | pub use crate::field::{ 7 | MakeExt as __tracing_subscriber_field_MakeExt, 8 | RecordFields as __tracing_subscriber_field_RecordFields, 9 | }; 10 | pub use crate::layer::{ 11 | Layer as __tracing_subscriber_Layer, SubscriberExt as __tracing_subscriber_SubscriberExt, 12 | }; 13 | 14 | pub use crate::util::SubscriberInitExt as _; 15 | 16 | feature! { 17 | #![all(feature = "fmt", feature = "std")] 18 | pub use crate::fmt::writer::MakeWriterExt as _; 19 | } 20 | -------------------------------------------------------------------------------- /tracing-subscriber/src/registry/stack.rs: -------------------------------------------------------------------------------- 1 | pub(crate) use tracing_core::span::Id; 2 | 3 | #[derive(Debug)] 4 | struct ContextId { 5 | id: Id, 6 | duplicate: bool, 7 | } 8 | 9 | /// `SpanStack` tracks what spans are currently executing on a thread-local basis. 10 | /// 11 | /// A "separate current span" for each thread is a semantic choice, as each span 12 | /// can be executing in a different thread. 13 | #[derive(Debug, Default)] 14 | pub(crate) struct SpanStack { 15 | stack: Vec, 16 | } 17 | 18 | impl SpanStack { 19 | #[inline] 20 | pub(super) fn push(&mut self, id: Id) -> bool { 21 | let duplicate = self.stack.iter().any(|i| i.id == id); 22 | self.stack.push(ContextId { id, duplicate }); 23 | !duplicate 24 | } 25 | 26 | #[inline] 27 | pub(super) fn pop(&mut self, expected_id: &Id) -> bool { 28 | if let Some((idx, _)) = self 29 | .stack 30 | .iter() 31 | .enumerate() 32 | .rev() 33 | .find(|(_, ctx_id)| ctx_id.id == *expected_id) 34 | { 35 | let ContextId { id: _, duplicate } = self.stack.remove(idx); 36 | return !duplicate; 37 | } 38 | false 39 | } 40 | 41 | #[inline] 42 | pub(crate) fn iter(&self) -> impl Iterator { 43 | self.stack 44 | .iter() 45 | .rev() 46 | .filter_map(|ContextId { id, duplicate }| if !*duplicate { Some(id) } else { None }) 47 | } 48 | 49 | #[inline] 50 | pub(crate) fn current(&self) -> Option<&Id> { 51 | self.iter().next() 52 | } 53 | } 54 | 55 | #[cfg(test)] 56 | mod tests { 57 | use super::{Id, SpanStack}; 58 | 59 | #[test] 60 | fn pop_last_span() { 61 | let mut stack = SpanStack::default(); 62 | let id = Id::from_u64(1); 63 | stack.push(id.clone()); 64 | 65 | assert!(stack.pop(&id)); 66 | } 67 | 68 | #[test] 69 | fn pop_first_span() { 70 | let mut stack = SpanStack::default(); 71 | stack.push(Id::from_u64(1)); 72 | stack.push(Id::from_u64(2)); 73 | 74 | let id = Id::from_u64(1); 75 | assert!(stack.pop(&id)); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tracing-subscriber/src/sync.rs: -------------------------------------------------------------------------------- 1 | //! Abstracts over sync primitive implementations. 2 | //! 3 | //! Optionally, we allow the Rust standard library's `RwLock` to be replaced 4 | //! with the `parking_lot` crate's implementation. This may provide improved 5 | //! performance in some cases. However, the `parking_lot` dependency is an 6 | //! opt-in feature flag. Because `parking_lot::RwLock` has a slightly different 7 | //! API than `std::sync::RwLock` (it does not support poisoning on panics), we 8 | //! wrap it with a type that provides the same method signatures. This allows us 9 | //! to transparently swap `parking_lot` in without changing code at the callsite. 10 | #[allow(unused_imports)] // may be used later; 11 | pub(crate) use std::sync::{LockResult, PoisonError, TryLockResult}; 12 | 13 | #[cfg(not(feature = "parking_lot"))] 14 | pub(crate) use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; 15 | 16 | #[cfg(feature = "parking_lot")] 17 | pub(crate) use self::parking_lot_impl::*; 18 | 19 | #[cfg(feature = "parking_lot")] 20 | mod parking_lot_impl { 21 | pub(crate) use parking_lot::{RwLockReadGuard, RwLockWriteGuard}; 22 | use std::sync::{LockResult, TryLockError, TryLockResult}; 23 | 24 | #[derive(Debug)] 25 | pub(crate) struct RwLock { 26 | inner: parking_lot::RwLock, 27 | } 28 | 29 | impl RwLock { 30 | pub(crate) fn new(val: T) -> Self { 31 | Self { 32 | inner: parking_lot::RwLock::new(val), 33 | } 34 | } 35 | 36 | #[inline] 37 | pub(crate) fn get_mut(&mut self) -> LockResult<&mut T> { 38 | Ok(self.inner.get_mut()) 39 | } 40 | 41 | #[inline] 42 | pub(crate) fn read(&self) -> LockResult> { 43 | Ok(self.inner.read()) 44 | } 45 | 46 | #[inline] 47 | #[allow(dead_code)] // may be used later; 48 | pub(crate) fn try_read(&self) -> TryLockResult> { 49 | self.inner.try_read().ok_or(TryLockError::WouldBlock) 50 | } 51 | 52 | #[inline] 53 | pub(crate) fn write(&self) -> LockResult> { 54 | Ok(self.inner.write()) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/duplicate_spans.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "env-filter", feature = "fmt"))] 2 | use tracing::{self, subscriber::with_default, Span}; 3 | use tracing_subscriber::{filter::EnvFilter, FmtSubscriber}; 4 | 5 | #[test] 6 | fn duplicate_spans() { 7 | let subscriber = FmtSubscriber::builder() 8 | .with_env_filter(EnvFilter::new("[root]=debug")) 9 | .finish(); 10 | 11 | with_default(subscriber, || { 12 | let root = tracing::debug_span!("root"); 13 | root.in_scope(|| { 14 | // root: 15 | assert_eq!(root, Span::current(), "Current span must be 'root'"); 16 | let leaf = tracing::debug_span!("leaf"); 17 | leaf.in_scope(|| { 18 | // root:leaf: 19 | assert_eq!(leaf, Span::current(), "Current span must be 'leaf'"); 20 | root.in_scope(|| { 21 | // root:leaf: 22 | assert_eq!( 23 | leaf, 24 | Span::current(), 25 | "Current span must be 'leaf' after entering twice the 'root' span" 26 | ); 27 | }) 28 | }); 29 | // root: 30 | assert_eq!( 31 | root, 32 | Span::current(), 33 | "Current span must be root ('leaf' exited, nested 'root' exited)" 34 | ); 35 | 36 | root.in_scope(|| { 37 | assert_eq!(root, Span::current(), "Current span must be root"); 38 | }); 39 | // root: 40 | assert_eq!( 41 | root, 42 | Span::current(), 43 | "Current span must still be root after exiting nested 'root'" 44 | ); 45 | }); 46 | }); 47 | } 48 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/event_enabling.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "registry")] 2 | 3 | use std::sync::{Arc, Mutex}; 4 | use tracing::{subscriber::with_default, Event, Metadata, Subscriber}; 5 | use tracing_subscriber::{layer::Context, prelude::*, registry, Layer}; 6 | 7 | struct TrackingLayer { 8 | enabled: bool, 9 | event_enabled_count: Arc>, 10 | event_enabled: bool, 11 | on_event_count: Arc>, 12 | } 13 | 14 | impl Layer for TrackingLayer 15 | where 16 | C: Subscriber + Send + Sync + 'static, 17 | { 18 | fn enabled(&self, _metadata: &Metadata<'_>, _ctx: Context<'_, C>) -> bool { 19 | self.enabled 20 | } 21 | 22 | fn event_enabled(&self, _event: &Event<'_>, _ctx: Context<'_, C>) -> bool { 23 | *self.event_enabled_count.lock().unwrap() += 1; 24 | self.event_enabled 25 | } 26 | 27 | fn on_event(&self, _event: &Event<'_>, _ctx: Context<'_, C>) { 28 | *self.on_event_count.lock().unwrap() += 1; 29 | } 30 | } 31 | 32 | #[test] 33 | fn event_enabled_is_only_called_once() { 34 | let event_enabled_count = Arc::new(Mutex::default()); 35 | let count = event_enabled_count.clone(); 36 | let subscriber = registry().with(TrackingLayer { 37 | enabled: true, 38 | event_enabled_count, 39 | event_enabled: true, 40 | on_event_count: Arc::new(Mutex::default()), 41 | }); 42 | with_default(subscriber, || { 43 | tracing::error!("hiya!"); 44 | }); 45 | 46 | assert_eq!(1, *count.lock().unwrap()); 47 | } 48 | 49 | #[test] 50 | fn event_enabled_not_called_when_not_enabled() { 51 | let event_enabled_count = Arc::new(Mutex::default()); 52 | let count = event_enabled_count.clone(); 53 | let subscriber = registry().with(TrackingLayer { 54 | enabled: false, 55 | event_enabled_count, 56 | event_enabled: true, 57 | on_event_count: Arc::new(Mutex::default()), 58 | }); 59 | with_default(subscriber, || { 60 | tracing::error!("hiya!"); 61 | }); 62 | 63 | assert_eq!(0, *count.lock().unwrap()); 64 | } 65 | 66 | #[test] 67 | fn event_disabled_does_disable_event() { 68 | let on_event_count = Arc::new(Mutex::default()); 69 | let count = on_event_count.clone(); 70 | let subscriber = registry().with(TrackingLayer { 71 | enabled: true, 72 | event_enabled_count: Arc::new(Mutex::default()), 73 | event_enabled: false, 74 | on_event_count, 75 | }); 76 | with_default(subscriber, || { 77 | tracing::error!("hiya!"); 78 | }); 79 | 80 | assert_eq!(0, *count.lock().unwrap()); 81 | } 82 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/filter_log.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "env-filter", feature = "tracing-log"))] 2 | 3 | use tracing::{self, Level}; 4 | use tracing_mock::*; 5 | use tracing_subscriber::{filter::EnvFilter, prelude::*}; 6 | 7 | mod my_module { 8 | pub(crate) fn test_records() { 9 | log::trace!("this should be disabled"); 10 | log::info!("this shouldn't be"); 11 | log::debug!("this should be disabled"); 12 | log::warn!("this should be enabled"); 13 | log::warn!(target: "something else", "this shouldn't be enabled"); 14 | log::error!("this should be enabled too"); 15 | } 16 | 17 | pub(crate) fn test_log_enabled() { 18 | assert!( 19 | log::log_enabled!(log::Level::Info), 20 | "info should be enabled inside `my_module`" 21 | ); 22 | assert!( 23 | !log::log_enabled!(log::Level::Debug), 24 | "debug should not be enabled inside `my_module`" 25 | ); 26 | assert!( 27 | log::log_enabled!(log::Level::Warn), 28 | "warn should be enabled inside `my_module`" 29 | ); 30 | } 31 | } 32 | 33 | #[test] 34 | fn log_is_enabled() { 35 | let filter: EnvFilter = "filter_log::my_module=info" 36 | .parse() 37 | .expect("filter should parse"); 38 | let (subscriber, finished) = subscriber::mock() 39 | .event(expect::event().at_level(Level::INFO)) 40 | .event(expect::event().at_level(Level::WARN)) 41 | .event(expect::event().at_level(Level::ERROR)) 42 | .only() 43 | .run_with_handle(); 44 | 45 | // Note: we have to set the global default in order to set the `log` max 46 | // level, which can only be set once. 47 | subscriber.with(filter).init(); 48 | 49 | my_module::test_records(); 50 | log::info!("this is disabled"); 51 | 52 | my_module::test_log_enabled(); 53 | assert!( 54 | !log::log_enabled!(log::Level::Info), 55 | "info should not be enabled outside `my_module`" 56 | ); 57 | assert!( 58 | !log::log_enabled!(log::Level::Warn), 59 | "warn should not be enabled outside `my_module`" 60 | ); 61 | 62 | finished.assert_finished(); 63 | } 64 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/fmt_max_level_hint.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "fmt")] 2 | use tracing_subscriber::filter::LevelFilter; 3 | 4 | #[test] 5 | fn fmt_sets_max_level_hint() { 6 | tracing_subscriber::fmt() 7 | .with_max_level(LevelFilter::DEBUG) 8 | .init(); 9 | assert_eq!(LevelFilter::current(), LevelFilter::DEBUG); 10 | } 11 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/layer_filter_interests_are_cached.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "registry")] 2 | use std::{ 3 | collections::HashMap, 4 | sync::{Arc, Mutex}, 5 | }; 6 | use tracing::{Level, Subscriber}; 7 | use tracing_mock::{expect, layer}; 8 | use tracing_subscriber::{filter, prelude::*}; 9 | 10 | #[test] 11 | fn layer_filter_interests_are_cached() { 12 | let seen = Arc::new(Mutex::new(HashMap::new())); 13 | let seen2 = seen.clone(); 14 | let filter = filter::filter_fn(move |meta| { 15 | *seen 16 | .lock() 17 | .unwrap() 18 | .entry(meta.callsite()) 19 | .or_insert(0usize) += 1; 20 | meta.level() == &Level::INFO 21 | }); 22 | 23 | let (expect, handle) = layer::mock() 24 | .event(expect::event().at_level(Level::INFO)) 25 | .event(expect::event().at_level(Level::INFO)) 26 | .only() 27 | .run_with_handle(); 28 | 29 | let subscriber = tracing_subscriber::registry().with(expect.with_filter(filter)); 30 | assert!(subscriber.max_level_hint().is_none()); 31 | 32 | let _subscriber = subscriber.set_default(); 33 | 34 | fn events() { 35 | tracing::trace!("hello trace"); 36 | tracing::debug!("hello debug"); 37 | tracing::info!("hello info"); 38 | tracing::warn!("hello warn"); 39 | tracing::error!("hello error"); 40 | } 41 | 42 | events(); 43 | { 44 | let lock = seen2.lock().unwrap(); 45 | for (callsite, &count) in lock.iter() { 46 | assert_eq!( 47 | count, 1, 48 | "callsite {:?} should have been seen 1 time (after first set of events)", 49 | callsite 50 | ); 51 | } 52 | } 53 | 54 | events(); 55 | { 56 | let lock = seen2.lock().unwrap(); 57 | for (callsite, &count) in lock.iter() { 58 | assert_eq!( 59 | count, 1, 60 | "callsite {:?} should have been seen 1 time (after second set of events)", 61 | callsite 62 | ); 63 | } 64 | } 65 | 66 | handle.assert_finished(); 67 | } 68 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/layer_filters/boxed.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use tracing_mock::layer::MockLayer; 3 | use tracing_subscriber::{filter, prelude::*, Layer}; 4 | 5 | fn layer() -> (MockLayer, subscriber::MockHandle) { 6 | layer::mock().only().run_with_handle() 7 | } 8 | 9 | fn filter() -> filter::DynFilterFn { 10 | // Use dynamic filter fn to disable interest caching and max-level hints, 11 | // allowing us to put all of these tests in the same file. 12 | filter::dynamic_filter_fn(|_, _| false) 13 | } 14 | 15 | /// reproduces https://github.com/tokio-rs/tracing/issues/1563#issuecomment-921363629 16 | #[test] 17 | fn box_works() { 18 | let (layer, handle) = layer(); 19 | let layer = Box::new(layer.with_filter(filter())); 20 | 21 | let _guard = tracing_subscriber::registry().with(layer).set_default(); 22 | 23 | for i in 0..2 { 24 | tracing::info!(i); 25 | } 26 | 27 | handle.assert_finished(); 28 | } 29 | 30 | /// the same as `box_works` but with a type-erased `Box`. 31 | #[test] 32 | fn dyn_box_works() { 33 | let (layer, handle) = layer(); 34 | let layer: Box + Send + Sync + 'static> = Box::new(layer.with_filter(filter())); 35 | 36 | let _guard = tracing_subscriber::registry().with(layer).set_default(); 37 | 38 | for i in 0..2 { 39 | tracing::info!(i); 40 | } 41 | 42 | handle.assert_finished(); 43 | } 44 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/layer_filters/combinators.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use tracing_subscriber::{ 3 | filter::{filter_fn, FilterExt, LevelFilter}, 4 | prelude::*, 5 | }; 6 | 7 | #[test] 8 | fn and() { 9 | let (layer, handle) = layer::mock() 10 | .event( 11 | event::msg("a very interesting event") 12 | .at_level(tracing::Level::INFO) 13 | .with_target("interesting_target"), 14 | ) 15 | .only() 16 | .run_with_handle(); 17 | 18 | // Enables spans and events with targets starting with `interesting_target`: 19 | let target_filter = filter::filter_fn(|meta| meta.target().starts_with("interesting_target")); 20 | 21 | // Enables spans and events with levels `INFO` and below: 22 | let level_filter = LevelFilter::INFO; 23 | 24 | // Combine the two filters together, returning a filter that only enables 25 | // spans and events that *both* filters will enable: 26 | let filter = target_filter.and(level_filter); 27 | 28 | let _subscriber = tracing_subscriber::registry() 29 | .with(layer.with_filter(filter)) 30 | .set_default(); 31 | 32 | // This event will *not* be enabled: 33 | tracing::info!("an event with an uninteresting target"); 34 | 35 | // This event *will* be enabled: 36 | tracing::info!(target: "interesting_target", "a very interesting event"); 37 | 38 | // This event will *not* be enabled: 39 | tracing::debug!(target: "interesting_target", "interesting debug event..."); 40 | 41 | handle.assert_finished(); 42 | } 43 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/layer_filters/downcast_raw.rs: -------------------------------------------------------------------------------- 1 | use tracing::Subscriber; 2 | use tracing_subscriber::filter::Targets; 3 | use tracing_subscriber::prelude::*; 4 | use tracing_subscriber::Layer; 5 | 6 | #[test] 7 | fn downcast_ref_to_inner_layer_and_filter() { 8 | // Test that a filtered layer gives downcast_ref access to 9 | // both the layer and the filter. 10 | 11 | struct WrappedLayer; 12 | 13 | impl Layer for WrappedLayer 14 | where 15 | S: Subscriber, 16 | S: for<'lookup> tracing_subscriber::registry::LookupSpan<'lookup>, 17 | { 18 | } 19 | 20 | let layer = WrappedLayer; 21 | let filter = Targets::new().with_default(tracing::Level::INFO); 22 | let registry = tracing_subscriber::registry().with(layer.with_filter(filter)); 23 | let dispatch = tracing::dispatcher::Dispatch::new(registry); 24 | 25 | // The filter is available 26 | assert!(dispatch.downcast_ref::().is_some()); 27 | // The wrapped layer is available 28 | assert!(dispatch.downcast_ref::().is_some()); 29 | } 30 | 31 | #[test] 32 | fn forward_downcast_raw_to_layer() { 33 | // Test that a filtered layer still gives its wrapped layer a chance to 34 | // return a custom struct from downcast_raw. 35 | // https://github.com/tokio-rs/tracing/issues/1618 36 | 37 | struct WrappedLayer { 38 | with_context: WithContext, 39 | } 40 | 41 | struct WithContext; 42 | 43 | impl Layer for WrappedLayer 44 | where 45 | S: Subscriber, 46 | S: for<'lookup> tracing_subscriber::registry::LookupSpan<'lookup>, 47 | { 48 | unsafe fn downcast_raw(&self, id: std::any::TypeId) -> Option<*const ()> { 49 | match id { 50 | id if id == std::any::TypeId::of::() => Some(self as *const _ as *const ()), 51 | id if id == std::any::TypeId::of::() => { 52 | Some(&self.with_context as *const _ as *const ()) 53 | } 54 | _ => None, 55 | } 56 | } 57 | } 58 | 59 | let layer = WrappedLayer { 60 | with_context: WithContext, 61 | }; 62 | let filter = Targets::new().with_default(tracing::Level::INFO); 63 | let registry = tracing_subscriber::registry().with(layer.with_filter(filter)); 64 | let dispatch = tracing::dispatcher::Dispatch::new(registry); 65 | 66 | // Types from a custom implementation of `downcast_raw` are available 67 | assert!(dispatch.downcast_ref::().is_some()); 68 | } 69 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/layer_filters/per_event.rs: -------------------------------------------------------------------------------- 1 | use tracing::Level; 2 | use tracing_mock::{expect, layer}; 3 | use tracing_subscriber::{field::Visit, layer::Filter, prelude::*}; 4 | 5 | struct FilterEvent; 6 | 7 | impl Filter for FilterEvent { 8 | fn enabled( 9 | &self, 10 | _meta: &tracing::Metadata<'_>, 11 | _cx: &tracing_subscriber::layer::Context<'_, S>, 12 | ) -> bool { 13 | true 14 | } 15 | 16 | fn event_enabled( 17 | &self, 18 | event: &tracing::Event<'_>, 19 | _cx: &tracing_subscriber::layer::Context<'_, S>, 20 | ) -> bool { 21 | struct ShouldEnable(bool); 22 | impl Visit for ShouldEnable { 23 | fn record_bool(&mut self, field: &tracing_core::Field, value: bool) { 24 | if field.name() == "enable" { 25 | self.0 = value; 26 | } 27 | } 28 | 29 | fn record_debug( 30 | &mut self, 31 | _field: &tracing_core::Field, 32 | _value: &dyn core::fmt::Debug, 33 | ) { 34 | } 35 | } 36 | let mut should_enable = ShouldEnable(false); 37 | event.record(&mut should_enable); 38 | should_enable.0 39 | } 40 | } 41 | 42 | #[test] 43 | fn per_layer_event_field_filtering() { 44 | let (expect, handle) = layer::mock() 45 | .event(expect::event().at_level(Level::TRACE)) 46 | .event(expect::event().at_level(Level::INFO)) 47 | .only() 48 | .run_with_handle(); 49 | 50 | let _subscriber = tracing_subscriber::registry() 51 | .with(expect.with_filter(FilterEvent)) 52 | .set_default(); 53 | 54 | tracing::trace!(enable = true, "hello trace"); 55 | tracing::debug!("hello debug"); 56 | tracing::info!(enable = true, "hello info"); 57 | tracing::warn!(enable = false, "hello warn"); 58 | tracing::error!("hello error"); 59 | 60 | handle.assert_finished(); 61 | } 62 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/layer_filters/targets.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use tracing_subscriber::{ 3 | filter::{filter_fn, Targets}, 4 | prelude::*, 5 | }; 6 | 7 | #[test] 8 | #[cfg_attr(not(feature = "tracing-log"), ignore)] 9 | fn log_events() { 10 | // Reproduces https://github.com/tokio-rs/tracing/issues/1563 11 | mod inner { 12 | pub(super) const MODULE_PATH: &str = module_path!(); 13 | 14 | #[tracing::instrument] 15 | pub(super) fn logs() { 16 | log::debug!("inner"); 17 | } 18 | } 19 | 20 | let filter = Targets::new() 21 | .with_default(LevelFilter::DEBUG) 22 | .with_target(inner::MODULE_PATH, LevelFilter::WARN); 23 | 24 | let layer = 25 | tracing_subscriber::layer::Identity::new().with_filter(filter_fn(move |_meta| true)); 26 | 27 | let _guard = tracing_subscriber::registry() 28 | .with(filter) 29 | .with(layer) 30 | .set_default(); 31 | 32 | inner::logs(); 33 | } 34 | 35 | #[test] 36 | fn inner_layer_short_circuits() { 37 | // This test ensures that when a global filter short-circuits `Interest` 38 | // evaluation, we aren't left with a "dirty" per-layer filter state. 39 | 40 | let (layer, handle) = layer::mock() 41 | .event(expect::event().with_fields(expect::msg("hello world"))) 42 | .only() 43 | .run_with_handle(); 44 | 45 | let filter = Targets::new().with_target("magic_target", LevelFilter::DEBUG); 46 | 47 | let _guard = tracing_subscriber::registry() 48 | // Note: we don't just use a `LevelFilter` for the global filter here, 49 | // because it will just return a max level filter, and the chain of 50 | // `register_callsite` calls that would trigger the bug never happens... 51 | .with(filter::filter_fn(|meta| meta.level() <= &Level::INFO)) 52 | .with(layer.with_filter(filter)) 53 | .set_default(); 54 | 55 | tracing::debug!("skip me please!"); 56 | tracing::info!(target: "magic_target", "hello world"); 57 | 58 | handle.assert_finished(); 59 | } 60 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/option_filter_interest_caching.rs: -------------------------------------------------------------------------------- 1 | // A separate test crate for `Option` for isolation from other tests 2 | // that may influence the interest cache. 3 | 4 | use std::sync::{ 5 | atomic::{AtomicUsize, Ordering}, 6 | Arc, 7 | }; 8 | use tracing_mock::{expect, layer}; 9 | use tracing_subscriber::{filter, prelude::*, Layer}; 10 | 11 | /// A `None` filter should always be interested in events, and it should not 12 | /// needlessly degrade the caching of other filters. 13 | #[test] 14 | fn none_interest_cache() { 15 | let (layer_none, handle_none) = layer::mock() 16 | .event(expect::event()) 17 | .event(expect::event()) 18 | .only() 19 | .run_with_handle(); 20 | let layer_none = layer_none.with_filter(None::>); 21 | 22 | let times_filtered = Arc::new(AtomicUsize::new(0)); 23 | let (layer_filter_fn, handle_filter_fn) = layer::mock() 24 | .event(expect::event()) 25 | .event(expect::event()) 26 | .only() 27 | .run_with_handle(); 28 | let layer_filter_fn = layer_filter_fn.with_filter(filter::filter_fn({ 29 | let times_filtered = Arc::clone(×_filtered); 30 | move |_| { 31 | times_filtered.fetch_add(1, Ordering::Relaxed); 32 | true 33 | } 34 | })); 35 | 36 | let subscriber = tracing_subscriber::registry() 37 | .with(layer_none) 38 | .with(layer_filter_fn); 39 | 40 | let _guard = subscriber.set_default(); 41 | for _ in 0..2 { 42 | tracing::debug!(target: "always_interesting", x="bar"); 43 | } 44 | 45 | // The `None` filter is unchanging and performs no filtering, so it should 46 | // be cacheable and always be interested in events. The filter fn is a 47 | // non-dynamic filter fn, which means the result can be cached per callsite. 48 | // The filter fn should only need to be called once, and the `Option` filter 49 | // should not interfere in the caching of that result. 50 | assert_eq!(times_filtered.load(Ordering::Relaxed), 1); 51 | handle_none.assert_finished(); 52 | handle_filter_fn.assert_finished(); 53 | } 54 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/registry_max_level_hint.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "registry", feature = "fmt"))] 2 | use tracing_subscriber::{filter::LevelFilter, prelude::*}; 3 | 4 | #[test] 5 | fn registry_sets_max_level_hint() { 6 | tracing_subscriber::registry() 7 | .with(tracing_subscriber::fmt::layer()) 8 | .with(LevelFilter::DEBUG) 9 | .init(); 10 | assert_eq!(LevelFilter::current(), LevelFilter::DEBUG); 11 | } 12 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/registry_with_subscriber.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "registry")] 2 | use tracing_futures::{Instrument, WithSubscriber}; 3 | use tracing_subscriber::prelude::*; 4 | 5 | #[tokio::test] 6 | async fn future_with_subscriber() { 7 | tracing_subscriber::registry().init(); 8 | let span = tracing::info_span!("foo"); 9 | let _e = span.enter(); 10 | let span = tracing::info_span!("bar"); 11 | let _e = span.enter(); 12 | tokio::spawn( 13 | async { 14 | async { 15 | let span = tracing::Span::current(); 16 | println!("{:?}", span); 17 | } 18 | .instrument(tracing::info_span!("hi")) 19 | .await 20 | } 21 | .with_subscriber(tracing_subscriber::registry()), 22 | ) 23 | .await 24 | .unwrap(); 25 | } 26 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/reload_max_log_level.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "env-filter", feature = "tracing-log"))] 2 | 3 | use tracing::{self, Level}; 4 | use tracing_mock::{expect, subscriber}; 5 | use tracing_subscriber::{filter::LevelFilter, prelude::*, reload}; 6 | 7 | #[test] 8 | fn reload_max_log_level() { 9 | let (subscriber, finished) = subscriber::mock() 10 | .event(expect::event().at_level(Level::INFO)) 11 | .event(expect::event().at_level(Level::DEBUG)) 12 | .event(expect::event().at_level(Level::INFO)) 13 | .only() 14 | .run_with_handle(); 15 | let (filter, reload_handle) = reload::Layer::new(LevelFilter::INFO); 16 | subscriber.with(filter).init(); 17 | 18 | assert!(log::log_enabled!(log::Level::Info)); 19 | assert!(!log::log_enabled!(log::Level::Debug)); 20 | assert!(!log::log_enabled!(log::Level::Trace)); 21 | 22 | log::debug!("i'm disabled"); 23 | log::info!("i'm enabled"); 24 | 25 | reload_handle 26 | .reload(Level::DEBUG) 27 | .expect("reloading succeeds"); 28 | 29 | assert!(log::log_enabled!(log::Level::Info)); 30 | assert!(log::log_enabled!(log::Level::Debug)); 31 | assert!(!log::log_enabled!(log::Level::Trace)); 32 | 33 | log::debug!("i'm enabled now"); 34 | log::info!("i'm still enabled, too"); 35 | 36 | finished.assert_finished(); 37 | } 38 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/utils.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "std")] 2 | 3 | use tracing_mock::*; 4 | use tracing_subscriber::prelude::*; 5 | 6 | #[test] 7 | fn init_ext_works() { 8 | let (subscriber, finished) = subscriber::mock() 9 | .event( 10 | expect::event() 11 | .at_level(tracing::Level::INFO) 12 | .with_target("init_works"), 13 | ) 14 | .only() 15 | .run_with_handle(); 16 | 17 | let _guard = subscriber.set_default(); 18 | tracing::info!(target: "init_works", "it worked!"); 19 | finished.assert_finished(); 20 | } 21 | 22 | #[test] 23 | #[cfg(feature = "fmt")] 24 | fn builders_are_init_ext() { 25 | tracing_subscriber::fmt().set_default(); 26 | let _ = tracing_subscriber::fmt() 27 | .with_target(false) 28 | .compact() 29 | .try_init(); 30 | } 31 | 32 | #[test] 33 | #[cfg(all(feature = "fmt", feature = "env-filter"))] 34 | fn layered_is_init_ext() { 35 | tracing_subscriber::registry() 36 | .with(tracing_subscriber::fmt::layer()) 37 | .with(tracing_subscriber::EnvFilter::new("foo=info")) 38 | .set_default(); 39 | } 40 | -------------------------------------------------------------------------------- /tracing-subscriber/tests/vec.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "registry")] 2 | use tracing::level_filters::LevelFilter; 3 | use tracing::Subscriber; 4 | use tracing_subscriber::prelude::*; 5 | 6 | #[test] 7 | fn just_empty_vec() { 8 | // Just a None means everything is off 9 | let subscriber = tracing_subscriber::registry().with(Vec::::new()); 10 | assert_eq!(subscriber.max_level_hint(), Some(LevelFilter::OFF)); 11 | } 12 | 13 | #[test] 14 | fn layer_and_empty_vec() { 15 | let subscriber = tracing_subscriber::registry() 16 | .with(LevelFilter::INFO) 17 | .with(Vec::::new()); 18 | assert_eq!(subscriber.max_level_hint(), Some(LevelFilter::INFO)); 19 | } 20 | -------------------------------------------------------------------------------- /tracing-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | ## BIG SCARY NOTE 2 | # This crate is internal and to be used for testing only. It should not 3 | # be published to crates.io ever. If the functionality is needed outside 4 | # the tracing project, it should be moved back to tracing-mock. 5 | 6 | [package] 7 | name = "tracing-test" 8 | version = "0.1.0" 9 | authors = [ 10 | "Eliza Weisman ", 11 | "Tokio Contributors ", 12 | ] 13 | license = "MIT" 14 | readme = "README.md" 15 | repository = "https://github.com/tokio-rs/tracing" 16 | homepage = "https://tokio.rs" 17 | edition = "2018" 18 | rust-version = "1.49.0" 19 | publish = false 20 | 21 | [dependencies] 22 | tokio-test = "0.4.2" 23 | 24 | [package.metadata.docs.rs] 25 | all-features = true 26 | rustdoc-args = ["--cfg", "docsrs"] 27 | -------------------------------------------------------------------------------- /tracing-test/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-test/README.md: -------------------------------------------------------------------------------- 1 | ![Tracing — Structured, application-level diagnostics][splash] 2 | 3 | [splash]: https://raw.githubusercontent.com/tokio-rs/tracing/main/assets/splash.svg 4 | 5 | # tracing-test 6 | 7 | Utilities for testing [`tracing`][tracing] and crates that uses it. 8 | 9 | [![Documentation (v0.2.x)][docs-v0.2.x-badge]][docs-v0.2.x-url] 10 | [![MIT licensed][mit-badge]][mit-url] 11 | [![Build Status][actions-badge]][actions-url] 12 | [![Discord chat][discord-badge]][discord-url] 13 | 14 | [Documentation][docs-v0.2.x-url] | [Chat][discord-url] 15 | 16 | [docs-v0.2.x-badge]: https://img.shields.io/badge/docs-v0.2.x-blue 17 | [docs-v0.2.x-url]: https://tracing.rs/tracing_mock 18 | [mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg 19 | [mit-url]: https://github.com/tokio-rs/tracing/blog/main/tracing-test/LICENSE 20 | [actions-badge]: https://github.com/tokio-rs/tracing/workflows/CI/badge.svg 21 | [actions-url]:https://github.com/tokio-rs/tracing/actions?query=workflow%3ACI 22 | [discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white 23 | [discord-url]: https://discord.gg/EeF3cQw 24 | 25 | ## Overview 26 | 27 | [`tracing`] is a framework for instrumenting Rust programs to collect 28 | structured, event-based diagnostic information. `tracing-test` provides 29 | some reusable tools to aid in testing, but that are only intended for 30 | internal use. For mocks and expectations, see [`tracing-mock`]. 31 | 32 | *Compiler support: [requires `rustc` 1.56+][msrv]* 33 | 34 | [msrv]: #supported-rust-versions 35 | 36 | ## Supported Rust Versions 37 | 38 | Tracing is built against the latest stable release. The minimum supported 39 | version is 1.56. The current Tracing version is not guaranteed to build on Rust 40 | versions earlier than the minimum supported version. 41 | 42 | Tracing follows the same compiler support policies as the rest of the Tokio 43 | project. The current stable Rust compiler and the three most recent minor 44 | versions before it will always be supported. For example, if the current stable 45 | compiler version is 1.45, the minimum supported version will not be increased 46 | past 1.42, three minor versions prior. Increasing the minimum supported compiler 47 | version is not considered a semver breaking change as long as doing so complies 48 | with this policy. 49 | 50 | ## License 51 | 52 | This project is licensed under the [MIT license][mit-url]. 53 | 54 | ### Contribution 55 | 56 | Unless you explicitly state otherwise, any contribution intentionally submitted 57 | for inclusion in Tracing by you, shall be licensed as MIT, without any additional 58 | terms or conditions. 59 | -------------------------------------------------------------------------------- /tracing-test/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | pin::Pin, 3 | task::{Context, Poll}, 4 | }; 5 | 6 | #[allow(missing_docs)] 7 | pub struct PollN { 8 | and_return: Option>, 9 | finish_at: usize, 10 | polls: usize, 11 | } 12 | 13 | impl std::future::Future for PollN 14 | where 15 | T: Unpin, 16 | E: Unpin, 17 | { 18 | type Output = Result; 19 | fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { 20 | let this = self.get_mut(); 21 | 22 | this.polls += 1; 23 | if this.polls == this.finish_at { 24 | let value = this.and_return.take().expect("polled after ready"); 25 | 26 | Poll::Ready(value) 27 | } else { 28 | cx.waker().wake_by_ref(); 29 | Poll::Pending 30 | } 31 | } 32 | } 33 | 34 | impl PollN<(), ()> { 35 | pub fn new_ok(finish_at: usize) -> Self { 36 | Self { 37 | and_return: Some(Ok(())), 38 | finish_at, 39 | polls: 0, 40 | } 41 | } 42 | 43 | pub fn new_err(finish_at: usize) -> Self { 44 | Self { 45 | and_return: Some(Err(())), 46 | finish_at, 47 | polls: 0, 48 | } 49 | } 50 | } 51 | 52 | pub fn block_on_future(future: F) -> F::Output 53 | where 54 | F: std::future::Future, 55 | { 56 | use tokio_test::task; 57 | 58 | let mut task = task::spawn(future); 59 | loop { 60 | if let Poll::Ready(v) = task.poll() { 61 | break v; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tracing-tower/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tracing-tower" 3 | version = "0.1.0" 4 | authors = ["Eliza Weisman "] 5 | edition = "2018" 6 | repository = "https://github.com/tokio-rs/tracing" 7 | homepage = "https://tokio.rs" 8 | description = """ 9 | Compatibility with the `tower` ecosystem. 10 | """ 11 | categories = [ 12 | "development-tools::debugging", 13 | "development-tools::profiling", 14 | "asynchronous", 15 | ] 16 | keywords = ["logging", "tracing"] 17 | license = "MIT" 18 | rust-version = "1.65.0" 19 | 20 | [features] 21 | default = ["tower-layer", "tower-make"] 22 | tower-make = [ 23 | "tower_make", 24 | "pin-project-lite", 25 | ] 26 | 27 | [dependencies] 28 | tracing = { path = "../tracing", version = "0.1.35", default-features = false, features = ["std"] } 29 | tracing-futures = { version = "0.2.1", path = "../tracing-futures", features = ["std-future"] } 30 | futures = "0.3.21" 31 | tower-service = "0.3.2" 32 | tower-layer = { version = "0.3.1", optional = true } 33 | tower_make = { package = "tower-make", version = "0.3.0", optional = true } 34 | pin-project-lite = { version = "0.2.9", optional = true } 35 | http = { version = "0.2.8", optional = true } 36 | 37 | [badges] 38 | maintenance = { status = "experimental" } 39 | 40 | [package.metadata.docs.rs] 41 | all-features = true 42 | rustdoc-args = ["--cfg", "docsrs"] 43 | 44 | [lints] 45 | workspace = true 46 | -------------------------------------------------------------------------------- /tracing-tower/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing-tower/src/http.rs: -------------------------------------------------------------------------------- 1 | macro_rules! make_req_fns { 2 | ($($name:ident, $level:expr),+) => { 3 | $( 4 | #[inline] 5 | pub fn $name(req: &http::Request) -> tracing::Span { 6 | tracing::span!( 7 | $level, 8 | "request", 9 | method = ?req.method(), 10 | uri = ?req.uri(), 11 | ) 12 | } 13 | )+ 14 | } 15 | } 16 | 17 | make_req_fns! { 18 | info_request, tracing::Level::INFO, 19 | warn_request, tracing::Level::WARN, 20 | error_request, tracing::Level::ERROR 21 | } 22 | 23 | #[inline] 24 | pub fn debug_request(req: &http::Request) -> tracing::Span { 25 | tracing::span!( 26 | tracing::Level::DEBUG, 27 | "request", 28 | method = ?req.method(), 29 | uri = ?req.uri(), 30 | version = ?req.version(), 31 | ) 32 | } 33 | 34 | #[inline] 35 | pub fn trace_request(req: &http::Request) -> tracing::Span { 36 | tracing::span!( 37 | tracing::Level::TRACE, 38 | "request", 39 | method = ?req.method(), 40 | uri = ?req.uri(), 41 | version = ?req.version(), 42 | headers = ?req.headers(), 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /tracing/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tracing/benches/baseline.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | fn bench(c: &mut Criterion) { 4 | use std::sync::atomic::{AtomicUsize, Ordering}; 5 | 6 | let mut group = c.benchmark_group("comparison"); 7 | group.bench_function("relaxed_load", |b| { 8 | let foo = AtomicUsize::new(1); 9 | b.iter(|| black_box(foo.load(Ordering::Relaxed))); 10 | }); 11 | group.bench_function("acquire_load", |b| { 12 | let foo = AtomicUsize::new(1); 13 | b.iter(|| black_box(foo.load(Ordering::Acquire))) 14 | }); 15 | group.bench_function("log", |b| { 16 | b.iter(|| { 17 | log::log!(log::Level::Info, "log"); 18 | }) 19 | }); 20 | group.finish(); 21 | } 22 | 23 | criterion_group!(benches, bench); 24 | criterion_main!(benches); 25 | -------------------------------------------------------------------------------- /tracing/benches/dispatch_get_clone.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | mod shared; 4 | 5 | fn bench(c: &mut Criterion) { 6 | shared::for_all_dispatches(&mut c.benchmark_group("Dispatch::get_clone"), |b| { 7 | b.iter(|| { 8 | let current = tracing::dispatcher::get_default(|current| current.clone()); 9 | black_box(current); 10 | }) 11 | }); 12 | } 13 | 14 | criterion_group!(benches, bench); 15 | criterion_main!(benches); 16 | -------------------------------------------------------------------------------- /tracing/benches/dispatch_get_ref.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | mod shared; 4 | 5 | fn bench(c: &mut Criterion) { 6 | shared::for_all_dispatches(&mut c.benchmark_group("Dispatch::get_ref"), |b| { 7 | b.iter(|| { 8 | tracing::dispatcher::get_default(|current| { 9 | black_box(¤t); 10 | }) 11 | }) 12 | }); 13 | } 14 | 15 | criterion_group!(benches, bench); 16 | criterion_main!(benches); 17 | -------------------------------------------------------------------------------- /tracing/benches/empty_span.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | mod shared; 4 | 5 | fn bench(c: &mut Criterion) { 6 | let mut group = c.benchmark_group("empty_span"); 7 | shared::for_all_dispatches(&mut group, |b| { 8 | b.iter(|| { 9 | let span = tracing::span::Span::none(); 10 | black_box(&span); 11 | }) 12 | }); 13 | group.bench_function("baseline_struct", |b| { 14 | b.iter(|| { 15 | let span = FakeEmptySpan::new(); 16 | black_box(&span); 17 | }) 18 | }); 19 | } 20 | 21 | struct FakeEmptySpan { 22 | inner: Option<(usize, std::sync::Arc<()>)>, 23 | meta: Option<&'static ()>, 24 | } 25 | 26 | impl FakeEmptySpan { 27 | fn new() -> Self { 28 | Self { 29 | inner: None, 30 | meta: None, 31 | } 32 | } 33 | } 34 | 35 | impl Drop for FakeEmptySpan { 36 | fn drop(&mut self) { 37 | black_box(&self.inner); 38 | black_box(&self.meta); 39 | } 40 | } 41 | 42 | criterion_group!(benches, bench); 43 | criterion_main!(benches); 44 | -------------------------------------------------------------------------------- /tracing/benches/enter_span.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | use tracing::{span, Level}; 3 | 4 | mod shared; 5 | 6 | fn bench(c: &mut Criterion) { 7 | shared::for_all_dispatches(&mut c.benchmark_group("enter_span"), |b| { 8 | let span = span!(Level::TRACE, "span"); 9 | b.iter(|| { 10 | let _span = span.enter(); 11 | }) 12 | }); 13 | } 14 | 15 | criterion_group!(benches, bench); 16 | criterion_main!(benches); 17 | -------------------------------------------------------------------------------- /tracing/benches/event.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | 3 | mod shared; 4 | 5 | fn bench(c: &mut Criterion) { 6 | shared::for_all_recording(&mut c.benchmark_group("event"), |b| { 7 | b.iter(|| tracing::info!("hello world!")) 8 | }); 9 | } 10 | 11 | criterion_group!(benches, bench); 12 | criterion_main!(benches); 13 | -------------------------------------------------------------------------------- /tracing/benches/span_fields.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | use tracing::{span, Level}; 3 | 4 | mod shared; 5 | 6 | fn bench(c: &mut Criterion) { 7 | shared::for_all_recording(&mut c.benchmark_group("span_fields"), |b| { 8 | b.iter(|| { 9 | let span = span!( 10 | Level::TRACE, 11 | "span", 12 | foo = "foo", 13 | bar = "bar", 14 | baz = 3, 15 | quuux = tracing::field::debug(0.99) 16 | ); 17 | criterion::black_box(span) 18 | }) 19 | }); 20 | } 21 | 22 | criterion_group!(benches, bench); 23 | criterion_main!(benches); 24 | -------------------------------------------------------------------------------- /tracing/benches/span_no_fields.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | use tracing::{span, Level}; 3 | 4 | mod shared; 5 | 6 | fn bench(c: &mut Criterion) { 7 | shared::for_all_recording(&mut c.benchmark_group("span_no_fields"), |b| { 8 | b.iter(|| span!(Level::TRACE, "span")) 9 | }); 10 | } 11 | 12 | criterion_group!(benches, bench); 13 | criterion_main!(benches); 14 | -------------------------------------------------------------------------------- /tracing/benches/span_repeated.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | use tracing::{span, Level}; 3 | 4 | mod shared; 5 | 6 | fn bench(c: &mut Criterion) { 7 | shared::for_all_recording(&mut c.benchmark_group("span_repeated"), |b| { 8 | let n = black_box(N_SPANS); 9 | b.iter(|| (0..n).fold(mk_span(0), |_, i| mk_span(i as u64))) 10 | }); 11 | } 12 | 13 | #[inline] 14 | fn mk_span(i: u64) -> tracing::Span { 15 | span!(Level::TRACE, "span", i = i) 16 | } 17 | 18 | const N_SPANS: usize = 100; 19 | criterion_group!(benches, bench); 20 | criterion_main!(benches); 21 | -------------------------------------------------------------------------------- /tracing/src/stdlib.rs: -------------------------------------------------------------------------------- 1 | //! Re-exports either the Rust `std` library or `core` and `alloc` when `std` is 2 | //! disabled. 3 | //! 4 | //! `crate::stdlib::...` should be used rather than `std::` when adding code that 5 | //! will be available with the standard library disabled. 6 | //! 7 | //! Note that this module is called `stdlib` rather than `std`, as Rust 1.34.0 8 | //! does not permit redefining the name `stdlib` (although this works on the 9 | //! latest stable Rust). 10 | #[cfg(feature = "std")] 11 | pub(crate) use std::*; 12 | 13 | #[cfg(not(feature = "std"))] 14 | pub(crate) use self::no_std::*; 15 | 16 | #[cfg(not(feature = "std"))] 17 | mod no_std { 18 | // We pre-emptively export everything from libcore/liballoc, (even modules 19 | // we aren't using currently) to make adding new code easier. Therefore, 20 | // some of these imports will be unused. 21 | #![allow(unused_imports)] 22 | 23 | pub(crate) use core::{ 24 | any, array, ascii, cell, char, clone, cmp, convert, default, f32, f64, ffi, future, hash, 25 | hint, i128, i16, i8, isize, iter, marker, mem, num, ops, option, pin, ptr, result, task, 26 | time, u128, u16, u32, u8, usize, 27 | }; 28 | 29 | pub(crate) use alloc::{boxed, collections, rc, string, vec}; 30 | 31 | pub(crate) mod borrow { 32 | pub(crate) use alloc::borrow::*; 33 | pub(crate) use core::borrow::*; 34 | } 35 | 36 | pub(crate) mod fmt { 37 | pub(crate) use alloc::fmt::*; 38 | pub(crate) use core::fmt::*; 39 | } 40 | 41 | pub(crate) mod slice { 42 | pub(crate) use alloc::slice::*; 43 | pub(crate) use core::slice::*; 44 | } 45 | 46 | pub(crate) mod str { 47 | pub(crate) use alloc::str::*; 48 | pub(crate) use core::str::*; 49 | } 50 | 51 | pub(crate) mod sync { 52 | pub(crate) use alloc::sync::*; 53 | pub(crate) use core::sync::*; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tracing/src/subscriber.rs: -------------------------------------------------------------------------------- 1 | //! Collects and records trace data. 2 | pub use tracing_core::subscriber::*; 3 | 4 | #[cfg(feature = "std")] 5 | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 6 | pub use tracing_core::dispatcher::DefaultGuard; 7 | 8 | /// Sets this [`Subscriber`] as the default for the current thread for the 9 | /// duration of a closure. 10 | /// 11 | /// The default subscriber is used when creating a new [`Span`] or 12 | /// [`Event`]. 13 | /// 14 | /// 15 | /// [`Span`]: super::span::Span 16 | /// [`Subscriber`]: super::subscriber::Subscriber 17 | /// [`Event`]: super::event::Event 18 | #[cfg(feature = "std")] 19 | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 20 | pub fn with_default(subscriber: S, f: impl FnOnce() -> T) -> T 21 | where 22 | S: Subscriber + Send + Sync + 'static, 23 | { 24 | crate::dispatcher::with_default(&crate::Dispatch::new(subscriber), f) 25 | } 26 | 27 | /// Sets this subscriber as the global default for the duration of the entire program. 28 | /// Will be used as a fallback if no thread-local subscriber has been set in a thread (using `with_default`.) 29 | /// 30 | /// Can only be set once; subsequent attempts to set the global default will fail. 31 | /// Returns whether the initialization was successful. 32 | /// 33 | /// Note: Libraries should *NOT* call `set_global_default()`! That will cause conflicts when 34 | /// executables try to set them later. 35 | /// 36 | /// [`Subscriber`]: super::subscriber::Subscriber 37 | /// [`Event`]: super::event::Event 38 | pub fn set_global_default(subscriber: S) -> Result<(), SetGlobalDefaultError> 39 | where 40 | S: Subscriber + Send + Sync + 'static, 41 | { 42 | crate::dispatcher::set_global_default(crate::Dispatch::new(subscriber)) 43 | } 44 | 45 | /// Sets the [`Subscriber`] as the default for the current thread for the 46 | /// duration of the lifetime of the returned [`DefaultGuard`]. 47 | /// 48 | /// The default subscriber is used when creating a new [`Span`] or [`Event`]. 49 | /// 50 | /// [`Span`]: super::span::Span 51 | /// [`Subscriber`]: super::subscriber::Subscriber 52 | /// [`Event`]: super::event::Event 53 | /// [`DefaultGuard`]: super::dispatcher::DefaultGuard 54 | #[cfg(feature = "std")] 55 | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 56 | #[must_use = "Dropping the guard unregisters the subscriber."] 57 | pub fn set_default(subscriber: S) -> DefaultGuard 58 | where 59 | S: Subscriber + Send + Sync + 'static, 60 | { 61 | crate::dispatcher::set_default(&crate::Dispatch::new(subscriber)) 62 | } 63 | 64 | pub use tracing_core::dispatcher::SetGlobalDefaultError; 65 | -------------------------------------------------------------------------------- /tracing/test-log-support/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | [package] 4 | name = "test-log-support" 5 | version = "0.1.0" 6 | publish = false 7 | edition = "2018" 8 | 9 | [dependencies] 10 | tracing = { path = "..", features = ["log", "log-always"] } 11 | log = { version = "0.4.0", features = ["std"] } 12 | -------------------------------------------------------------------------------- /tracing/test-log-support/src/lib.rs: -------------------------------------------------------------------------------- 1 | use log::{LevelFilter, Log, Metadata, Record}; 2 | use std::sync::{Arc, Mutex}; 3 | 4 | pub struct Test { 5 | state: Arc, 6 | } 7 | 8 | struct State { 9 | last_log: Mutex>, 10 | } 11 | 12 | struct Logger { 13 | filters: Vec<(&'static str, LevelFilter)>, 14 | state: Arc, 15 | } 16 | 17 | impl Log for Logger { 18 | fn enabled(&self, meta: &Metadata) -> bool { 19 | for (target, level) in &self.filters { 20 | if meta.target().starts_with(target) { 21 | return meta.level() <= *level; 22 | } 23 | } 24 | false 25 | } 26 | 27 | fn log(&self, record: &Record) { 28 | let line = format!("{}", record.args()); 29 | println!("{:<5} {} {}", record.level(), record.target(), line); 30 | if let Ok(mut last) = self.state.last_log.lock() { 31 | *last = Some(line); 32 | } 33 | } 34 | 35 | fn flush(&self) {} 36 | } 37 | 38 | impl Test { 39 | pub fn start() -> Self { 40 | Self::with_filters(&[("", LevelFilter::Trace)]) 41 | } 42 | 43 | pub fn with_filters<'a>( 44 | filters: impl IntoIterator, 45 | ) -> Self { 46 | let me = Arc::new(State { 47 | last_log: Mutex::new(None), 48 | }); 49 | let state = me.clone(); 50 | let mut max = LevelFilter::Off; 51 | let filters = filters 52 | .into_iter() 53 | .cloned() 54 | .inspect(|(_, f)| { 55 | if f > &max { 56 | max = *f; 57 | } 58 | }) 59 | .collect(); 60 | let logger = Logger { filters, state: me }; 61 | log::set_boxed_logger(Box::new(logger)).unwrap(); 62 | log::set_max_level(max); 63 | Test { state } 64 | } 65 | 66 | #[track_caller] 67 | pub fn assert_logged(&self, expected: &str) { 68 | let last = match self.state.last_log.lock().unwrap().take() { 69 | Some(last) => last, 70 | _ => panic!( 71 | "test failed: expected \"{}\", but nothing was logged", 72 | expected 73 | ), 74 | }; 75 | 76 | assert_eq!(last.as_str().trim(), expected); 77 | } 78 | 79 | #[track_caller] 80 | pub fn assert_not_logged(&self) { 81 | if let Some(last) = self.state.last_log.lock().unwrap().take() { 82 | panic!( 83 | "test failed: nothing to be logged, but \"{}\" was logged", 84 | last 85 | ); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tracing/test-log-support/tests/log_move_arg.rs: -------------------------------------------------------------------------------- 1 | use tracing::{event, span, Level}; 2 | 3 | /// Test that spans and events only use their argument once. See #196 and #1739. 4 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 5 | #[test] 6 | fn test_move_arg() { 7 | let foo = Foo; 8 | let parent_span = span!(Level::INFO, "Span 1", bar = ?Bar(foo)); 9 | let foo = Foo; 10 | span!(parent: &parent_span, Level::INFO, "Span 2", bar = ?Bar(foo)); 11 | 12 | let foo = Foo; 13 | event!(Level::INFO, bar = ?Bar(foo), "Event 1"); 14 | let foo = Foo; 15 | event!(parent: &parent_span, Level::INFO, bar = ?Bar(foo), "Event 2"); 16 | } 17 | 18 | #[derive(Debug)] 19 | struct Foo; 20 | 21 | #[derive(Debug)] 22 | struct Bar(Foo); 23 | -------------------------------------------------------------------------------- /tracing/test-log-support/tests/log_no_trace.rs: -------------------------------------------------------------------------------- 1 | use test_log_support::Test; 2 | use tracing::{error, info, span, trace, warn, Level}; 3 | 4 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 5 | #[test] 6 | fn test_always_log() { 7 | let test = Test::start(); 8 | 9 | error!(foo = 5); 10 | test.assert_logged("foo=5"); 11 | 12 | warn!("hello {};", "world"); 13 | test.assert_logged("hello world;"); 14 | 15 | info!( 16 | message = "hello world;", 17 | thingy = display(42), 18 | other_thingy = debug(666) 19 | ); 20 | test.assert_logged("hello world; thingy=42 other_thingy=666"); 21 | 22 | let foo = span!(Level::TRACE, "foo"); 23 | test.assert_logged("foo;"); 24 | 25 | foo.in_scope(|| { 26 | test.assert_logged("-> foo;"); 27 | 28 | trace!({foo = 3, bar = 4}, "hello {};", "san francisco"); 29 | test.assert_logged("hello san francisco; foo=3 bar=4"); 30 | }); 31 | test.assert_logged("<- foo;"); 32 | 33 | drop(foo); 34 | test.assert_logged("-- foo;"); 35 | 36 | trace!(foo = 1, bar = 2, "hello world"); 37 | test.assert_logged("hello world foo=1 bar=2"); 38 | 39 | let foo = span!(Level::TRACE, "foo", bar = 3, baz = false); 40 | test.assert_logged("foo; bar=3 baz=false"); 41 | 42 | drop(foo); 43 | } 44 | -------------------------------------------------------------------------------- /tracing/test-log-support/tests/span_lifecycle_can_be_enabled.rs: -------------------------------------------------------------------------------- 1 | use test_log_support::Test; 2 | use tracing::{error, info, span, trace, warn, Level}; 3 | 4 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 5 | #[test] 6 | fn span_lifecycle_can_be_enabled() { 7 | let test = Test::with_filters(&[ 8 | (module_path!(), log::LevelFilter::Trace), 9 | ("tracing::span", log::LevelFilter::Trace), 10 | ]); 11 | 12 | error!(foo = 5); 13 | test.assert_logged("foo=5"); 14 | 15 | warn!("hello {};", "world"); 16 | test.assert_logged("hello world;"); 17 | 18 | info!(message = "hello world;", thingy = 42, other_thingy = 666); 19 | test.assert_logged("hello world; thingy=42 other_thingy=666"); 20 | 21 | let foo = span!(Level::TRACE, "foo"); 22 | test.assert_logged("foo;"); 23 | 24 | foo.in_scope(|| { 25 | // enter should be logged 26 | test.assert_logged("-> foo;"); 27 | 28 | trace!({foo = 3, bar = 4}, "hello {};", "san francisco"); 29 | test.assert_logged("hello san francisco; foo=3 bar=4"); 30 | }); 31 | // exit should be logged 32 | test.assert_logged("<- foo;"); 33 | 34 | drop(foo); 35 | // drop should be logged 36 | test.assert_logged("-- foo;"); 37 | 38 | trace!(foo = 1, bar = 2, "hello world"); 39 | test.assert_logged("hello world foo=1 bar=2"); 40 | 41 | let foo = span!(Level::TRACE, "foo", bar = 3, baz = false); 42 | // creating a span with fields _should_ be logged. 43 | test.assert_logged("foo; bar=3 baz=false"); 44 | 45 | foo.in_scope(|| { 46 | // entering the span should be logged 47 | test.assert_logged("-> foo;"); 48 | }); 49 | // exiting the span should be logged 50 | test.assert_logged("<- foo;"); 51 | 52 | foo.record("baz", &true); 53 | // recording a field should be logged 54 | test.assert_logged("foo; baz=true"); 55 | 56 | let bar = span!(Level::INFO, "bar"); 57 | // lifecycles for INFO spans should be logged 58 | test.assert_logged("bar;"); 59 | 60 | bar.in_scope(|| { 61 | // entering the INFO span should be logged 62 | test.assert_logged("-> bar;"); 63 | }); 64 | // exiting the INFO span should be logged 65 | test.assert_logged("<- bar;"); 66 | 67 | drop(foo); 68 | // drop should be logged. 69 | test.assert_logged("-- foo;"); 70 | 71 | drop(bar); 72 | // dropping the INFO should be logged. 73 | test.assert_logged("-- bar;"); 74 | } 75 | -------------------------------------------------------------------------------- /tracing/test-log-support/tests/span_lifecycle_defaults_off.rs: -------------------------------------------------------------------------------- 1 | use test_log_support::Test; 2 | use tracing::{error, info, span, trace, warn, Level}; 3 | 4 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 5 | #[test] 6 | fn span_lifecycle_defaults_off() { 7 | let test = Test::with_filters(&[(module_path!(), log::LevelFilter::Trace)]); 8 | 9 | error!(foo = 5); 10 | test.assert_logged("foo=5"); 11 | 12 | warn!("hello {};", "world"); 13 | test.assert_logged("hello world;"); 14 | 15 | info!(message = "hello world;", thingy = 42, other_thingy = 666); 16 | test.assert_logged("hello world; thingy=42 other_thingy=666"); 17 | 18 | let foo = span!(Level::TRACE, "foo"); 19 | test.assert_not_logged(); 20 | 21 | foo.in_scope(|| { 22 | // enter should not be logged 23 | test.assert_not_logged(); 24 | 25 | trace!({foo = 3, bar = 4}, "hello {};", "san francisco"); 26 | test.assert_logged("hello san francisco; foo=3 bar=4"); 27 | }); 28 | // exit should not be logged 29 | test.assert_not_logged(); 30 | 31 | drop(foo); 32 | // drop should not be logged 33 | test.assert_not_logged(); 34 | 35 | trace!(foo = 1, bar = 2, "hello world"); 36 | test.assert_logged("hello world foo=1 bar=2"); 37 | 38 | let foo = span!(Level::TRACE, "foo", bar = 3, baz = false); 39 | // creating a span with fields _should_ be logged. 40 | test.assert_logged("foo; bar=3 baz=false"); 41 | 42 | foo.in_scope(|| { 43 | // entering the span should not be logged 44 | test.assert_not_logged(); 45 | }); 46 | // exiting the span should not be logged 47 | test.assert_not_logged(); 48 | 49 | foo.record("baz", &true); 50 | // recording a field should be logged 51 | test.assert_logged("foo; baz=true"); 52 | 53 | drop(foo); 54 | // drop should not be logged. 55 | test.assert_not_logged(); 56 | } 57 | -------------------------------------------------------------------------------- /tracing/test-log-support/tests/span_lifecycle_is_trace.rs: -------------------------------------------------------------------------------- 1 | use test_log_support::Test; 2 | use tracing::{error, info, span, trace, warn, Level}; 3 | 4 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 5 | #[test] 6 | fn span_lifecycle_is_trace() { 7 | let test = Test::with_filters(&[ 8 | (module_path!(), log::LevelFilter::Trace), 9 | ("", log::LevelFilter::Info), 10 | ]); 11 | 12 | error!(foo = 5); 13 | test.assert_logged("foo=5"); 14 | 15 | warn!("hello {};", "world"); 16 | test.assert_logged("hello world;"); 17 | 18 | info!(message = "hello world;", thingy = 42, other_thingy = 666); 19 | test.assert_logged("hello world; thingy=42 other_thingy=666"); 20 | 21 | let foo = span!(Level::TRACE, "foo"); 22 | // A span without fields should not be logged 23 | test.assert_not_logged(); 24 | 25 | foo.in_scope(|| { 26 | // enter should not be logged 27 | test.assert_not_logged(); 28 | 29 | trace!({foo = 3, bar = 4}, "hello {};", "san francisco"); 30 | test.assert_logged("hello san francisco; foo=3 bar=4"); 31 | }); 32 | // exit should not be logged 33 | test.assert_not_logged(); 34 | 35 | drop(foo); 36 | // drop should not be logged 37 | test.assert_not_logged(); 38 | 39 | trace!(foo = 1, bar = 2, "hello world"); 40 | test.assert_logged("hello world foo=1 bar=2"); 41 | 42 | let foo = span!(Level::TRACE, "foo", bar = 3, baz = false); 43 | // creating a span with fields _should_ be logged. 44 | test.assert_logged("foo; bar=3 baz=false"); 45 | 46 | foo.in_scope(|| { 47 | // entering the span should not be logged 48 | test.assert_not_logged(); 49 | }); 50 | // exiting the span should not be logged 51 | test.assert_not_logged(); 52 | 53 | foo.record("baz", &true); 54 | // recording a field should be logged 55 | test.assert_logged("foo; baz=true"); 56 | 57 | drop(foo); 58 | // drop should not be logged. 59 | test.assert_not_logged(); 60 | } 61 | -------------------------------------------------------------------------------- /tracing/test_static_max_level_features/Cargo.toml: -------------------------------------------------------------------------------- 1 | # Note: these tests _cannot_ be in the root workspace, as they will enable 2 | # filtering features on the rest of the workspace, breaking other tests. 3 | # 4 | # DO NOT ADD THIS TO THE ROOT WORKSPACE. 5 | [workspace] 6 | 7 | [package] 8 | name = "test_cargo_max_level_features" 9 | version = "0.1.0" 10 | publish = false 11 | edition = "2018" 12 | 13 | [dependencies] 14 | tracing-core = { path = "../../tracing-core" } 15 | 16 | [dependencies.tracing] 17 | path = ".." 18 | features = ["max_level_debug", "release_max_level_info"] 19 | 20 | [dev-dependencies] 21 | tokio-test = "0.2.0" 22 | tracing-test = { path = "../../tracing-test" } 23 | -------------------------------------------------------------------------------- /tracing/tests/enabled.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "std")] 2 | use tracing::Level; 3 | use tracing_mock::*; 4 | 5 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 6 | #[test] 7 | fn level_and_target() { 8 | let subscriber = subscriber::mock() 9 | .with_filter(|meta| { 10 | if meta.target() == "debug_module" { 11 | meta.level() <= &Level::DEBUG 12 | } else { 13 | meta.level() <= &Level::INFO 14 | } 15 | }) 16 | .only() 17 | .run(); 18 | 19 | let _guard = tracing::subscriber::set_default(subscriber); 20 | 21 | assert!(tracing::enabled!(target: "debug_module", Level::DEBUG)); 22 | assert!(tracing::enabled!(Level::ERROR)); 23 | assert!(!tracing::enabled!(Level::DEBUG)); 24 | } 25 | 26 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 27 | #[test] 28 | fn span_and_event() { 29 | let subscriber = subscriber::mock() 30 | .with_filter(|meta| { 31 | if meta.target() == "debug_module" { 32 | meta.level() <= &Level::DEBUG 33 | } else if meta.is_span() { 34 | meta.level() <= &Level::TRACE 35 | } else if meta.is_event() { 36 | meta.level() <= &Level::DEBUG 37 | } else { 38 | meta.level() <= &Level::INFO 39 | } 40 | }) 41 | .only() 42 | .run(); 43 | 44 | let _guard = tracing::subscriber::set_default(subscriber); 45 | 46 | // Ensure that the `_event` and `_span` alternatives work correctly 47 | assert!(!tracing::event_enabled!(Level::TRACE)); 48 | assert!(tracing::event_enabled!(Level::DEBUG)); 49 | assert!(tracing::span_enabled!(Level::TRACE)); 50 | 51 | // target variants 52 | assert!(tracing::span_enabled!(target: "debug_module", Level::DEBUG)); 53 | assert!(tracing::event_enabled!(target: "debug_module", Level::DEBUG)); 54 | } 55 | -------------------------------------------------------------------------------- /tracing/tests/filter_caching_is_lexically_scoped.rs: -------------------------------------------------------------------------------- 1 | // Tests that depend on a count of the number of times their filter is evaluated 2 | // can't exist in the same file with other tests that add subscribers to the 3 | // registry. The registry was changed so that each time a new dispatcher is 4 | // added all filters are re-evaluated. The tests being run only in separate 5 | // threads with shared global state lets them interfere with each other 6 | 7 | #[cfg(not(feature = "std"))] 8 | extern crate std; 9 | 10 | use tracing::{span, Level}; 11 | use tracing_mock::*; 12 | 13 | use std::sync::{ 14 | atomic::{AtomicUsize, Ordering}, 15 | Arc, 16 | }; 17 | 18 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 19 | #[test] 20 | fn filter_caching_is_lexically_scoped() { 21 | pub fn my_great_function() -> bool { 22 | span!(Level::TRACE, "emily").in_scope(|| true) 23 | } 24 | 25 | pub fn my_other_function() -> bool { 26 | span!(Level::TRACE, "frank").in_scope(|| true) 27 | } 28 | 29 | let count = Arc::new(AtomicUsize::new(0)); 30 | let count2 = count.clone(); 31 | 32 | let subscriber = subscriber::mock() 33 | .with_filter(move |meta| match meta.name() { 34 | "emily" | "frank" => { 35 | count2.fetch_add(1, Ordering::Relaxed); 36 | true 37 | } 38 | _ => false, 39 | }) 40 | .run(); 41 | 42 | // Since this test is in its own file anyway, we can do this. Thus, this 43 | // test will work even with no-std. 44 | tracing::subscriber::set_global_default(subscriber).unwrap(); 45 | 46 | // Call the function once. The filter should be re-evaluated. 47 | assert!(my_great_function()); 48 | assert_eq!(count.load(Ordering::Relaxed), 1); 49 | 50 | // Call the function again. The cached result should be used. 51 | assert!(my_great_function()); 52 | assert_eq!(count.load(Ordering::Relaxed), 1); 53 | 54 | assert!(my_other_function()); 55 | assert_eq!(count.load(Ordering::Relaxed), 2); 56 | 57 | assert!(my_great_function()); 58 | assert_eq!(count.load(Ordering::Relaxed), 2); 59 | 60 | assert!(my_other_function()); 61 | assert_eq!(count.load(Ordering::Relaxed), 2); 62 | 63 | assert!(my_great_function()); 64 | assert_eq!(count.load(Ordering::Relaxed), 2); 65 | } 66 | -------------------------------------------------------------------------------- /tracing/tests/filters_dont_leak.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "std")] 2 | 3 | use tracing_mock::*; 4 | 5 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 6 | #[test] 7 | fn spans_dont_leak() { 8 | fn do_span() { 9 | let span = tracing::debug_span!("alice"); 10 | let _e = span.enter(); 11 | } 12 | 13 | let (subscriber, handle) = subscriber::mock() 14 | .named("spans/subscriber1") 15 | .with_filter(|_| false) 16 | .only() 17 | .run_with_handle(); 18 | 19 | let _guard = tracing::subscriber::set_default(subscriber); 20 | 21 | do_span(); 22 | 23 | let alice = expect::span().named("alice"); 24 | let (subscriber2, handle2) = subscriber::mock() 25 | .named("spans/subscriber2") 26 | .with_filter(|_| true) 27 | .new_span(alice.clone()) 28 | .enter(alice.clone()) 29 | .exit(alice.clone()) 30 | .drop_span(alice) 31 | .only() 32 | .run_with_handle(); 33 | 34 | tracing::subscriber::with_default(subscriber2, || { 35 | println!("--- subscriber 2 is default ---"); 36 | do_span() 37 | }); 38 | 39 | println!("--- subscriber 1 is default ---"); 40 | do_span(); 41 | 42 | handle.assert_finished(); 43 | handle2.assert_finished(); 44 | } 45 | 46 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 47 | #[test] 48 | fn events_dont_leak() { 49 | fn do_event() { 50 | tracing::debug!("alice"); 51 | } 52 | 53 | let (subscriber, handle) = subscriber::mock() 54 | .named("events/subscriber1") 55 | .with_filter(|_| false) 56 | .only() 57 | .run_with_handle(); 58 | 59 | let _guard = tracing::subscriber::set_default(subscriber); 60 | 61 | do_event(); 62 | 63 | let (subscriber2, handle2) = subscriber::mock() 64 | .named("events/subscriber2") 65 | .with_filter(|_| true) 66 | .event(expect::event()) 67 | .only() 68 | .run_with_handle(); 69 | 70 | tracing::subscriber::with_default(subscriber2, || { 71 | println!("--- subscriber 2 is default ---"); 72 | do_event() 73 | }); 74 | 75 | println!("--- subscriber 1 is default ---"); 76 | 77 | do_event(); 78 | 79 | handle.assert_finished(); 80 | handle2.assert_finished(); 81 | } 82 | -------------------------------------------------------------------------------- /tracing/tests/future_send.rs: -------------------------------------------------------------------------------- 1 | // These tests reproduce the following issues: 2 | // - https://github.com/tokio-rs/tracing/issues/1487 3 | // - https://github.com/tokio-rs/tracing/issues/1793 4 | 5 | use core::future::{self, Future}; 6 | #[test] 7 | fn async_fn_is_send() { 8 | async fn some_async_fn() { 9 | tracing::info!("{}", future::ready("test").await); 10 | } 11 | 12 | assert_send(some_async_fn()) 13 | } 14 | 15 | #[test] 16 | fn async_block_is_send() { 17 | assert_send(async { 18 | tracing::info!("{}", future::ready("test").await); 19 | }) 20 | } 21 | 22 | fn assert_send(_f: F) {} 23 | -------------------------------------------------------------------------------- /tracing/tests/instrument.rs: -------------------------------------------------------------------------------- 1 | // These tests require the thread-local scoped dispatcher, which only works when 2 | // we have a standard library. The behaviour being tested should be the same 3 | // with the standard lib disabled. 4 | #![cfg(feature = "std")] 5 | 6 | use std::{future::Future, pin::Pin, task}; 7 | 8 | use futures::FutureExt as _; 9 | use tracing::{subscriber::with_default, Instrument as _, Level}; 10 | use tracing_mock::*; 11 | 12 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 13 | #[test] 14 | fn span_on_drop() { 15 | #[derive(Clone, Debug)] 16 | struct AssertSpanOnDrop; 17 | 18 | impl Drop for AssertSpanOnDrop { 19 | fn drop(&mut self) { 20 | tracing::info!("Drop"); 21 | } 22 | } 23 | 24 | #[allow(dead_code)] // Field not used, but logs on `Drop` 25 | struct Fut(Option); 26 | 27 | impl Future for Fut { 28 | type Output = (); 29 | 30 | fn poll(mut self: Pin<&mut Self>, _: &mut task::Context<'_>) -> task::Poll { 31 | self.set(Fut(None)); 32 | task::Poll::Ready(()) 33 | } 34 | } 35 | 36 | let subscriber = subscriber::mock() 37 | .enter(expect::span().named("foo")) 38 | .event( 39 | expect::event() 40 | .with_ancestry(expect::has_contextual_parent("foo")) 41 | .at_level(Level::INFO), 42 | ) 43 | .exit(expect::span().named("foo")) 44 | .enter(expect::span().named("foo")) 45 | .exit(expect::span().named("foo")) 46 | .drop_span(expect::span().named("foo")) 47 | .enter(expect::span().named("bar")) 48 | .event( 49 | expect::event() 50 | .with_ancestry(expect::has_contextual_parent("bar")) 51 | .at_level(Level::INFO), 52 | ) 53 | .exit(expect::span().named("bar")) 54 | .drop_span(expect::span().named("bar")) 55 | .only() 56 | .run(); 57 | 58 | with_default(subscriber, || { 59 | // polled once 60 | Fut(Some(AssertSpanOnDrop)) 61 | .instrument(tracing::span!(Level::TRACE, "foo")) 62 | .now_or_never() 63 | .unwrap(); 64 | 65 | // never polled 66 | drop(Fut(Some(AssertSpanOnDrop)).instrument(tracing::span!(Level::TRACE, "bar"))); 67 | }); 68 | } 69 | -------------------------------------------------------------------------------- /tracing/tests/macro_imports.rs: -------------------------------------------------------------------------------- 1 | use tracing::Level; 2 | 3 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 4 | #[test] 5 | fn prefixed_span_macros() { 6 | tracing::span!(Level::DEBUG, "foo"); 7 | tracing::trace_span!("foo"); 8 | tracing::debug_span!("foo"); 9 | tracing::info_span!("foo"); 10 | tracing::warn_span!("foo"); 11 | tracing::error_span!("foo"); 12 | } 13 | 14 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 15 | #[test] 16 | fn prefixed_event_macros() { 17 | tracing::event!(Level::DEBUG, "foo"); 18 | tracing::trace!("foo"); 19 | tracing::debug!("foo"); 20 | tracing::info!("foo"); 21 | tracing::warn!("foo"); 22 | tracing::error!("foo"); 23 | } 24 | -------------------------------------------------------------------------------- /tracing/tests/macros_incompatible_concat.rs: -------------------------------------------------------------------------------- 1 | use tracing::{enabled, event, span, Level}; 2 | 3 | #[macro_export] 4 | macro_rules! concat { 5 | () => {}; 6 | } 7 | 8 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 9 | #[test] 10 | fn span() { 11 | span!(Level::DEBUG, "foo"); 12 | } 13 | 14 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 15 | #[test] 16 | fn event() { 17 | event!(Level::DEBUG, "foo"); 18 | } 19 | 20 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 21 | #[test] 22 | fn enabled() { 23 | enabled!(Level::DEBUG); 24 | } 25 | -------------------------------------------------------------------------------- /tracing/tests/max_level_hint.rs: -------------------------------------------------------------------------------- 1 | use tracing::Level; 2 | use tracing_mock::*; 3 | 4 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 5 | #[test] 6 | fn max_level_hints() { 7 | // This test asserts that when a subscriber provides us with the global 8 | // maximum level that it will enable (by implementing the 9 | // `Subscriber::max_level_hint` method), we will never call 10 | // `Subscriber::enabled` for events above that maximum level. 11 | // 12 | // In this case, we test that by making the `enabled` method assert that no 13 | // `Metadata` for spans or events at the `TRACE` or `DEBUG` levels. 14 | let (subscriber, handle) = subscriber::mock() 15 | .with_max_level_hint(Level::INFO) 16 | .with_filter(|meta| { 17 | assert!( 18 | dbg!(meta).level() <= &Level::INFO, 19 | "a TRACE or DEBUG event was dynamically filtered: " 20 | ); 21 | true 22 | }) 23 | .event(expect::event().at_level(Level::INFO)) 24 | .event(expect::event().at_level(Level::WARN)) 25 | .event(expect::event().at_level(Level::ERROR)) 26 | .only() 27 | .run_with_handle(); 28 | 29 | tracing::subscriber::set_global_default(subscriber).unwrap(); 30 | 31 | tracing::info!("doing a thing that you might care about"); 32 | tracing::debug!("charging turboencabulator with interocitor"); 33 | tracing::warn!("extremely serious warning, pay attention"); 34 | tracing::trace!("interocitor charge level is 10%"); 35 | tracing::error!("everything is on fire"); 36 | handle.assert_finished(); 37 | } 38 | -------------------------------------------------------------------------------- /tracing/tests/no_subscriber.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "std")] 2 | 3 | use tracing_mock::subscriber; 4 | 5 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] 6 | #[test] 7 | fn no_subscriber_disables_global() { 8 | // Reproduces https://github.com/tokio-rs/tracing/issues/1999 9 | let (subscriber, handle) = subscriber::mock().only().run_with_handle(); 10 | tracing::subscriber::set_global_default(subscriber) 11 | .expect("setting global default must succeed"); 12 | tracing::subscriber::with_default(tracing::subscriber::NoSubscriber::default(), || { 13 | tracing::info!("this should not be recorded"); 14 | }); 15 | handle.assert_finished(); 16 | } 17 | -------------------------------------------------------------------------------- /tracing/tests/register_callsite_deadlock.rs: -------------------------------------------------------------------------------- 1 | use std::{sync::mpsc, thread, time::Duration}; 2 | use tracing::{ 3 | metadata::Metadata, 4 | span, 5 | subscriber::{self, Interest, Subscriber}, 6 | Event, 7 | }; 8 | 9 | #[test] 10 | fn register_callsite_doesnt_deadlock() { 11 | pub struct EvilSubscriber; 12 | 13 | impl Subscriber for EvilSubscriber { 14 | fn register_callsite(&self, meta: &'static Metadata<'static>) -> Interest { 15 | tracing::info!(?meta, "registered a callsite"); 16 | Interest::always() 17 | } 18 | 19 | fn enabled(&self, _: &Metadata<'_>) -> bool { 20 | true 21 | } 22 | fn new_span(&self, _: &span::Attributes<'_>) -> span::Id { 23 | span::Id::from_u64(1) 24 | } 25 | fn record(&self, _: &span::Id, _: &span::Record<'_>) {} 26 | fn record_follows_from(&self, _: &span::Id, _: &span::Id) {} 27 | fn event(&self, _: &Event<'_>) {} 28 | fn enter(&self, _: &span::Id) {} 29 | fn exit(&self, _: &span::Id) {} 30 | } 31 | 32 | subscriber::set_global_default(EvilSubscriber).unwrap(); 33 | 34 | // spawn a thread, and assert it doesn't hang... 35 | let (tx, didnt_hang) = mpsc::channel(); 36 | let th = thread::spawn(move || { 37 | tracing::info!("hello world!"); 38 | tx.send(()).unwrap(); 39 | }); 40 | 41 | didnt_hang 42 | // Note: 60 seconds is *way* more than enough, but let's be generous in 43 | // case of e.g. slow CI machines. 44 | .recv_timeout(Duration::from_secs(60)) 45 | .expect("the thread must not have hung!"); 46 | th.join().expect("thread should join successfully"); 47 | } 48 | -------------------------------------------------------------------------------- /tracing/tests/scoped_clobbers_default.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "std")] 2 | use tracing_mock::{expect, subscriber}; 3 | 4 | #[test] 5 | fn scoped_clobbers_global() { 6 | // Reproduces https://github.com/tokio-rs/tracing/issues/2050 7 | 8 | let (scoped, scoped_handle) = subscriber::mock() 9 | .event(expect::event().with_fields(expect::msg("before global"))) 10 | .event(expect::event().with_fields(expect::msg("before drop"))) 11 | .only() 12 | .run_with_handle(); 13 | 14 | let (global, global_handle) = subscriber::mock() 15 | .event(expect::event().with_fields(expect::msg("after drop"))) 16 | .only() 17 | .run_with_handle(); 18 | 19 | // Set a scoped default subscriber, returning a guard. 20 | let guard = tracing::subscriber::set_default(scoped); 21 | tracing::info!("before global"); 22 | 23 | // Now, set the global default. 24 | tracing::subscriber::set_global_default(global) 25 | .expect("global default should not already be set"); 26 | // This event should still be collected by the scoped default. 27 | tracing::info!("before drop"); 28 | 29 | // Drop the guard. Now, the global default subscriber should be used. 30 | drop(guard); 31 | tracing::info!("after drop"); 32 | 33 | scoped_handle.assert_finished(); 34 | global_handle.assert_finished(); 35 | } 36 | --------------------------------------------------------------------------------