log-0.4.26/.cargo_vcs_info.json0000644000000001360000000000100117060ustar { "git": { "sha1": "5a915548178b06f16049e3a4d0de79251bdf9603" }, "path_in_vcs": "" }log-0.4.26/.github/workflows/main.yml000064400000000000000000000122121046102023000155400ustar 00000000000000name: CI on: [push, pull_request] permissions: contents: read # to fetch code (actions/checkout) jobs: test: name: Test runs-on: ${{ matrix.os }} strategy: matrix: build: [stable, beta, nightly, macos, win32, win64, mingw] include: - build: stable os: ubuntu-latest rust: stable - build: beta os: ubuntu-latest rust: beta - build: nightly os: ubuntu-latest rust: nightly - build: macos os: macos-latest rust: stable - build: win32 os: windows-latest rust: stable-i686-pc-windows-msvc - build: win64 os: windows-latest rust: stable-x86_64-pc-windows-msvc - build: mingw os: windows-latest rust: stable-x86_64-pc-windows-gnu steps: - uses: actions/checkout@master - name: Install Rust run: | rustup update ${{ matrix.rust }} --no-self-update rustup default ${{ matrix.rust }} cargo install cargo-hack - run: cargo hack test --feature-powerset --lib --exclude-features max_level_off,max_level_error,max_level_warn,max_level_info,max_level_debug,max_level_trace,release_max_level_off,release_max_level_error,release_max_level_warn,release_max_level_info,release_max_level_debug,release_max_level_trace - run: cargo run --verbose --manifest-path test_max_level_features/Cargo.toml - run: cargo run --verbose --manifest-path test_max_level_features/Cargo.toml --release rustfmt: name: Rustfmt runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Install Rust run: | rustup update stable --no-self-update rustup default stable rustup component add rustfmt # log repo does not use Cargo workspaces, so `cargo fmt` will not check all the code # perhaps this should be changed in the future - run: cargo fmt -- --check - run: cargo fmt --manifest-path test_max_level_features/Cargo.toml -- --check - run: cargo fmt --manifest-path tests/Cargo.toml -- --check clippy: name: Clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Install Rust run: | rustup update stable --no-self-update rustup default stable rustup component add clippy - run: cargo clippy --verbose - run: cargo clippy --verbose --manifest-path test_max_level_features/Cargo.toml - run: cargo clippy --verbose --manifest-path tests/Cargo.toml doc: name: Check Documentation runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Install Rust run: | rustup update stable --no-self-update rustup default stable rustup component add rust-docs - name: Run rustdoc run: RUSTDOCFLAGS="-D warnings" cargo doc --verbose --features std,serde,sval,sval_ref,value-bag,kv,kv_std,kv_sval,kv_serde features: name: Feature check runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly - run: cargo build --verbose -Z avoid-dev-deps --features kv - run: cargo build --verbose -Z avoid-dev-deps --features "kv std" - run: cargo build --verbose -Z avoid-dev-deps --features "kv kv_sval" - run: cargo build --verbose -Z avoid-dev-deps --features "kv kv_serde" - run: cargo build --verbose -Z avoid-dev-deps --features "kv kv_std" - run: cargo build --verbose -Z avoid-dev-deps --features "kv kv_sval kv_serde" minimalv: name: Minimal versions runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Install Rust run: | rustup update nightly --no-self-update rustup default nightly - run: cargo build --verbose -Z minimal-versions --features kv - run: cargo build --verbose -Z minimal-versions --features "kv std" - run: cargo build --verbose -Z minimal-versions --features "kv kv_sval" - run: cargo build --verbose -Z minimal-versions --features "kv kv_serde" - run: cargo build --verbose -Z minimal-versions --features "kv kv_std" - run: cargo build --verbose -Z minimal-versions --features "kv kv_sval kv_serde" msrv: name: MSRV runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Install Rust run: | rustup update 1.60.0 --no-self-update rustup default 1.60.0 - run: | cargo test --verbose --manifest-path tests/Cargo.toml cargo test --verbose --manifest-path tests/Cargo.toml --features kv embedded: name: Embedded runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Install Rust run: | rustup update stable --no-self-update rustup default stable - run: rustup target add thumbv6m-none-eabi riscv32imc-unknown-none-elf - run: cargo build --verbose --target=thumbv6m-none-eabi - run: cargo build --verbose --target=riscv32imc-unknown-none-elf log-0.4.26/.gitignore000064400000000000000000000000321046102023000124610ustar 00000000000000target/ Cargo.lock .idea/ log-0.4.26/CHANGELOG.md000064400000000000000000000443551046102023000123220ustar 00000000000000# Change Log ## [Unreleased] ## [0.4.26] - 2025-02-18 ## What's Changed * Derive `Clone` for `kv::Value` by @SpriteOvO in https://github.com/rust-lang/log/pull/668 * Add `spdlog-rs` link to crate doc by @SpriteOvO in https://github.com/rust-lang/log/pull/669 **Full Changelog**: https://github.com/rust-lang/log/compare/0.4.25...0.4.26 ## [0.4.25] - 2025-01-14 ## What's Changed * Revert loosening of kv cargo features by @KodrAus in https://github.com/rust-lang/log/pull/662 **Full Changelog**: https://github.com/rust-lang/log/compare/0.4.24...0.4.25 ## [0.4.24] - 2025-01-11 ## What's Changed * Fix up kv feature activation by @KodrAus in https://github.com/rust-lang/log/pull/659 **Full Changelog**: https://github.com/rust-lang/log/compare/0.4.23...0.4.24 ## [0.4.23] - 2025-01-10 (yanked) ## What's Changed * Fix some typos by @Kleinmarb in https://github.com/rust-lang/log/pull/637 * Add logforth to implementation by @tisonkun in https://github.com/rust-lang/log/pull/638 * Add `spdlog-rs` link to README by @SpriteOvO in https://github.com/rust-lang/log/pull/639 * Add correct lifetime to kv::Value::to_borrowed_str by @stevenroose in https://github.com/rust-lang/log/pull/643 * docs: Add logforth as an impl by @tisonkun in https://github.com/rust-lang/log/pull/642 * Add clang_log implementation by @DDAN-17 in https://github.com/rust-lang/log/pull/646 * Bind lifetimes of &str returned from Key by the lifetime of 'k rather than the lifetime of the Key struct by @gbbosak in https://github.com/rust-lang/log/pull/648 * Fix up key lifetimes and add method to try get a borrowed key by @KodrAus in https://github.com/rust-lang/log/pull/653 * Add Ftail implementation by @tjardoo in https://github.com/rust-lang/log/pull/652 ## New Contributors * @Kleinmarb made their first contribution in https://github.com/rust-lang/log/pull/637 * @tisonkun made their first contribution in https://github.com/rust-lang/log/pull/638 * @SpriteOvO made their first contribution in https://github.com/rust-lang/log/pull/639 * @stevenroose made their first contribution in https://github.com/rust-lang/log/pull/643 * @DDAN-17 made their first contribution in https://github.com/rust-lang/log/pull/646 * @gbbosak made their first contribution in https://github.com/rust-lang/log/pull/648 * @tjardoo made their first contribution in https://github.com/rust-lang/log/pull/652 **Full Changelog**: https://github.com/rust-lang/log/compare/0.4.22...0.4.23 ## [0.4.22] - 2024-06-27 ## What's Changed * Add some clarifications to the library docs by @KodrAus in https://github.com/rust-lang/log/pull/620 * Add links to `colog` crate by @chrivers in https://github.com/rust-lang/log/pull/621 * adding line_number test + updating some testing infrastructure by @DIvkov575 in https://github.com/rust-lang/log/pull/619 * Clarify the actual set of functions that can race in _racy variants by @KodrAus in https://github.com/rust-lang/log/pull/623 * Replace deprecated std::sync::atomic::spin_loop_hint() by @Catamantaloedis in https://github.com/rust-lang/log/pull/625 * Check usage of max_level features by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/627 * Remove unneeded import by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/628 * Loosen orderings for logger initialization in https://github.com/rust-lang/log/pull/632. Originally by @pwoolcoc in https://github.com/rust-lang/log/pull/599 * Use Location::caller() for file and line info in https://github.com/rust-lang/log/pull/633. Originally by @Cassy343 in https://github.com/rust-lang/log/pull/520 ## New Contributors * @chrivers made their first contribution in https://github.com/rust-lang/log/pull/621 * @DIvkov575 made their first contribution in https://github.com/rust-lang/log/pull/619 * @Catamantaloedis made their first contribution in https://github.com/rust-lang/log/pull/625 **Full Changelog**: https://github.com/rust-lang/log/compare/0.4.21...0.4.22 ## [0.4.21] - 2024-02-27 ## What's Changed * Minor clippy nits by @nyurik in https://github.com/rust-lang/log/pull/578 * Simplify Display impl by @nyurik in https://github.com/rust-lang/log/pull/579 * Set all crates to 2021 edition by @nyurik in https://github.com/rust-lang/log/pull/580 * Various changes based on review by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/583 * Fix typo in file_static() method doc by @dimo414 in https://github.com/rust-lang/log/pull/590 * Specialize empty key value pairs by @EFanZh in https://github.com/rust-lang/log/pull/576 * Fix incorrect lifetime in Value::to_str() by @peterjoel in https://github.com/rust-lang/log/pull/587 * Remove some API of the key-value feature by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/585 * Add logcontrol-log and log-reload by @swsnr in https://github.com/rust-lang/log/pull/595 * Add Serialization section to kv::Value docs by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/593 * Rename Value::to_str to to_cow_str by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/592 * Clarify documentation and simplify initialization of `STATIC_MAX_LEVEL` by @ptosi in https://github.com/rust-lang/log/pull/594 * Update docs to 2021 edition, test by @nyurik in https://github.com/rust-lang/log/pull/577 * Add "alterable_logger" link to README.md by @brummer-simon in https://github.com/rust-lang/log/pull/589 * Normalize line ending by @EFanZh in https://github.com/rust-lang/log/pull/602 * Remove `ok_or` in favor of `Option::ok_or` by @AngelicosPhosphoros in https://github.com/rust-lang/log/pull/607 * Use `Acquire` ordering for initialization check by @AngelicosPhosphoros in https://github.com/rust-lang/log/pull/610 * Get structured logging API ready for stabilization by @KodrAus in https://github.com/rust-lang/log/pull/613 ## New Contributors * @nyurik made their first contribution in https://github.com/rust-lang/log/pull/578 * @dimo414 made their first contribution in https://github.com/rust-lang/log/pull/590 * @peterjoel made their first contribution in https://github.com/rust-lang/log/pull/587 * @ptosi made their first contribution in https://github.com/rust-lang/log/pull/594 * @brummer-simon made their first contribution in https://github.com/rust-lang/log/pull/589 * @AngelicosPhosphoros made their first contribution in https://github.com/rust-lang/log/pull/607 ## [0.4.20] - 2023-07-11 * Remove rustversion dev-dependency by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/568 * Remove `local_inner_macros` usage by @EFanZh in https://github.com/rust-lang/log/pull/570 ## [0.4.19] - 2023-06-10 * Use target_has_atomic instead of the old atomic_cas cfg by @GuillaumeGomez in https://github.com/rust-lang/log/pull/555 * Put MSRV into Cargo.toml by @est31 in https://github.com/rust-lang/log/pull/557 ## [0.4.18] - 2023-05-28 * fix Markdown links (again) by @hellow554 in https://github.com/rust-lang/log/pull/513 * add cargo doc to workflow by @hellow554 in https://github.com/rust-lang/log/pull/515 * Apply Clippy lints by @hellow554 in https://github.com/rust-lang/log/pull/516 * Replace ad-hoc eq_ignore_ascii_case with slice::eq_ignore_ascii_case by @glandium in https://github.com/rust-lang/log/pull/519 * fix up windows targets by @KodrAus in https://github.com/rust-lang/log/pull/528 * typo fix by @jiangying000 in https://github.com/rust-lang/log/pull/529 * Remove dependency on cfg_if by @EriKWDev in https://github.com/rust-lang/log/pull/536 * GitHub Workflows security hardening by @sashashura in https://github.com/rust-lang/log/pull/538 * Fix build status badge by @atouchet in https://github.com/rust-lang/log/pull/539 * Add call_logger to the documentation by @a1ecbr0wn in https://github.com/rust-lang/log/pull/547 * Use stable internals for key-value API by @KodrAus in https://github.com/rust-lang/log/pull/550 * Change wording of list of implementations by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/553 * Add std-logger to list of implementations by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/554 * Add `set_max_level_racy` and gate `set_max_level` by @djkoloski in https://github.com/rust-lang/log/pull/544 * [doc] src/lib.rs : prefix an unused variable with an underscore by @OccupyMars2025 in https://github.com/rust-lang/log/pull/561 * [doc] src/macros.rs : correct grammar errors of an example in lib documentation by @OccupyMars2025 in https://github.com/rust-lang/log/pull/562 ## [0.4.17] - 2022-04-29 * Update `kv_unstable` internal dependencies. ## [0.4.16] - 2022-03-22 * Fix a conflict with unqualified `Option` use in macros. ## [0.4.15] - 2022-02-23 * Silence a warning about the deprecated `spin_loop_hint`. * Relax ordering in the atomic `set_max_level` call. * Add thumbv4t-none-eabi to targets that don't support atomics * Allow levels to be iterated over. * Implement `Log` on some common wrapper types. * Improvements to test coverage. * Improvements to documentation. * Add key-value support to the `log!` macros. * Tighten `kv_unstable` internal dependencies, so they don't bump past their current alpha. * Add a simple visit API to `kv_unstable`. * Support `NonZero*` integers as values in structured logging * Support static strings as keys in structured logging ## [0.4.14] - 2021-01-27 * Remove the `__private_api_log_lit` special case. * Fixed incorrect combination of `kv_unstable` and `std` features causing compile failures. * Remove unstable `Value::to_*` conversions that were incorrectly using `as`. * Rename unstable `Value::to_error` to `Value::to_borrowed_error`. ## [0.4.13] - 2021-01-11 * This is the same as `0.4.11`, except with a `kv_unstable_std` feature added to aid migrating current dependents to `0.4.14` (which was originally going to be `0.4.13` until it was decided to create a patch from `0.4.11` to minimize disruption). ## [0.4.12] - 2020-12-24 ### New * Support platforms without atomics by racing instead of failing to compile * Implement `Log` for `Box` * Update `cfg-if` to `1.0` * Internal reworks of the structured logging API. Removed the `Fill` API and added `source::as_map` and `source::as_list` to easily serialize a `Source` as either a map of `{key: value, ..}` or as a list of `[(key, value), ..]`. ### Fixed * Fixed deserialization of `LevelFilter` to use their `u64` index variants ## [0.4.11] - 2020-07-09 ### New * Support coercing structured values into concrete types. * Reference the `win_dbg_logger` in the readme. ### Fixed * Updates a few deprecated items used internally. * Fixed issues in docs and expands sections. * Show the correct build badge in the readme. * Fix up a possible inference breakage with structured value errors. * Respect formatting flags in structured value formatting. ## [0.4.10] - 2019-12-16 (yanked) ### Fixed * Fixed the `log!` macros, so they work in expression context (this regressed in `0.4.9`, which has been yanked). ## [0.4.9] - 2019-12-12 (yanked) ### Minimum Supported Rust Version This release bumps the minimum compiler version to `1.31.0`. This was mainly needed for `cfg-if`, but between `1.16.0` and `1.31.0` there are a lot of language and library improvements we now take advantage of. ### New * Unstable support for capturing key-value pairs in a record using the `log!` macros ### Improved * Better documentation for max level filters. * Internal updates to line up with bumped MSRV ## [0.4.8] - 2019-07-28 ### New * Support attempting to get `Record` fields as static strings. ## [0.4.7] - 2019-07-06 ### New * Support for embedded environments with thread-unsafe initialization. * Initial unstable support for capturing structured data under the `kv_unstable` feature gate. This new API doesn't affect existing users and may change in future patches (so those changes may not appear in the changelog until it stabilizes). ### Improved * Docs for using `log` with the 2018 edition. * Error messages for macros missing arguments. ## [0.4.6] - 2018-10-27 ### Improved * Support 2018-style macro import for the `log_enabled!` macro. ## [0.4.5] - 2018-09-03 ### Improved * Make `log`'s internal helper macros less likely to conflict with user-defined macros. ## [0.4.4] - 2018-08-17 ### Improved * Support 2018-style imports of the log macros. ## [0.4.3] - 2018-06-29 ### Improved * More code generation improvements. ## [0.4.2] - 2018-06-05 ### Improved * Log invocations now generate less code. ### Fixed * Example Logger implementations now properly set the max log level. ## [0.4.1] - 2017-12-30 ### Fixed * Some doc links were fixed. ## [0.4.0] - 2017-12-24 The changes in this release include cleanup of some obscure functionality and a more robust public API designed to support bridges to other logging systems, and provide more flexibility to new features in the future. ### Compatibility Vast portions of the Rust ecosystem use the 0.3.x release series of log, and we don't want to force the community to go through the pain of upgrading every crate to 0.4.x at the exact same time. Along with 0.4.0, we've published a new 0.3.9 release which acts as a "shim" over 0.4.0. This will allow crates using either version to coexist without losing messages from one side or the other. There is one caveat - a log message generated by a crate using 0.4.x but consumed by a logging implementation using 0.3.x will not have a file name or module path. Applications affected by this can upgrade their logging implementations to one using 0.4.x to avoid losing this information. The other direction does not lose any information, fortunately! **TL;DR** Libraries should feel comfortable upgrading to 0.4.0 without treating that as a breaking change. Applications may need to update their logging implementation (e.g. env-logger) to a newer version using log 0.4.x to avoid losing module and file information. ### New * The crate is now `no_std` by default. * `Level` and `LevelFilter` now implement `Serialize` and `Deserialize` when the `serde` feature is enabled. * The `Record` and `Metadata` types can now be constructed by third-party code via a builder API. * The `logger` free function returns a reference to the logger implementation. This, along with the ability to construct `Record`s, makes it possible to bridge from another logging framework to this one without digging into the private internals of the crate. The standard `error!` `warn!`, etc., macros now exclusively use the public API of the crate rather than "secret" internal APIs. * `Log::flush` has been added to allow crates to tell the logging implementation to ensure that all "in flight" log events have been persisted. This can be used, for example, just before an application exits to ensure that asynchronous log sinks finish their work. ### Removed * The `shutdown` and `shutdown_raw` functions have been removed. Supporting shutdown significantly complicated the implementation and imposed a performance cost on each logging operation. * The `log_panics` function and its associated `nightly` Cargo feature have been removed. Use the [log-panics](https://crates.io/crates/log-panics) instead. ### Changed * The `Log` prefix has been removed from type names. For example, `LogLevelFilter` is now `LevelFilter`, and `LogRecord` is now `Record`. * The `MaxLogLevelFilter` object has been removed in favor of a `set_max_level` free function. * The `set_logger` free functions have been restructured. The logger is now directly passed to the functions rather than a closure which returns the logger. `set_logger` now takes a `&'static Log` and is usable in `no_std` contexts in place of the old `set_logger_raw`. `set_boxed_logger` is a convenience function which takes a `Box` but otherwise acts like `set_logger`. It requires the `std` feature. * The `file` and `module_path` values in `Record` no longer have the `'static` lifetime to support integration with other logging frameworks that don't provide a `'static` lifetime for the equivalent values. * The `file`, `line`, and `module_path` values in `Record` are now `Option`s to support integration with other logging frameworks that don't provide those values. ### In the Future * We're looking to add support for *structured* logging - the inclusion of extra key-value pairs of information in a log event in addition to the normal string message. This should be able to be added in a backwards compatible manner to the 0.4.x series when the design is worked out. ## Older Look at the [release tags] for information about older releases. [Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.26...HEAD [0.4.26]: https://github.com/rust-lang/log/compare/0.4.25...0.4.26 [0.4.25]: https://github.com/rust-lang/log/compare/0.4.24...0.4.25 [0.4.24]: https://github.com/rust-lang/log/compare/0.4.23...0.4.24 [0.4.23]: https://github.com/rust-lang/log/compare/0.4.22...0.4.23 [0.4.22]: https://github.com/rust-lang/log/compare/0.4.21...0.4.22 [0.4.21]: https://github.com/rust-lang/log/compare/0.4.20...0.4.21 [0.4.20]: https://github.com/rust-lang-nursery/log/compare/0.4.19...0.4.20 [0.4.19]: https://github.com/rust-lang-nursery/log/compare/0.4.18...0.4.19 [0.4.18]: https://github.com/rust-lang-nursery/log/compare/0.4.17...0.4.18 [0.4.17]: https://github.com/rust-lang-nursery/log/compare/0.4.16...0.4.17 [0.4.16]: https://github.com/rust-lang-nursery/log/compare/0.4.15...0.4.16 [0.4.15]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.15 [0.4.14]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.14 [0.4.13]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.13 [0.4.12]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.12 [0.4.11]: https://github.com/rust-lang-nursery/log/compare/0.4.10...0.4.11 [0.4.10]: https://github.com/rust-lang-nursery/log/compare/0.4.9...0.4.10 [0.4.9]: https://github.com/rust-lang-nursery/log/compare/0.4.8...0.4.9 [0.4.8]: https://github.com/rust-lang-nursery/log/compare/0.4.7...0.4.8 [0.4.7]: https://github.com/rust-lang-nursery/log/compare/0.4.6...0.4.7 [0.4.6]: https://github.com/rust-lang-nursery/log/compare/0.4.5...0.4.6 [0.4.5]: https://github.com/rust-lang-nursery/log/compare/0.4.4...0.4.5 [0.4.4]: https://github.com/rust-lang-nursery/log/compare/0.4.3...0.4.4 [0.4.3]: https://github.com/rust-lang-nursery/log/compare/0.4.2...0.4.3 [0.4.2]: https://github.com/rust-lang-nursery/log/compare/0.4.1...0.4.2 [0.4.1]: https://github.com/rust-lang-nursery/log/compare/0.4.0...0.4.1 [0.4.0]: https://github.com/rust-lang-nursery/log/compare/0.3.8...0.4.0 [release tags]: https://github.com/rust-lang-nursery/log/releases log-0.4.26/Cargo.lock0000644000000146010000000000100076630ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "erased-serde" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" dependencies = [ "serde", "typeid", ] [[package]] name = "itoa" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "log" version = "0.4.26" dependencies = [ "proc-macro2", "serde", "serde_json", "serde_test", "sval", "sval_derive", "sval_ref", "value-bag", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "proc-macro2" version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "serde" version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_fmt" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d4ddca14104cd60529e8c7f7ba71a2c8acd8f7f5cfcdc2faf97eeb7c3010a4" dependencies = [ "serde", ] [[package]] name = "serde_json" version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_test" version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" dependencies = [ "serde", ] [[package]] name = "sval" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c2f18f53c889ec3dfe1c08b20fd51406d09b14bf18b366416718763ccff05a" [[package]] name = "sval_buffer" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b8cb1bb48d0bed828b908e6b99e7ab8c7244994dc27948a2e31d42e8c4d77c1" dependencies = [ "sval", "sval_ref", ] [[package]] name = "sval_derive" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aa14bfe7bb752a869ba1ddac19a87c195a7894f53c3fe49288db776dd7781c2" dependencies = [ "sval_derive_macros", ] [[package]] name = "sval_derive_macros" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf2b3af5021d4ed853d720836e1f238d81f9c24dda16ef815c6797dae9655193" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "sval_dynamic" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba574872d4ad653071a9db76c49656082db83a37cd5f559874273d36b4a02b9d" dependencies = [ "sval", ] [[package]] name = "sval_fmt" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "944450b2dbbf8aae98537776b399b23d72b19243ee42522cfd110305f3c9ba5a" dependencies = [ "itoa", "ryu", "sval", ] [[package]] name = "sval_json" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "411bbd543c413796ccfbaa44f6676e20032b6c69e4996cb6c3e6ef30c79b96d1" dependencies = [ "itoa", "ryu", "sval", ] [[package]] name = "sval_nested" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30582d2a90869b380f8260559138c1b68ac3e0765520959f22a1a1fdca31769" dependencies = [ "sval", "sval_buffer", "sval_ref", ] [[package]] name = "sval_ref" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "762d3fbf3c0869064b7c93808c67ad2ed0292dde9b060ac282817941d4707dff" dependencies = [ "sval", ] [[package]] name = "sval_serde" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "752d307438c6a6a3d095a2fecf6950cfb946d301a5bd6b57f047db4f6f8d97b9" dependencies = [ "serde", "sval", "sval_nested", ] [[package]] name = "syn" version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "typeid" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" [[package]] name = "unicode-ident" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" [[package]] name = "value-bag" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" dependencies = [ "value-bag-serde1", "value-bag-sval2", ] [[package]] name = "value-bag-serde1" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bb773bd36fd59c7ca6e336c94454d9c66386416734817927ac93d81cb3c5b0b" dependencies = [ "erased-serde", "serde", "serde_fmt", ] [[package]] name = "value-bag-sval2" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a916a702cac43a88694c97657d449775667bcd14b70419441d05b7fea4a83a" dependencies = [ "sval", "sval_buffer", "sval_dynamic", "sval_fmt", "sval_json", "sval_ref", "sval_serde", ] log-0.4.26/Cargo.toml0000644000000051530000000000100077100ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.60.0" name = "log" version = "0.4.26" authors = ["The Rust Project Developers"] build = false exclude = ["rfcs/**/*"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = """ A lightweight logging facade for Rust """ documentation = "https://docs.rs/log" readme = "README.md" keywords = ["logging"] categories = ["development-tools::debugging"] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/log" [package.metadata.docs.rs] features = [ "std", "serde", "kv_std", "kv_sval", "kv_serde", ] [features] kv = [] kv_serde = [ "kv_std", "value-bag/serde", "serde", ] kv_std = [ "std", "kv", "value-bag/error", ] kv_sval = [ "kv", "value-bag/sval", "sval", "sval_ref", ] kv_unstable = [ "kv", "value-bag", ] kv_unstable_serde = [ "kv_serde", "kv_unstable_std", ] kv_unstable_std = [ "kv_std", "kv_unstable", ] kv_unstable_sval = [ "kv_sval", "kv_unstable", ] max_level_debug = [] max_level_error = [] max_level_info = [] max_level_off = [] max_level_trace = [] max_level_warn = [] release_max_level_debug = [] release_max_level_error = [] release_max_level_info = [] release_max_level_off = [] release_max_level_trace = [] release_max_level_warn = [] std = [] [lib] name = "log" path = "src/lib.rs" [[bench]] name = "value" path = "benches/value.rs" [dependencies.serde] version = "1.0" optional = true default-features = false [dependencies.sval] version = "2.1" optional = true default-features = false [dependencies.sval_ref] version = "2.1" optional = true default-features = false [dependencies.value-bag] version = "1.7" features = ["inline-i128"] optional = true default-features = false [dev-dependencies.proc-macro2] version = "1.0.63" default-features = false [dev-dependencies.serde] version = "1.0" features = ["derive"] [dev-dependencies.serde_json] version = "1.0" [dev-dependencies.serde_test] version = "1.0" [dev-dependencies.sval] version = "2.1" [dev-dependencies.sval_derive] version = "2.1" [dev-dependencies.value-bag] version = "1.7" features = ["test"] log-0.4.26/Cargo.toml.orig000064400000000000000000000046661046102023000134010ustar 00000000000000[package] name = "log" version = "0.4.26" # remember to update html_root_url authors = ["The Rust Project Developers"] license = "MIT OR Apache-2.0" readme = "README.md" repository = "https://github.com/rust-lang/log" documentation = "https://docs.rs/log" description = """ A lightweight logging facade for Rust """ categories = ["development-tools::debugging"] keywords = ["logging"] exclude = ["rfcs/**/*"] rust-version = "1.60.0" edition = "2021" [package.metadata.docs.rs] features = ["std", "serde", "kv_std", "kv_sval", "kv_serde"] [[test]] name = "integration" path = "tests/integration.rs" harness = false [[test]] name = "macros" path = "tests/macros.rs" harness = true [features] max_level_off = [] max_level_error = [] max_level_warn = [] max_level_info = [] max_level_debug = [] max_level_trace = [] release_max_level_off = [] release_max_level_error = [] release_max_level_warn = [] release_max_level_info = [] release_max_level_debug = [] release_max_level_trace = [] std = [] kv = [] kv_sval = ["kv", "value-bag/sval", "sval", "sval_ref"] kv_std = ["std", "kv", "value-bag/error"] kv_serde = ["kv_std", "value-bag/serde", "serde"] # Deprecated: use `kv_*` instead # These `*_unstable` features will be removed in a future release kv_unstable = ["kv", "value-bag"] kv_unstable_sval = ["kv_sval", "kv_unstable"] kv_unstable_std = ["kv_std", "kv_unstable"] kv_unstable_serde = ["kv_serde", "kv_unstable_std"] [dependencies] serde = { version = "1.0", optional = true, default-features = false } sval = { version = "2.1", optional = true, default-features = false } sval_ref = { version = "2.1", optional = true, default-features = false } value-bag = { version = "1.7", optional = true, default-features = false, features = ["inline-i128"] } [dev-dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_test = "1.0" sval = { version = "2.1" } sval_derive = { version = "2.1" } value-bag = { version = "1.7", features = ["test"] } # NOTE: log doesn't actually depent on this crate. However, our dependencies, # serde and sval, dependent on version 1.0 of the crate, which has problem fixed # in 1.0.60, specifically in the following commit # https://github.com/dtolnay/proc-macro2/commit/e31d61910049e097afdd3d27c37786309082bdcb. # By defining the crate as direct dependency we can increase its minimal # version making the minimal (crate) version CI happy. proc-macro2 = { version = "1.0.63", default-features = false } log-0.4.26/LICENSE-APACHE000064400000000000000000000251371046102023000124320ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. log-0.4.26/LICENSE-MIT000064400000000000000000000020571046102023000121360ustar 00000000000000Copyright (c) 2014 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. log-0.4.26/README.md000064400000000000000000000122261046102023000117600ustar 00000000000000log === A Rust library providing a lightweight logging *facade*. [![Build status](https://img.shields.io/github/actions/workflow/status/rust-lang/log/main.yml?branch=master)](https://github.com/rust-lang/log/actions) [![Latest version](https://img.shields.io/crates/v/log.svg)](https://crates.io/crates/log) [![Documentation](https://docs.rs/log/badge.svg)](https://docs.rs/log) ![License](https://img.shields.io/crates/l/log.svg) * [`log` documentation](https://docs.rs/log) A logging facade provides a single logging API that abstracts over the actual logging implementation. Libraries can use the logging API provided by this crate, and the consumer of those libraries can choose the logging implementation that is most suitable for its use case. ## Minimum supported `rustc` `1.60.0+` This version is explicitly tested in CI and may be bumped in any release as needed. Maintaining compatibility with older compilers is a priority though, so the bar for bumping the minimum supported version is set very high. Any changes to the supported minimum version will be called out in the release notes. ## Usage ### In libraries Libraries should link only to the `log` crate, and use the provided macros to log whatever information will be useful to downstream consumers: ```toml [dependencies] log = "0.4" ``` ```rust use log::{info, trace, warn}; pub fn shave_the_yak(yak: &mut Yak) { trace!("Commencing yak shaving"); loop { match find_a_razor() { Ok(razor) => { info!("Razor located: {razor}"); yak.shave(razor); break; } Err(err) => { warn!("Unable to locate a razor: {err}, retrying"); } } } } ``` ### In executables In order to produce log output, executables have to use a logger implementation compatible with the facade. There are many available implementations to choose from, here are some options: * Simple minimal loggers: * [`env_logger`](https://docs.rs/env_logger/*/env_logger/) * [`colog`](https://docs.rs/colog/*/colog/) * [`simple_logger`](https://docs.rs/simple_logger/*/simple_logger/) * [`simplelog`](https://docs.rs/simplelog/*/simplelog/) * [`pretty_env_logger`](https://docs.rs/pretty_env_logger/*/pretty_env_logger/) * [`stderrlog`](https://docs.rs/stderrlog/*/stderrlog/) * [`flexi_logger`](https://docs.rs/flexi_logger/*/flexi_logger/) * [`call_logger`](https://docs.rs/call_logger/*/call_logger/) * [`std-logger`](https://docs.rs/std-logger/*/std_logger/) * [`structured-logger`](https://docs.rs/structured-logger/latest/structured_logger/) * [`clang_log`](https://docs.rs/clang_log/latest/clang_log) * [`ftail`](https://docs.rs/ftail/latest/ftail/) * Complex configurable frameworks: * [`log4rs`](https://docs.rs/log4rs/*/log4rs/) * [`logforth`](https://docs.rs/logforth/*/logforth/) * [`fern`](https://docs.rs/fern/*/fern/) * [`spdlog-rs`](https://docs.rs/spdlog-rs/*/spdlog/) * Adaptors for other facilities: * [`syslog`](https://docs.rs/syslog/*/syslog/) * [`systemd-journal-logger`](https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/) * [`slog-stdlog`](https://docs.rs/slog-stdlog/*/slog_stdlog/) * [`android_log`](https://docs.rs/android_log/*/android_log/) * [`win_dbg_logger`](https://docs.rs/win_dbg_logger/*/win_dbg_logger/) * [`db_logger`](https://docs.rs/db_logger/*/db_logger/) * [`log-to-defmt`](https://docs.rs/log-to-defmt/*/log_to_defmt/) * [`logcontrol-log`](https://docs.rs/logcontrol-log/*/logcontrol_log/) * For WebAssembly binaries: * [`console_log`](https://docs.rs/console_log/*/console_log/) * For dynamic libraries: * You may need to construct [an FFI-safe wrapper over `log`](https://github.com/rust-lang/log/issues/421) to initialize in your libraries. * Utilities: * [`log_err`](https://docs.rs/log_err/*/log_err/) * [`log-reload`](https://docs.rs/log-reload/*/log_reload/) * [`alterable_logger`](https://docs.rs/alterable_logger/*/alterable_logger) Executables should choose a logger implementation and initialize it early in the runtime of the program. Logger implementations will typically include a function to do this. Any log messages generated before the logger is initialized will be ignored. The executable itself may use the `log` crate to log as well. ## Structured logging If you enable the `kv` feature, you can associate structured data with your log records: ```rust use log::{info, trace, warn}; pub fn shave_the_yak(yak: &mut Yak) { // `yak:serde` will capture `yak` using its `serde::Serialize` impl // // You could also use `:?` for `Debug`, or `:%` for `Display`. For a // full list, see the `log` crate documentation trace!(target = "yak_events", yak:serde; "Commencing yak shaving"); loop { match find_a_razor() { Ok(razor) => { info!(razor; "Razor located"); yak.shave(razor); break; } Err(e) => { // `e:err` will capture `e` using its `std::error::Error` impl warn!(e:err; "Unable to locate a razor, retrying"); } } } } ``` log-0.4.26/benches/value.rs000064400000000000000000000007501046102023000135710ustar 00000000000000#![cfg(feature = "kv")] #![feature(test)] use log::kv::Value; #[bench] fn u8_to_value(b: &mut test::Bencher) { b.iter(|| Value::from(1u8)); } #[bench] fn u8_to_value_debug(b: &mut test::Bencher) { b.iter(|| Value::from_debug(&1u8)); } #[bench] fn str_to_value_debug(b: &mut test::Bencher) { b.iter(|| Value::from_debug(&"a string")); } #[bench] fn custom_to_value_debug(b: &mut test::Bencher) { #[derive(Debug)] struct A; b.iter(|| Value::from_debug(&A)); } log-0.4.26/src/__private_api.rs000064400000000000000000000060561046102023000144430ustar 00000000000000//! WARNING: this is not part of the crate's public API and is subject to change at any time use self::sealed::KVs; use crate::{Level, Metadata, Record}; use std::fmt::Arguments; use std::panic::Location; pub use std::{format_args, module_path, stringify}; #[cfg(not(feature = "kv"))] pub type Value<'a> = &'a str; mod sealed { /// Types for the `kv` argument. pub trait KVs<'a> { fn into_kvs(self) -> Option<&'a [(&'a str, super::Value<'a>)]>; } } // Types for the `kv` argument. impl<'a> KVs<'a> for &'a [(&'a str, Value<'a>)] { #[inline] fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> { Some(self) } } impl<'a> KVs<'a> for () { #[inline] fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> { None } } // Log implementation. fn log_impl( args: Arguments, level: Level, &(target, module_path, loc): &(&str, &'static str, &'static Location), kvs: Option<&[(&str, Value)]>, ) { #[cfg(not(feature = "kv"))] if kvs.is_some() { panic!("key-value support is experimental and must be enabled using the `kv` feature") } let mut builder = Record::builder(); builder .args(args) .level(level) .target(target) .module_path_static(Some(module_path)) .file_static(Some(loc.file())) .line(Some(loc.line())); #[cfg(feature = "kv")] builder.key_values(&kvs); crate::logger().log(&builder.build()); } pub fn log<'a, K>( args: Arguments, level: Level, target_module_path_and_loc: &(&str, &'static str, &'static Location), kvs: K, ) where K: KVs<'a>, { log_impl(args, level, target_module_path_and_loc, kvs.into_kvs()) } pub fn enabled(level: Level, target: &str) -> bool { crate::logger().enabled(&Metadata::builder().level(level).target(target).build()) } #[track_caller] pub fn loc() -> &'static Location<'static> { Location::caller() } #[cfg(feature = "kv")] mod kv_support { use crate::kv; pub type Value<'a> = kv::Value<'a>; // NOTE: Many functions here accept a double reference &&V // This is so V itself can be ?Sized, while still letting us // erase it to some dyn Trait (because &T is sized) pub fn capture_to_value<'a, V: kv::ToValue + ?Sized>(v: &'a &'a V) -> Value<'a> { v.to_value() } pub fn capture_debug<'a, V: core::fmt::Debug + ?Sized>(v: &'a &'a V) -> Value<'a> { Value::from_debug(v) } pub fn capture_display<'a, V: core::fmt::Display + ?Sized>(v: &'a &'a V) -> Value<'a> { Value::from_display(v) } #[cfg(feature = "kv_std")] pub fn capture_error<'a>(v: &'a (dyn std::error::Error + 'static)) -> Value<'a> { Value::from_dyn_error(v) } #[cfg(feature = "kv_sval")] pub fn capture_sval<'a, V: sval::Value + ?Sized>(v: &'a &'a V) -> Value<'a> { Value::from_sval(v) } #[cfg(feature = "kv_serde")] pub fn capture_serde<'a, V: serde::Serialize + ?Sized>(v: &'a &'a V) -> Value<'a> { Value::from_serde(v) } } #[cfg(feature = "kv")] pub use self::kv_support::*; log-0.4.26/src/kv/error.rs000064400000000000000000000044431046102023000134110ustar 00000000000000use std::fmt; /// An error encountered while working with structured data. #[derive(Debug)] pub struct Error { inner: Inner, } #[derive(Debug)] enum Inner { #[cfg(feature = "std")] Boxed(std_support::BoxedError), Msg(&'static str), #[cfg(feature = "value-bag")] Value(crate::kv::value::inner::Error), Fmt, } impl Error { /// Create an error from a message. pub fn msg(msg: &'static str) -> Self { Error { inner: Inner::Msg(msg), } } // Not public so we don't leak the `crate::kv::value::inner` API #[cfg(feature = "value-bag")] pub(super) fn from_value(err: crate::kv::value::inner::Error) -> Self { Error { inner: Inner::Value(err), } } // Not public so we don't leak the `crate::kv::value::inner` API #[cfg(feature = "value-bag")] pub(super) fn into_value(self) -> crate::kv::value::inner::Error { match self.inner { Inner::Value(err) => err, #[cfg(feature = "kv_std")] _ => crate::kv::value::inner::Error::boxed(self), #[cfg(not(feature = "kv_std"))] _ => crate::kv::value::inner::Error::msg("error inspecting a value"), } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Inner::*; match &self.inner { #[cfg(feature = "std")] Boxed(err) => err.fmt(f), #[cfg(feature = "value-bag")] Value(err) => err.fmt(f), Msg(msg) => msg.fmt(f), Fmt => fmt::Error.fmt(f), } } } impl From for Error { fn from(_: fmt::Error) -> Self { Error { inner: Inner::Fmt } } } #[cfg(feature = "std")] mod std_support { use super::*; use std::{error, io}; pub(super) type BoxedError = Box; impl Error { /// Create an error from a standard error type. pub fn boxed(err: E) -> Self where E: Into, { Error { inner: Inner::Boxed(err.into()), } } } impl error::Error for Error {} impl From for Error { fn from(err: io::Error) -> Self { Error::boxed(err) } } } log-0.4.26/src/kv/key.rs000064400000000000000000000070171046102023000130500ustar 00000000000000//! Structured keys. use std::borrow::Borrow; use std::fmt; /// A type that can be converted into a [`Key`](struct.Key.html). pub trait ToKey { /// Perform the conversion. fn to_key(&self) -> Key; } impl<'a, T> ToKey for &'a T where T: ToKey + ?Sized, { fn to_key(&self) -> Key { (**self).to_key() } } impl<'k> ToKey for Key<'k> { fn to_key(&self) -> Key { Key { key: self.key } } } impl ToKey for str { fn to_key(&self) -> Key { Key::from_str(self) } } /// A key in a key-value. // These impls must only be based on the as_str() representation of the key // If a new field (such as an optional index) is added to the key they must not affect comparison #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Key<'k> { // NOTE: This may become `Cow<'k, str>` key: &'k str, } impl<'k> Key<'k> { /// Get a key from a borrowed string. pub fn from_str(key: &'k str) -> Self { Key { key } } /// Get a borrowed string from this key. /// /// The lifetime of the returned string is bound to the borrow of `self` rather /// than to `'k`. pub fn as_str(&self) -> &str { self.key } /// Try get a borrowed string for the lifetime `'k` from this key. /// /// If the key is a borrow of a longer lived string, this method will return `Some`. /// If the key is internally buffered, this method will return `None`. pub fn to_borrowed_str(&self) -> Option<&'k str> { // NOTE: If the internals of `Key` support buffering this // won't be unconditionally `Some` anymore. We want to keep // this option open Some(self.key) } } impl<'k> fmt::Display for Key<'k> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.key.fmt(f) } } impl<'k> AsRef for Key<'k> { fn as_ref(&self) -> &str { self.as_str() } } impl<'k> Borrow for Key<'k> { fn borrow(&self) -> &str { self.as_str() } } impl<'k> From<&'k str> for Key<'k> { fn from(s: &'k str) -> Self { Key::from_str(s) } } #[cfg(feature = "std")] mod std_support { use super::*; use std::borrow::Cow; impl ToKey for String { fn to_key(&self) -> Key { Key::from_str(self) } } impl<'a> ToKey for Cow<'a, str> { fn to_key(&self) -> Key { Key::from_str(self) } } } #[cfg(feature = "kv_sval")] mod sval_support { use super::*; use sval::Value; use sval_ref::ValueRef; impl<'a> Value for Key<'a> { fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( &'sval self, stream: &mut S, ) -> sval::Result { self.key.stream(stream) } } impl<'a> ValueRef<'a> for Key<'a> { fn stream_ref + ?Sized>(&self, stream: &mut S) -> sval::Result { self.key.stream(stream) } } } #[cfg(feature = "kv_serde")] mod serde_support { use super::*; use serde::{Serialize, Serializer}; impl<'a> Serialize for Key<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.key.serialize(serializer) } } } #[cfg(test)] mod tests { use super::*; #[test] fn key_from_string() { assert_eq!("a key", Key::from_str("a key").as_str()); } #[test] fn key_to_borrowed() { assert_eq!("a key", Key::from_str("a key").to_borrowed_str().unwrap()); } } log-0.4.26/src/kv/mod.rs000064400000000000000000000174061046102023000130420ustar 00000000000000//! Structured logging. //! //! Add the `kv` feature to your `Cargo.toml` to enable //! this module: //! //! ```toml //! [dependencies.log] //! features = ["kv"] //! ``` //! //! # Structured logging in `log` //! //! Structured logging enhances traditional text-based log records with user-defined //! attributes. Structured logs can be analyzed using a variety of data processing //! techniques, without needing to find and parse attributes from unstructured text first. //! //! In `log`, user-defined attributes are part of a [`Source`] on the log record. //! Each attribute is a key-value; a pair of [`Key`] and [`Value`]. Keys are strings //! and values are a datum of any type that can be formatted or serialized. Simple types //! like strings, booleans, and numbers are supported, as well as arbitrarily complex //! structures involving nested objects and sequences. //! //! ## Adding key-values to log records //! //! Key-values appear before the message format in the `log!` macros: //! //! ``` //! # use log::info; //! info!(a = 1; "Something of interest"); //! ``` //! //! Key-values support the same shorthand identifier syntax as `format_args`: //! //! ``` //! # use log::info; //! let a = 1; //! //! info!(a; "Something of interest"); //! ``` //! //! Values are capturing using the [`ToValue`] trait by default. To capture a value //! using a different trait implementation, use a modifier after its key. Here's how //! the same example can capture `a` using its `Debug` implementation instead: //! //! ``` //! # use log::info; //! info!(a:? = 1; "Something of interest"); //! ``` //! //! The following capturing modifiers are supported: //! //! - `:?` will capture the value using `Debug`. //! - `:debug` will capture the value using `Debug`. //! - `:%` will capture the value using `Display`. //! - `:display` will capture the value using `Display`. //! - `:err` will capture the value using `std::error::Error` (requires the `kv_std` feature). //! - `:sval` will capture the value using `sval::Value` (requires the `kv_sval` feature). //! - `:serde` will capture the value using `serde::Serialize` (requires the `kv_serde` feature). //! //! ## Working with key-values on log records //! //! Use the [`Record::key_values`](../struct.Record.html#method.key_values) method to access key-values. //! //! Individual values can be pulled from the source by their key: //! //! ``` //! # fn main() -> Result<(), log::kv::Error> { //! use log::kv::{Source, Key, Value}; //! # let record = log::Record::builder().key_values(&[("a", 1)]).build(); //! //! // info!(a = 1; "Something of interest"); //! //! let a: Value = record.key_values().get(Key::from("a")).unwrap(); //! assert_eq!(1, a.to_i64().unwrap()); //! # Ok(()) //! # } //! ``` //! //! All key-values can also be enumerated using a [`VisitSource`]: //! //! ``` //! # fn main() -> Result<(), log::kv::Error> { //! use std::collections::BTreeMap; //! //! use log::kv::{self, Source, Key, Value, VisitSource}; //! //! struct Collect<'kvs>(BTreeMap, Value<'kvs>>); //! //! impl<'kvs> VisitSource<'kvs> for Collect<'kvs> { //! fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> { //! self.0.insert(key, value); //! //! Ok(()) //! } //! } //! //! let mut visitor = Collect(BTreeMap::new()); //! //! # let record = log::Record::builder().key_values(&[("a", 1), ("b", 2), ("c", 3)]).build(); //! // info!(a = 1, b = 2, c = 3; "Something of interest"); //! //! record.key_values().visit(&mut visitor)?; //! //! let collected = visitor.0; //! //! assert_eq!( //! vec!["a", "b", "c"], //! collected //! .keys() //! .map(|k| k.as_str()) //! .collect::>(), //! ); //! # Ok(()) //! # } //! ``` //! //! [`Value`]s have methods for conversions to common types: //! //! ``` //! # fn main() -> Result<(), log::kv::Error> { //! use log::kv::{Source, Key}; //! # let record = log::Record::builder().key_values(&[("a", 1)]).build(); //! //! // info!(a = 1; "Something of interest"); //! //! let a = record.key_values().get(Key::from("a")).unwrap(); //! //! assert_eq!(1, a.to_i64().unwrap()); //! # Ok(()) //! # } //! ``` //! //! Values also have their own [`VisitValue`] type. Value visitors are a lightweight //! API for working with primitives types: //! //! ``` //! # fn main() -> Result<(), log::kv::Error> { //! use log::kv::{self, Source, Key, VisitValue}; //! # let record = log::Record::builder().key_values(&[("a", 1)]).build(); //! //! struct IsNumeric(bool); //! //! impl<'kvs> VisitValue<'kvs> for IsNumeric { //! fn visit_any(&mut self, _value: kv::Value) -> Result<(), kv::Error> { //! self.0 = false; //! Ok(()) //! } //! //! fn visit_u64(&mut self, _value: u64) -> Result<(), kv::Error> { //! self.0 = true; //! Ok(()) //! } //! //! fn visit_i64(&mut self, _value: i64) -> Result<(), kv::Error> { //! self.0 = true; //! Ok(()) //! } //! //! fn visit_u128(&mut self, _value: u128) -> Result<(), kv::Error> { //! self.0 = true; //! Ok(()) //! } //! //! fn visit_i128(&mut self, _value: i128) -> Result<(), kv::Error> { //! self.0 = true; //! Ok(()) //! } //! //! fn visit_f64(&mut self, _value: f64) -> Result<(), kv::Error> { //! self.0 = true; //! Ok(()) //! } //! } //! //! // info!(a = 1; "Something of interest"); //! //! let a = record.key_values().get(Key::from("a")).unwrap(); //! //! let mut visitor = IsNumeric(false); //! //! a.visit(&mut visitor)?; //! //! let is_numeric = visitor.0; //! //! assert!(is_numeric); //! # Ok(()) //! # } //! ``` //! //! To serialize a value to a format like JSON, you can also use either `serde` or `sval`: //! //! ``` //! # fn main() -> Result<(), Box> { //! # #[cfg(feature = "serde")] //! # { //! # use log::kv::Key; //! #[derive(serde::Serialize)] //! struct Data { //! a: i32, b: bool, //! c: &'static str, //! } //! //! let data = Data { a: 1, b: true, c: "Some data" }; //! //! # let source = [("a", log::kv::Value::from_serde(&data))]; //! # let record = log::Record::builder().key_values(&source).build(); //! // info!(a = data; "Something of interest"); //! //! let a = record.key_values().get(Key::from("a")).unwrap(); //! //! assert_eq!("{\"a\":1,\"b\":true,\"c\":\"Some data\"}", serde_json::to_string(&a)?); //! # } //! # Ok(()) //! # } //! ``` //! //! The choice of serialization framework depends on the needs of the consumer. //! If you're in a no-std environment, you can use `sval`. In other cases, you can use `serde`. //! Log producers and log consumers don't need to agree on the serialization framework. //! A value can be captured using its `serde::Serialize` implementation and still be serialized //! through `sval` without losing any structure or data. //! //! Values can also always be formatted using the standard `Debug` and `Display` //! traits: //! //! ``` //! # use log::kv::Key; //! # #[derive(Debug)] //! struct Data { //! a: i32, //! b: bool, //! c: &'static str, //! } //! //! let data = Data { a: 1, b: true, c: "Some data" }; //! //! # let source = [("a", log::kv::Value::from_debug(&data))]; //! # let record = log::Record::builder().key_values(&source).build(); //! // info!(a = data; "Something of interest"); //! //! let a = record.key_values().get(Key::from("a")).unwrap(); //! //! assert_eq!("Data { a: 1, b: true, c: \"Some data\" }", format!("{a:?}")); //! ``` mod error; mod key; #[cfg(not(feature = "kv_unstable"))] mod source; #[cfg(not(feature = "kv_unstable"))] mod value; pub use self::error::Error; pub use self::key::{Key, ToKey}; pub use self::source::{Source, VisitSource}; pub use self::value::{ToValue, Value, VisitValue}; #[cfg(feature = "kv_unstable")] pub mod source; #[cfg(feature = "kv_unstable")] pub mod value; #[cfg(feature = "kv_unstable")] pub use self::source::Visitor; log-0.4.26/src/kv/source.rs000064400000000000000000000323131046102023000135550ustar 00000000000000//! Sources for key-values. //! //! This module defines the [`Source`] type and supporting APIs for //! working with collections of key-values. use crate::kv::{Error, Key, ToKey, ToValue, Value}; use std::fmt; /// A source of key-values. /// /// The source may be a single pair, a set of pairs, or a filter over a set of pairs. /// Use the [`VisitSource`](trait.VisitSource.html) trait to inspect the structured data /// in a source. /// /// A source is like an iterator over its key-values, except with a push-based API /// instead of a pull-based one. /// /// # Examples /// /// Enumerating the key-values in a source: /// /// ``` /// # fn main() -> Result<(), log::kv::Error> { /// use log::kv::{self, Source, Key, Value, VisitSource}; /// /// // A `VisitSource` that prints all key-values /// // VisitSources are fed the key-value pairs of each key-values /// struct Printer; /// /// impl<'kvs> VisitSource<'kvs> for Printer { /// fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> { /// println!("{key}: {value}"); /// /// Ok(()) /// } /// } /// /// // A source with 3 key-values /// // Common collection types implement the `Source` trait /// let source = &[ /// ("a", 1), /// ("b", 2), /// ("c", 3), /// ]; /// /// // Pass an instance of the `VisitSource` to a `Source` to visit it /// source.visit(&mut Printer)?; /// # Ok(()) /// # } /// ``` pub trait Source { /// Visit key-values. /// /// A source doesn't have to guarantee any ordering or uniqueness of key-values. /// If the given visitor returns an error then the source may early-return with it, /// even if there are more key-values. /// /// # Implementation notes /// /// A source should yield the same key-values to a subsequent visitor unless /// that visitor itself fails. fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error>; /// Get the value for a given key. /// /// If the key appears multiple times in the source then which key is returned /// is implementation specific. /// /// # Implementation notes /// /// A source that can provide a more efficient implementation of this method /// should override it. fn get(&self, key: Key) -> Option> { get_default(self, key) } /// Count the number of key-values that can be visited. /// /// # Implementation notes /// /// A source that knows the number of key-values upfront may provide a more /// efficient implementation. /// /// A subsequent call to `visit` should yield the same number of key-values. fn count(&self) -> usize { count_default(self) } } /// The default implementation of `Source::get` fn get_default<'v>(source: &'v (impl Source + ?Sized), key: Key) -> Option> { struct Get<'k, 'v> { key: Key<'k>, found: Option>, } impl<'k, 'kvs> VisitSource<'kvs> for Get<'k, 'kvs> { fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { if self.key == key { self.found = Some(value); } Ok(()) } } let mut get = Get { key, found: None }; let _ = source.visit(&mut get); get.found } /// The default implementation of `Source::count`. fn count_default(source: impl Source) -> usize { struct Count(usize); impl<'kvs> VisitSource<'kvs> for Count { fn visit_pair(&mut self, _: Key<'kvs>, _: Value<'kvs>) -> Result<(), Error> { self.0 += 1; Ok(()) } } let mut count = Count(0); let _ = source.visit(&mut count); count.0 } impl<'a, T> Source for &'a T where T: Source + ?Sized, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { Source::visit(&**self, visitor) } fn get(&self, key: Key) -> Option> { Source::get(&**self, key) } fn count(&self) -> usize { Source::count(&**self) } } impl Source for (K, V) where K: ToKey, V: ToValue, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { visitor.visit_pair(self.0.to_key(), self.1.to_value()) } fn get(&self, key: Key) -> Option> { if self.0.to_key() == key { Some(self.1.to_value()) } else { None } } fn count(&self) -> usize { 1 } } impl Source for [S] where S: Source, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { for source in self { source.visit(visitor)?; } Ok(()) } fn get(&self, key: Key) -> Option> { for source in self { if let Some(found) = source.get(key.clone()) { return Some(found); } } None } fn count(&self) -> usize { self.iter().map(Source::count).sum() } } impl Source for [S; N] where S: Source, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { Source::visit(self as &[_], visitor) } fn get(&self, key: Key) -> Option> { Source::get(self as &[_], key) } fn count(&self) -> usize { Source::count(self as &[_]) } } impl Source for Option where S: Source, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { if let Some(source) = self { source.visit(visitor)?; } Ok(()) } fn get(&self, key: Key) -> Option> { self.as_ref().and_then(|s| s.get(key)) } fn count(&self) -> usize { self.as_ref().map_or(0, Source::count) } } /// A visitor for the key-value pairs in a [`Source`](trait.Source.html). pub trait VisitSource<'kvs> { /// Visit a key-value pair. fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error>; } impl<'a, 'kvs, T> VisitSource<'kvs> for &'a mut T where T: VisitSource<'kvs> + ?Sized, { fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { (**self).visit_pair(key, value) } } impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugMap<'a, 'b> { fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { self.entry(&key, &value); Ok(()) } } impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugList<'a, 'b> { fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { self.entry(&(key, value)); Ok(()) } } impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugSet<'a, 'b> { fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { self.entry(&(key, value)); Ok(()) } } impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugTuple<'a, 'b> { fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { self.field(&key); self.field(&value); Ok(()) } } #[cfg(feature = "std")] mod std_support { use super::*; use std::borrow::Borrow; use std::collections::{BTreeMap, HashMap}; use std::hash::{BuildHasher, Hash}; use std::rc::Rc; use std::sync::Arc; impl Source for Box where S: Source + ?Sized, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { Source::visit(&**self, visitor) } fn get(&self, key: Key) -> Option> { Source::get(&**self, key) } fn count(&self) -> usize { Source::count(&**self) } } impl Source for Arc where S: Source + ?Sized, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { Source::visit(&**self, visitor) } fn get(&self, key: Key) -> Option> { Source::get(&**self, key) } fn count(&self) -> usize { Source::count(&**self) } } impl Source for Rc where S: Source + ?Sized, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { Source::visit(&**self, visitor) } fn get(&self, key: Key) -> Option> { Source::get(&**self, key) } fn count(&self) -> usize { Source::count(&**self) } } impl Source for Vec where S: Source, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { Source::visit(&**self, visitor) } fn get(&self, key: Key) -> Option> { Source::get(&**self, key) } fn count(&self) -> usize { Source::count(&**self) } } impl<'kvs, V> VisitSource<'kvs> for Box where V: VisitSource<'kvs> + ?Sized, { fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { (**self).visit_pair(key, value) } } impl Source for HashMap where K: ToKey + Borrow + Eq + Hash, V: ToValue, S: BuildHasher, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { for (key, value) in self { visitor.visit_pair(key.to_key(), value.to_value())?; } Ok(()) } fn get(&self, key: Key) -> Option> { HashMap::get(self, key.as_str()).map(|v| v.to_value()) } fn count(&self) -> usize { self.len() } } impl Source for BTreeMap where K: ToKey + Borrow + Ord, V: ToValue, { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { for (key, value) in self { visitor.visit_pair(key.to_key(), value.to_value())?; } Ok(()) } fn get(&self, key: Key) -> Option> { BTreeMap::get(self, key.as_str()).map(|v| v.to_value()) } fn count(&self) -> usize { self.len() } } #[cfg(test)] mod tests { use crate::kv::value; use super::*; #[test] fn count() { assert_eq!(1, Source::count(&Box::new(("a", 1)))); assert_eq!(2, Source::count(&vec![("a", 1), ("b", 2)])); } #[test] fn get() { let source = vec![("a", 1), ("b", 2), ("a", 1)]; assert_eq!( value::inner::Token::I64(1), Source::get(&source, Key::from_str("a")).unwrap().to_token() ); let source = Box::new(None::<(&str, i32)>); assert!(Source::get(&source, Key::from_str("a")).is_none()); } #[test] fn hash_map() { let mut map = HashMap::new(); map.insert("a", 1); map.insert("b", 2); assert_eq!(2, Source::count(&map)); assert_eq!( value::inner::Token::I64(1), Source::get(&map, Key::from_str("a")).unwrap().to_token() ); } #[test] fn btree_map() { let mut map = BTreeMap::new(); map.insert("a", 1); map.insert("b", 2); assert_eq!(2, Source::count(&map)); assert_eq!( value::inner::Token::I64(1), Source::get(&map, Key::from_str("a")).unwrap().to_token() ); } } } // NOTE: Deprecated; but aliases can't carry this attribute #[cfg(feature = "kv_unstable")] pub use VisitSource as Visitor; #[cfg(test)] mod tests { use crate::kv::value; use super::*; #[test] fn source_is_object_safe() { fn _check(_: &dyn Source) {} } #[test] fn visitor_is_object_safe() { fn _check(_: &dyn VisitSource) {} } #[test] fn count() { struct OnePair { key: &'static str, value: i32, } impl Source for OnePair { fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { visitor.visit_pair(self.key.to_key(), self.value.to_value()) } } assert_eq!(1, Source::count(&("a", 1))); assert_eq!(2, Source::count(&[("a", 1), ("b", 2)] as &[_])); assert_eq!(0, Source::count(&None::<(&str, i32)>)); assert_eq!(1, Source::count(&OnePair { key: "a", value: 1 })); } #[test] fn get() { let source = &[("a", 1), ("b", 2), ("a", 1)] as &[_]; assert_eq!( value::inner::Token::I64(1), Source::get(source, Key::from_str("a")).unwrap().to_token() ); assert_eq!( value::inner::Token::I64(2), Source::get(source, Key::from_str("b")).unwrap().to_token() ); assert!(Source::get(&source, Key::from_str("c")).is_none()); let source = None::<(&str, i32)>; assert!(Source::get(&source, Key::from_str("a")).is_none()); } } log-0.4.26/src/kv/value.rs000064400000000000000000001172371046102023000134020ustar 00000000000000//! Structured values. //! //! This module defines the [`Value`] type and supporting APIs for //! capturing and serializing them. use std::fmt; pub use crate::kv::Error; /// A type that can be converted into a [`Value`](struct.Value.html). pub trait ToValue { /// Perform the conversion. fn to_value(&self) -> Value; } impl<'a, T> ToValue for &'a T where T: ToValue + ?Sized, { fn to_value(&self) -> Value { (**self).to_value() } } impl<'v> ToValue for Value<'v> { fn to_value(&self) -> Value { Value { inner: self.inner.clone(), } } } /// A value in a key-value. /// /// Values are an anonymous bag containing some structured datum. /// /// # Capturing values /// /// There are a few ways to capture a value: /// /// - Using the `Value::from_*` methods. /// - Using the `ToValue` trait. /// - Using the standard `From` trait. /// /// ## Using the `Value::from_*` methods /// /// `Value` offers a few constructor methods that capture values of different kinds. /// /// ``` /// use log::kv::Value; /// /// let value = Value::from_debug(&42i32); /// /// assert_eq!(None, value.to_i64()); /// ``` /// /// ## Using the `ToValue` trait /// /// The `ToValue` trait can be used to capture values generically. /// It's the bound used by `Source`. /// /// ``` /// # use log::kv::ToValue; /// let value = 42i32.to_value(); /// /// assert_eq!(Some(42), value.to_i64()); /// ``` /// /// ## Using the standard `From` trait /// /// Standard types that implement `ToValue` also implement `From`. /// /// ``` /// use log::kv::Value; /// /// let value = Value::from(42i32); /// /// assert_eq!(Some(42), value.to_i64()); /// ``` /// /// # Data model /// /// Values can hold one of a number of types: /// /// - **Null:** The absence of any other meaningful value. Note that /// `Some(Value::null())` is not the same as `None`. The former is /// `null` while the latter is `undefined`. This is important to be /// able to tell the difference between a key-value that was logged, /// but its value was empty (`Some(Value::null())`) and a key-value /// that was never logged at all (`None`). /// - **Strings:** `str`, `char`. /// - **Booleans:** `bool`. /// - **Integers:** `u8`-`u128`, `i8`-`i128`, `NonZero*`. /// - **Floating point numbers:** `f32`-`f64`. /// - **Errors:** `dyn (Error + 'static)`. /// - **`serde`:** Any type in `serde`'s data model. /// - **`sval`:** Any type in `sval`'s data model. /// /// # Serialization /// /// Values provide a number of ways to be serialized. /// /// For basic types the [`Value::visit`] method can be used to extract the /// underlying typed value. However, this is limited in the amount of types /// supported (see the [`VisitValue`] trait methods). /// /// For more complex types one of the following traits can be used: /// * `sval::Value`, requires the `kv_sval` feature. /// * `serde::Serialize`, requires the `kv_serde` feature. /// /// You don't need a visitor to serialize values through `serde` or `sval`. /// /// A value can always be serialized using any supported framework, regardless /// of how it was captured. If, for example, a value was captured using its /// `Display` implementation, it will serialize through `serde` as a string. If it was /// captured as a struct using `serde`, it will also serialize as a struct /// through `sval`, or can be formatted using a `Debug`-compatible representation. #[derive(Clone)] pub struct Value<'v> { inner: inner::Inner<'v>, } impl<'v> Value<'v> { /// Get a value from a type implementing `ToValue`. pub fn from_any(value: &'v T) -> Self where T: ToValue, { value.to_value() } /// Get a value from a type implementing `std::fmt::Debug`. pub fn from_debug(value: &'v T) -> Self where T: fmt::Debug, { Value { inner: inner::Inner::from_debug(value), } } /// Get a value from a type implementing `std::fmt::Display`. pub fn from_display(value: &'v T) -> Self where T: fmt::Display, { Value { inner: inner::Inner::from_display(value), } } /// Get a value from a type implementing `serde::Serialize`. #[cfg(feature = "kv_serde")] pub fn from_serde(value: &'v T) -> Self where T: serde::Serialize, { Value { inner: inner::Inner::from_serde1(value), } } /// Get a value from a type implementing `sval::Value`. #[cfg(feature = "kv_sval")] pub fn from_sval(value: &'v T) -> Self where T: sval::Value, { Value { inner: inner::Inner::from_sval2(value), } } /// Get a value from a dynamic `std::fmt::Debug`. pub fn from_dyn_debug(value: &'v dyn fmt::Debug) -> Self { Value { inner: inner::Inner::from_dyn_debug(value), } } /// Get a value from a dynamic `std::fmt::Display`. pub fn from_dyn_display(value: &'v dyn fmt::Display) -> Self { Value { inner: inner::Inner::from_dyn_display(value), } } /// Get a value from a dynamic error. #[cfg(feature = "kv_std")] pub fn from_dyn_error(err: &'v (dyn std::error::Error + 'static)) -> Self { Value { inner: inner::Inner::from_dyn_error(err), } } /// Get a `null` value. pub fn null() -> Self { Value { inner: inner::Inner::empty(), } } /// Get a value from an internal primitive. fn from_inner(value: T) -> Self where T: Into>, { Value { inner: value.into(), } } /// Inspect this value using a simple visitor. /// /// When the `kv_serde` or `kv_sval` features are enabled, you can also /// serialize a value using its `Serialize` or `Value` implementation. pub fn visit(&self, visitor: impl VisitValue<'v>) -> Result<(), Error> { inner::visit(&self.inner, visitor) } } impl<'v> fmt::Debug for Value<'v> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.inner, f) } } impl<'v> fmt::Display for Value<'v> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.inner, f) } } #[cfg(feature = "kv_serde")] impl<'v> serde::Serialize for Value<'v> { fn serialize(&self, s: S) -> Result where S: serde::Serializer, { self.inner.serialize(s) } } #[cfg(feature = "kv_sval")] impl<'v> sval::Value for Value<'v> { fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { sval::Value::stream(&self.inner, stream) } } #[cfg(feature = "kv_sval")] impl<'v> sval_ref::ValueRef<'v> for Value<'v> { fn stream_ref + ?Sized>(&self, stream: &mut S) -> sval::Result { sval_ref::ValueRef::stream_ref(&self.inner, stream) } } impl ToValue for str { fn to_value(&self) -> Value { Value::from(self) } } impl<'v> From<&'v str> for Value<'v> { fn from(value: &'v str) -> Self { Value::from_inner(value) } } impl ToValue for () { fn to_value(&self) -> Value { Value::from_inner(()) } } impl ToValue for Option where T: ToValue, { fn to_value(&self) -> Value { match *self { Some(ref value) => value.to_value(), None => Value::from_inner(()), } } } macro_rules! impl_to_value_primitive { ($($into_ty:ty,)*) => { $( impl ToValue for $into_ty { fn to_value(&self) -> Value { Value::from(*self) } } impl<'v> From<$into_ty> for Value<'v> { fn from(value: $into_ty) -> Self { Value::from_inner(value) } } impl<'v> From<&'v $into_ty> for Value<'v> { fn from(value: &'v $into_ty) -> Self { Value::from_inner(*value) } } )* }; } macro_rules! impl_to_value_nonzero_primitive { ($($into_ty:ident,)*) => { $( impl ToValue for std::num::$into_ty { fn to_value(&self) -> Value { Value::from(self.get()) } } impl<'v> From for Value<'v> { fn from(value: std::num::$into_ty) -> Self { Value::from(value.get()) } } impl<'v> From<&'v std::num::$into_ty> for Value<'v> { fn from(value: &'v std::num::$into_ty) -> Self { Value::from(value.get()) } } )* }; } macro_rules! impl_value_to_primitive { ($(#[doc = $doc:tt] $into_name:ident -> $into_ty:ty,)*) => { impl<'v> Value<'v> { $( #[doc = $doc] pub fn $into_name(&self) -> Option<$into_ty> { self.inner.$into_name() } )* } } } impl_to_value_primitive![ usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64, char, bool, ]; #[rustfmt::skip] impl_to_value_nonzero_primitive![ NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, ]; impl_value_to_primitive![ #[doc = "Try convert this value into a `u64`."] to_u64 -> u64, #[doc = "Try convert this value into a `i64`."] to_i64 -> i64, #[doc = "Try convert this value into a `u128`."] to_u128 -> u128, #[doc = "Try convert this value into a `i128`."] to_i128 -> i128, #[doc = "Try convert this value into a `f64`."] to_f64 -> f64, #[doc = "Try convert this value into a `char`."] to_char -> char, #[doc = "Try convert this value into a `bool`."] to_bool -> bool, ]; impl<'v> Value<'v> { /// Try to convert this value into an error. #[cfg(feature = "kv_std")] pub fn to_borrowed_error(&self) -> Option<&(dyn std::error::Error + 'static)> { self.inner.to_borrowed_error() } /// Try to convert this value into a borrowed string. pub fn to_borrowed_str(&self) -> Option<&'v str> { self.inner.to_borrowed_str() } } #[cfg(feature = "kv_std")] mod std_support { use std::borrow::Cow; use std::rc::Rc; use std::sync::Arc; use super::*; impl ToValue for Box where T: ToValue + ?Sized, { fn to_value(&self) -> Value { (**self).to_value() } } impl ToValue for Arc where T: ToValue + ?Sized, { fn to_value(&self) -> Value { (**self).to_value() } } impl ToValue for Rc where T: ToValue + ?Sized, { fn to_value(&self) -> Value { (**self).to_value() } } impl ToValue for String { fn to_value(&self) -> Value { Value::from(&**self) } } impl<'v> ToValue for Cow<'v, str> { fn to_value(&self) -> Value { Value::from(&**self) } } impl<'v> Value<'v> { /// Try convert this value into a string. pub fn to_cow_str(&self) -> Option> { self.inner.to_str() } } impl<'v> From<&'v String> for Value<'v> { fn from(v: &'v String) -> Self { Value::from(&**v) } } } /// A visitor for a [`Value`]. /// /// Also see [`Value`'s documentation on seralization]. Value visitors are a simple alternative /// to a more fully-featured serialization framework like `serde` or `sval`. A value visitor /// can differentiate primitive types through methods like [`VisitValue::visit_bool`] and /// [`VisitValue::visit_str`], but more complex types like maps and sequences /// will fallthrough to [`VisitValue::visit_any`]. /// /// If you're trying to serialize a value to a format like JSON, you can use either `serde` /// or `sval` directly with the value. You don't need a visitor. /// /// [`Value`'s documentation on seralization]: Value#serialization pub trait VisitValue<'v> { /// Visit a `Value`. /// /// This is the only required method on `VisitValue` and acts as a fallback for any /// more specific methods that aren't overridden. /// The `Value` may be formatted using its `fmt::Debug` or `fmt::Display` implementation, /// or serialized using its `sval::Value` or `serde::Serialize` implementation. fn visit_any(&mut self, value: Value) -> Result<(), Error>; /// Visit an empty value. fn visit_null(&mut self) -> Result<(), Error> { self.visit_any(Value::null()) } /// Visit an unsigned integer. fn visit_u64(&mut self, value: u64) -> Result<(), Error> { self.visit_any(value.into()) } /// Visit a signed integer. fn visit_i64(&mut self, value: i64) -> Result<(), Error> { self.visit_any(value.into()) } /// Visit a big unsigned integer. fn visit_u128(&mut self, value: u128) -> Result<(), Error> { self.visit_any((value).into()) } /// Visit a big signed integer. fn visit_i128(&mut self, value: i128) -> Result<(), Error> { self.visit_any((value).into()) } /// Visit a floating point. fn visit_f64(&mut self, value: f64) -> Result<(), Error> { self.visit_any(value.into()) } /// Visit a boolean. fn visit_bool(&mut self, value: bool) -> Result<(), Error> { self.visit_any(value.into()) } /// Visit a string. fn visit_str(&mut self, value: &str) -> Result<(), Error> { self.visit_any(value.into()) } /// Visit a string. fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { self.visit_str(value) } /// Visit a Unicode character. fn visit_char(&mut self, value: char) -> Result<(), Error> { let mut b = [0; 4]; self.visit_str(&*value.encode_utf8(&mut b)) } /// Visit an error. #[cfg(feature = "kv_std")] fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> { self.visit_any(Value::from_dyn_error(err)) } /// Visit an error. #[cfg(feature = "kv_std")] fn visit_borrowed_error( &mut self, err: &'v (dyn std::error::Error + 'static), ) -> Result<(), Error> { self.visit_any(Value::from_dyn_error(err)) } } impl<'a, 'v, T: ?Sized> VisitValue<'v> for &'a mut T where T: VisitValue<'v>, { fn visit_any(&mut self, value: Value) -> Result<(), Error> { (**self).visit_any(value) } fn visit_null(&mut self) -> Result<(), Error> { (**self).visit_null() } fn visit_u64(&mut self, value: u64) -> Result<(), Error> { (**self).visit_u64(value) } fn visit_i64(&mut self, value: i64) -> Result<(), Error> { (**self).visit_i64(value) } fn visit_u128(&mut self, value: u128) -> Result<(), Error> { (**self).visit_u128(value) } fn visit_i128(&mut self, value: i128) -> Result<(), Error> { (**self).visit_i128(value) } fn visit_f64(&mut self, value: f64) -> Result<(), Error> { (**self).visit_f64(value) } fn visit_bool(&mut self, value: bool) -> Result<(), Error> { (**self).visit_bool(value) } fn visit_str(&mut self, value: &str) -> Result<(), Error> { (**self).visit_str(value) } fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { (**self).visit_borrowed_str(value) } fn visit_char(&mut self, value: char) -> Result<(), Error> { (**self).visit_char(value) } #[cfg(feature = "kv_std")] fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> { (**self).visit_error(err) } #[cfg(feature = "kv_std")] fn visit_borrowed_error( &mut self, err: &'v (dyn std::error::Error + 'static), ) -> Result<(), Error> { (**self).visit_borrowed_error(err) } } #[cfg(feature = "value-bag")] pub(in crate::kv) mod inner { /** An implementation of `Value` based on a library called `value_bag`. `value_bag` was written specifically for use in `log`'s value, but was split out when it outgrew the codebase here. It's a general-purpose type-erasure library that handles mapping between more fully-featured serialization frameworks. */ use super::*; pub use value_bag::ValueBag as Inner; pub use value_bag::Error; #[cfg(test)] pub use value_bag::test::TestToken as Token; pub fn visit<'v>( inner: &Inner<'v>, visitor: impl VisitValue<'v>, ) -> Result<(), crate::kv::Error> { struct InnerVisitValue(V); impl<'v, V> value_bag::visit::Visit<'v> for InnerVisitValue where V: VisitValue<'v>, { fn visit_any(&mut self, value: value_bag::ValueBag) -> Result<(), Error> { self.0 .visit_any(Value { inner: value }) .map_err(crate::kv::Error::into_value) } fn visit_empty(&mut self) -> Result<(), Error> { self.0.visit_null().map_err(crate::kv::Error::into_value) } fn visit_u64(&mut self, value: u64) -> Result<(), Error> { self.0 .visit_u64(value) .map_err(crate::kv::Error::into_value) } fn visit_i64(&mut self, value: i64) -> Result<(), Error> { self.0 .visit_i64(value) .map_err(crate::kv::Error::into_value) } fn visit_u128(&mut self, value: u128) -> Result<(), Error> { self.0 .visit_u128(value) .map_err(crate::kv::Error::into_value) } fn visit_i128(&mut self, value: i128) -> Result<(), Error> { self.0 .visit_i128(value) .map_err(crate::kv::Error::into_value) } fn visit_f64(&mut self, value: f64) -> Result<(), Error> { self.0 .visit_f64(value) .map_err(crate::kv::Error::into_value) } fn visit_bool(&mut self, value: bool) -> Result<(), Error> { self.0 .visit_bool(value) .map_err(crate::kv::Error::into_value) } fn visit_str(&mut self, value: &str) -> Result<(), Error> { self.0 .visit_str(value) .map_err(crate::kv::Error::into_value) } fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { self.0 .visit_borrowed_str(value) .map_err(crate::kv::Error::into_value) } fn visit_char(&mut self, value: char) -> Result<(), Error> { self.0 .visit_char(value) .map_err(crate::kv::Error::into_value) } #[cfg(feature = "kv_std")] fn visit_error( &mut self, err: &(dyn std::error::Error + 'static), ) -> Result<(), Error> { self.0 .visit_error(err) .map_err(crate::kv::Error::into_value) } #[cfg(feature = "kv_std")] fn visit_borrowed_error( &mut self, err: &'v (dyn std::error::Error + 'static), ) -> Result<(), Error> { self.0 .visit_borrowed_error(err) .map_err(crate::kv::Error::into_value) } } inner .visit(&mut InnerVisitValue(visitor)) .map_err(crate::kv::Error::from_value) } } #[cfg(not(feature = "value-bag"))] pub(in crate::kv) mod inner { /** This is a dependency-free implementation of `Value` when there's no serialization frameworks involved. In these simple cases a more fully featured solution like `value_bag` isn't needed, so we avoid pulling it in. There are a few things here that need to remain consistent with the `value_bag`-based implementation: 1. Conversions should always produce the same results. If a conversion here returns `Some`, then the same `value_bag`-based conversion must also. Of particular note here are floats to ints; they're based on the standard library's `TryInto` conversions, which need to be converted to `i32` or `u32`, and then to `f64`. 2. VisitValues should always be called in the same way. If a particular type of value calls `visit_i64`, then the same `value_bag`-based visitor must also. */ use super::*; #[derive(Clone)] pub enum Inner<'v> { None, Bool(bool), Str(&'v str), Char(char), I64(i64), U64(u64), F64(f64), I128(i128), U128(u128), Debug(&'v dyn fmt::Debug), Display(&'v dyn fmt::Display), } impl<'v> From<()> for Inner<'v> { fn from(_: ()) -> Self { Inner::None } } impl<'v> From for Inner<'v> { fn from(v: bool) -> Self { Inner::Bool(v) } } impl<'v> From for Inner<'v> { fn from(v: char) -> Self { Inner::Char(v) } } impl<'v> From for Inner<'v> { fn from(v: f32) -> Self { Inner::F64(v as f64) } } impl<'v> From for Inner<'v> { fn from(v: f64) -> Self { Inner::F64(v) } } impl<'v> From for Inner<'v> { fn from(v: i8) -> Self { Inner::I64(v as i64) } } impl<'v> From for Inner<'v> { fn from(v: i16) -> Self { Inner::I64(v as i64) } } impl<'v> From for Inner<'v> { fn from(v: i32) -> Self { Inner::I64(v as i64) } } impl<'v> From for Inner<'v> { fn from(v: i64) -> Self { Inner::I64(v as i64) } } impl<'v> From for Inner<'v> { fn from(v: isize) -> Self { Inner::I64(v as i64) } } impl<'v> From for Inner<'v> { fn from(v: u8) -> Self { Inner::U64(v as u64) } } impl<'v> From for Inner<'v> { fn from(v: u16) -> Self { Inner::U64(v as u64) } } impl<'v> From for Inner<'v> { fn from(v: u32) -> Self { Inner::U64(v as u64) } } impl<'v> From for Inner<'v> { fn from(v: u64) -> Self { Inner::U64(v as u64) } } impl<'v> From for Inner<'v> { fn from(v: usize) -> Self { Inner::U64(v as u64) } } impl<'v> From for Inner<'v> { fn from(v: i128) -> Self { Inner::I128(v) } } impl<'v> From for Inner<'v> { fn from(v: u128) -> Self { Inner::U128(v) } } impl<'v> From<&'v str> for Inner<'v> { fn from(v: &'v str) -> Self { Inner::Str(v) } } impl<'v> fmt::Debug for Inner<'v> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Inner::None => fmt::Debug::fmt(&None::<()>, f), Inner::Bool(v) => fmt::Debug::fmt(v, f), Inner::Str(v) => fmt::Debug::fmt(v, f), Inner::Char(v) => fmt::Debug::fmt(v, f), Inner::I64(v) => fmt::Debug::fmt(v, f), Inner::U64(v) => fmt::Debug::fmt(v, f), Inner::F64(v) => fmt::Debug::fmt(v, f), Inner::I128(v) => fmt::Debug::fmt(v, f), Inner::U128(v) => fmt::Debug::fmt(v, f), Inner::Debug(v) => fmt::Debug::fmt(v, f), Inner::Display(v) => fmt::Display::fmt(v, f), } } } impl<'v> fmt::Display for Inner<'v> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Inner::None => fmt::Debug::fmt(&None::<()>, f), Inner::Bool(v) => fmt::Display::fmt(v, f), Inner::Str(v) => fmt::Display::fmt(v, f), Inner::Char(v) => fmt::Display::fmt(v, f), Inner::I64(v) => fmt::Display::fmt(v, f), Inner::U64(v) => fmt::Display::fmt(v, f), Inner::F64(v) => fmt::Display::fmt(v, f), Inner::I128(v) => fmt::Display::fmt(v, f), Inner::U128(v) => fmt::Display::fmt(v, f), Inner::Debug(v) => fmt::Debug::fmt(v, f), Inner::Display(v) => fmt::Display::fmt(v, f), } } } impl<'v> Inner<'v> { pub fn from_debug(value: &'v T) -> Self { Inner::Debug(value) } pub fn from_display(value: &'v T) -> Self { Inner::Display(value) } pub fn from_dyn_debug(value: &'v dyn fmt::Debug) -> Self { Inner::Debug(value) } pub fn from_dyn_display(value: &'v dyn fmt::Display) -> Self { Inner::Display(value) } pub fn empty() -> Self { Inner::None } pub fn to_bool(&self) -> Option { match self { Inner::Bool(v) => Some(*v), _ => None, } } pub fn to_char(&self) -> Option { match self { Inner::Char(v) => Some(*v), _ => None, } } pub fn to_f64(&self) -> Option { match self { Inner::F64(v) => Some(*v), Inner::I64(v) => { let v: i32 = (*v).try_into().ok()?; v.try_into().ok() } Inner::U64(v) => { let v: u32 = (*v).try_into().ok()?; v.try_into().ok() } Inner::I128(v) => { let v: i32 = (*v).try_into().ok()?; v.try_into().ok() } Inner::U128(v) => { let v: u32 = (*v).try_into().ok()?; v.try_into().ok() } _ => None, } } pub fn to_i64(&self) -> Option { match self { Inner::I64(v) => Some(*v), Inner::U64(v) => (*v).try_into().ok(), Inner::I128(v) => (*v).try_into().ok(), Inner::U128(v) => (*v).try_into().ok(), _ => None, } } pub fn to_u64(&self) -> Option { match self { Inner::U64(v) => Some(*v), Inner::I64(v) => (*v).try_into().ok(), Inner::I128(v) => (*v).try_into().ok(), Inner::U128(v) => (*v).try_into().ok(), _ => None, } } pub fn to_u128(&self) -> Option { match self { Inner::U128(v) => Some(*v), Inner::I64(v) => (*v).try_into().ok(), Inner::U64(v) => (*v).try_into().ok(), Inner::I128(v) => (*v).try_into().ok(), _ => None, } } pub fn to_i128(&self) -> Option { match self { Inner::I128(v) => Some(*v), Inner::I64(v) => (*v).try_into().ok(), Inner::U64(v) => (*v).try_into().ok(), Inner::U128(v) => (*v).try_into().ok(), _ => None, } } pub fn to_borrowed_str(&self) -> Option<&'v str> { match self { Inner::Str(v) => Some(v), _ => None, } } #[cfg(test)] pub fn to_test_token(&self) -> Token { match self { Inner::None => Token::None, Inner::Bool(v) => Token::Bool(*v), Inner::Str(v) => Token::Str(*v), Inner::Char(v) => Token::Char(*v), Inner::I64(v) => Token::I64(*v), Inner::U64(v) => Token::U64(*v), Inner::F64(v) => Token::F64(*v), Inner::I128(_) => unimplemented!(), Inner::U128(_) => unimplemented!(), Inner::Debug(_) => unimplemented!(), Inner::Display(_) => unimplemented!(), } } } #[cfg(test)] #[derive(Debug, PartialEq)] pub enum Token<'v> { None, Bool(bool), Char(char), Str(&'v str), F64(f64), I64(i64), U64(u64), } pub fn visit<'v>( inner: &Inner<'v>, mut visitor: impl VisitValue<'v>, ) -> Result<(), crate::kv::Error> { match inner { Inner::None => visitor.visit_null(), Inner::Bool(v) => visitor.visit_bool(*v), Inner::Str(v) => visitor.visit_borrowed_str(*v), Inner::Char(v) => visitor.visit_char(*v), Inner::I64(v) => visitor.visit_i64(*v), Inner::U64(v) => visitor.visit_u64(*v), Inner::F64(v) => visitor.visit_f64(*v), Inner::I128(v) => visitor.visit_i128(*v), Inner::U128(v) => visitor.visit_u128(*v), Inner::Debug(v) => visitor.visit_any(Value::from_dyn_debug(*v)), Inner::Display(v) => visitor.visit_any(Value::from_dyn_display(*v)), } } } impl<'v> Value<'v> { /// Get a value from a type implementing `std::fmt::Debug`. #[cfg(feature = "kv_unstable")] #[deprecated(note = "use `from_debug` instead")] pub fn capture_debug(value: &'v T) -> Self where T: fmt::Debug + 'static, { Value::from_debug(value) } /// Get a value from a type implementing `std::fmt::Display`. #[cfg(feature = "kv_unstable")] #[deprecated(note = "use `from_display` instead")] pub fn capture_display(value: &'v T) -> Self where T: fmt::Display + 'static, { Value::from_display(value) } /// Get a value from an error. #[cfg(feature = "kv_unstable_std")] #[deprecated(note = "use `from_dyn_error` instead")] pub fn capture_error(err: &'v T) -> Self where T: std::error::Error + 'static, { Value::from_dyn_error(err) } /// Get a value from a type implementing `serde::Serialize`. #[cfg(feature = "kv_unstable_serde")] #[deprecated(note = "use `from_serde` instead")] pub fn capture_serde(value: &'v T) -> Self where T: serde::Serialize + 'static, { Value::from_serde(value) } /// Get a value from a type implementing `sval::Value`. #[cfg(feature = "kv_unstable_sval")] #[deprecated(note = "use `from_sval` instead")] pub fn capture_sval(value: &'v T) -> Self where T: sval::Value + 'static, { Value::from_sval(value) } /// Check whether this value can be downcast to `T`. #[cfg(feature = "kv_unstable")] #[deprecated( note = "downcasting has been removed; log an issue at https://github.com/rust-lang/log/issues if this is something you rely on" )] pub fn is(&self) -> bool { false } /// Try downcast this value to `T`. #[cfg(feature = "kv_unstable")] #[deprecated( note = "downcasting has been removed; log an issue at https://github.com/rust-lang/log/issues if this is something you rely on" )] pub fn downcast_ref(&self) -> Option<&T> { None } } // NOTE: Deprecated; but aliases can't carry this attribute #[cfg(feature = "kv_unstable")] pub use VisitValue as Visit; /// Get a value from a type implementing `std::fmt::Debug`. #[cfg(feature = "kv_unstable")] #[deprecated(note = "use the `key:? = value` macro syntax instead")] #[macro_export] macro_rules! as_debug { ($capture:expr) => { $crate::kv::Value::from_debug(&$capture) }; } /// Get a value from a type implementing `std::fmt::Display`. #[cfg(feature = "kv_unstable")] #[deprecated(note = "use the `key:% = value` macro syntax instead")] #[macro_export] macro_rules! as_display { ($capture:expr) => { $crate::kv::Value::from_display(&$capture) }; } /// Get a value from an error. #[cfg(feature = "kv_unstable_std")] #[deprecated(note = "use the `key:err = value` macro syntax instead")] #[macro_export] macro_rules! as_error { ($capture:expr) => { $crate::kv::Value::from_dyn_error(&$capture) }; } #[cfg(feature = "kv_unstable_serde")] #[deprecated(note = "use the `key:serde = value` macro syntax instead")] /// Get a value from a type implementing `serde::Serialize`. #[macro_export] macro_rules! as_serde { ($capture:expr) => { $crate::kv::Value::from_serde(&$capture) }; } /// Get a value from a type implementing `sval::Value`. #[cfg(feature = "kv_unstable_sval")] #[deprecated(note = "use the `key:sval = value` macro syntax instead")] #[macro_export] macro_rules! as_sval { ($capture:expr) => { $crate::kv::Value::from_sval(&$capture) }; } #[cfg(test)] pub(crate) mod tests { use super::*; impl<'v> Value<'v> { pub(crate) fn to_token(&self) -> inner::Token { self.inner.to_test_token() } } fn unsigned() -> impl Iterator> { vec![ Value::from(8u8), Value::from(16u16), Value::from(32u32), Value::from(64u64), Value::from(1usize), Value::from(std::num::NonZeroU8::new(8).unwrap()), Value::from(std::num::NonZeroU16::new(16).unwrap()), Value::from(std::num::NonZeroU32::new(32).unwrap()), Value::from(std::num::NonZeroU64::new(64).unwrap()), Value::from(std::num::NonZeroUsize::new(1).unwrap()), ] .into_iter() } fn signed() -> impl Iterator> { vec![ Value::from(-8i8), Value::from(-16i16), Value::from(-32i32), Value::from(-64i64), Value::from(-1isize), Value::from(std::num::NonZeroI8::new(-8).unwrap()), Value::from(std::num::NonZeroI16::new(-16).unwrap()), Value::from(std::num::NonZeroI32::new(-32).unwrap()), Value::from(std::num::NonZeroI64::new(-64).unwrap()), Value::from(std::num::NonZeroIsize::new(-1).unwrap()), ] .into_iter() } fn float() -> impl Iterator> { vec![Value::from(32.32f32), Value::from(64.64f64)].into_iter() } fn bool() -> impl Iterator> { vec![Value::from(true), Value::from(false)].into_iter() } fn str() -> impl Iterator> { vec![Value::from("a string"), Value::from("a loong string")].into_iter() } fn char() -> impl Iterator> { vec![Value::from('a'), Value::from('â›°')].into_iter() } #[test] fn test_to_value_display() { assert_eq!(42u64.to_value().to_string(), "42"); assert_eq!(42i64.to_value().to_string(), "42"); assert_eq!(42.01f64.to_value().to_string(), "42.01"); assert_eq!(true.to_value().to_string(), "true"); assert_eq!('a'.to_value().to_string(), "a"); assert_eq!("a loong string".to_value().to_string(), "a loong string"); assert_eq!(Some(true).to_value().to_string(), "true"); assert_eq!(().to_value().to_string(), "None"); assert_eq!(None::.to_value().to_string(), "None"); } #[test] fn test_to_value_structured() { assert_eq!(42u64.to_value().to_token(), inner::Token::U64(42)); assert_eq!(42i64.to_value().to_token(), inner::Token::I64(42)); assert_eq!(42.01f64.to_value().to_token(), inner::Token::F64(42.01)); assert_eq!(true.to_value().to_token(), inner::Token::Bool(true)); assert_eq!('a'.to_value().to_token(), inner::Token::Char('a')); assert_eq!( "a loong string".to_value().to_token(), inner::Token::Str("a loong string".into()) ); assert_eq!(Some(true).to_value().to_token(), inner::Token::Bool(true)); assert_eq!(().to_value().to_token(), inner::Token::None); assert_eq!(None::.to_value().to_token(), inner::Token::None); } #[test] fn test_to_number() { for v in unsigned() { assert!(v.to_u64().is_some()); assert!(v.to_i64().is_some()); } for v in signed() { assert!(v.to_i64().is_some()); } for v in unsigned().chain(signed()).chain(float()) { assert!(v.to_f64().is_some()); } for v in bool().chain(str()).chain(char()) { assert!(v.to_u64().is_none()); assert!(v.to_i64().is_none()); assert!(v.to_f64().is_none()); } } #[test] fn test_to_float() { // Only integers from i32::MIN..=u32::MAX can be converted into floats assert!(Value::from(i32::MIN).to_f64().is_some()); assert!(Value::from(u32::MAX).to_f64().is_some()); assert!(Value::from((i32::MIN as i64) - 1).to_f64().is_none()); assert!(Value::from((u32::MAX as u64) + 1).to_f64().is_none()); } #[test] fn test_to_cow_str() { for v in str() { assert!(v.to_borrowed_str().is_some()); #[cfg(feature = "kv_std")] assert!(v.to_cow_str().is_some()); } let short_lived = String::from("short lived"); let v = Value::from(&*short_lived); assert!(v.to_borrowed_str().is_some()); #[cfg(feature = "kv_std")] assert!(v.to_cow_str().is_some()); for v in unsigned().chain(signed()).chain(float()).chain(bool()) { assert!(v.to_borrowed_str().is_none()); #[cfg(feature = "kv_std")] assert!(v.to_cow_str().is_none()); } } #[test] fn test_to_bool() { for v in bool() { assert!(v.to_bool().is_some()); } for v in unsigned() .chain(signed()) .chain(float()) .chain(str()) .chain(char()) { assert!(v.to_bool().is_none()); } } #[test] fn test_to_char() { for v in char() { assert!(v.to_char().is_some()); } for v in unsigned() .chain(signed()) .chain(float()) .chain(str()) .chain(bool()) { assert!(v.to_char().is_none()); } } #[test] fn test_visit_integer() { struct Extract(Option); impl<'v> VisitValue<'v> for Extract { fn visit_any(&mut self, value: Value) -> Result<(), Error> { unimplemented!("unexpected value: {value:?}") } fn visit_u64(&mut self, value: u64) -> Result<(), Error> { self.0 = Some(value); Ok(()) } } let mut extract = Extract(None); Value::from(42u64).visit(&mut extract).unwrap(); assert_eq!(Some(42), extract.0); } #[test] fn test_visit_borrowed_str() { struct Extract<'v>(Option<&'v str>); impl<'v> VisitValue<'v> for Extract<'v> { fn visit_any(&mut self, value: Value) -> Result<(), Error> { unimplemented!("unexpected value: {value:?}") } fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { self.0 = Some(value); Ok(()) } } let mut extract = Extract(None); let short_lived = String::from("A short-lived string"); Value::from(&*short_lived).visit(&mut extract).unwrap(); assert_eq!(Some("A short-lived string"), extract.0); } } log-0.4.26/src/lib.rs000064400000000000000000001670651046102023000124200ustar 00000000000000// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! A lightweight logging facade. //! //! The `log` crate provides a single logging API that abstracts over the //! actual logging implementation. Libraries can use the logging API provided //! by this crate, and the consumer of those libraries can choose the logging //! implementation that is most suitable for its use case. //! //! If no logging implementation is selected, the facade falls back to a "noop" //! implementation that ignores all log messages. The overhead in this case //! is very small - just an integer load, comparison and jump. //! //! A log request consists of a _target_, a _level_, and a _body_. A target is a //! string which defaults to the module path of the location of the log request, //! though that default may be overridden. Logger implementations typically use //! the target to filter requests based on some user configuration. //! //! # Usage //! //! The basic use of the log crate is through the five logging macros: [`error!`], //! [`warn!`], [`info!`], [`debug!`] and [`trace!`] //! where `error!` represents the highest-priority log messages //! and `trace!` the lowest. The log messages are filtered by configuring //! the log level to exclude messages with a lower priority. //! Each of these macros accept format strings similarly to [`println!`]. //! //! //! [`error!`]: ./macro.error.html //! [`warn!`]: ./macro.warn.html //! [`info!`]: ./macro.info.html //! [`debug!`]: ./macro.debug.html //! [`trace!`]: ./macro.trace.html //! [`println!`]: https://doc.rust-lang.org/stable/std/macro.println.html //! //! Avoid writing expressions with side-effects in log statements. They may not be evaluated. //! //! ## In libraries //! //! Libraries should link only to the `log` crate, and use the provided //! macros to log whatever information will be useful to downstream consumers. //! //! ### Examples //! //! ``` //! # #[derive(Debug)] pub struct Yak(String); //! # impl Yak { fn shave(&mut self, _: u32) {} } //! # fn find_a_razor() -> Result { Ok(1) } //! use log::{info, warn}; //! //! pub fn shave_the_yak(yak: &mut Yak) { //! info!(target: "yak_events", "Commencing yak shaving for {yak:?}"); //! //! loop { //! match find_a_razor() { //! Ok(razor) => { //! info!("Razor located: {razor}"); //! yak.shave(razor); //! break; //! } //! Err(err) => { //! warn!("Unable to locate a razor: {err}, retrying"); //! } //! } //! } //! } //! # fn main() {} //! ``` //! //! ## In executables //! //! Executables should choose a logging implementation and initialize it early in the //! runtime of the program. Logging implementations will typically include a //! function to do this. Any log messages generated before //! the implementation is initialized will be ignored. //! //! The executable itself may use the `log` crate to log as well. //! //! ### Warning //! //! The logging system may only be initialized once. //! //! ## Structured logging //! //! If you enable the `kv` feature you can associate structured values //! with your log records. If we take the example from before, we can include //! some additional context besides what's in the formatted message: //! //! ``` //! # use serde::Serialize; //! # #[derive(Debug, Serialize)] pub struct Yak(String); //! # impl Yak { fn shave(&mut self, _: u32) {} } //! # fn find_a_razor() -> Result { Ok(1) } //! # #[cfg(feature = "kv_serde")] //! # fn main() { //! use log::{info, warn}; //! //! pub fn shave_the_yak(yak: &mut Yak) { //! info!(target: "yak_events", yak:serde; "Commencing yak shaving"); //! //! loop { //! match find_a_razor() { //! Ok(razor) => { //! info!(razor; "Razor located"); //! yak.shave(razor); //! break; //! } //! Err(e) => { //! warn!(e:err; "Unable to locate a razor, retrying"); //! } //! } //! } //! } //! # } //! # #[cfg(not(feature = "kv_serde"))] //! # fn main() {} //! ``` //! //! See the [`kv`] module documentation for more details. //! //! # Available logging implementations //! //! In order to produce log output executables have to use //! a logger implementation compatible with the facade. //! There are many available implementations to choose from, //! here are some of the most popular ones: //! //! * Simple minimal loggers: //! * [env_logger] //! * [colog] //! * [simple_logger] //! * [simplelog] //! * [pretty_env_logger] //! * [stderrlog] //! * [flexi_logger] //! * [call_logger] //! * [structured-logger] //! * [clang_log] //! * [ftail] //! * Complex configurable frameworks: //! * [log4rs] //! * [logforth] //! * [fern] //! * [spdlog-rs] //! * Adaptors for other facilities: //! * [syslog] //! * [slog-stdlog] //! * [systemd-journal-logger] //! * [android_log] //! * [win_dbg_logger] //! * [db_logger] //! * [log-to-defmt] //! * [logcontrol-log] //! * For WebAssembly binaries: //! * [console_log] //! * For dynamic libraries: //! * You may need to construct an FFI-safe wrapper over `log` to initialize in your libraries //! * Utilities: //! * [log_err] //! * [log-reload] //! //! # Implementing a Logger //! //! Loggers implement the [`Log`] trait. Here's a very basic example that simply //! logs all messages at the [`Error`][level_link], [`Warn`][level_link] or //! [`Info`][level_link] levels to stdout: //! //! ``` //! use log::{Record, Level, Metadata}; //! //! struct SimpleLogger; //! //! impl log::Log for SimpleLogger { //! fn enabled(&self, metadata: &Metadata) -> bool { //! metadata.level() <= Level::Info //! } //! //! fn log(&self, record: &Record) { //! if self.enabled(record.metadata()) { //! println!("{} - {}", record.level(), record.args()); //! } //! } //! //! fn flush(&self) {} //! } //! //! # fn main() {} //! ``` //! //! Loggers are installed by calling the [`set_logger`] function. The maximum //! log level also needs to be adjusted via the [`set_max_level`] function. The //! logging facade uses this as an optimization to improve performance of log //! messages at levels that are disabled. It's important to set it, as it //! defaults to [`Off`][filter_link], so no log messages will ever be captured! //! In the case of our example logger, we'll want to set the maximum log level //! to [`Info`][filter_link], since we ignore any [`Debug`][level_link] or //! [`Trace`][level_link] level log messages. A logging implementation should //! provide a function that wraps a call to [`set_logger`] and //! [`set_max_level`], handling initialization of the logger: //! //! ``` //! # use log::{Level, Metadata}; //! # struct SimpleLogger; //! # impl log::Log for SimpleLogger { //! # fn enabled(&self, _: &Metadata) -> bool { false } //! # fn log(&self, _: &log::Record) {} //! # fn flush(&self) {} //! # } //! # fn main() {} //! use log::{SetLoggerError, LevelFilter}; //! //! static LOGGER: SimpleLogger = SimpleLogger; //! //! pub fn init() -> Result<(), SetLoggerError> { //! log::set_logger(&LOGGER) //! .map(|()| log::set_max_level(LevelFilter::Info)) //! } //! ``` //! //! Implementations that adjust their configurations at runtime should take care //! to adjust the maximum log level as well. //! //! # Use with `std` //! //! `set_logger` requires you to provide a `&'static Log`, which can be hard to //! obtain if your logger depends on some runtime configuration. The //! `set_boxed_logger` function is available with the `std` Cargo feature. It is //! identical to `set_logger` except that it takes a `Box` rather than a //! `&'static Log`: //! //! ``` //! # use log::{Level, LevelFilter, Log, SetLoggerError, Metadata}; //! # struct SimpleLogger; //! # impl log::Log for SimpleLogger { //! # fn enabled(&self, _: &Metadata) -> bool { false } //! # fn log(&self, _: &log::Record) {} //! # fn flush(&self) {} //! # } //! # fn main() {} //! # #[cfg(feature = "std")] //! pub fn init() -> Result<(), SetLoggerError> { //! log::set_boxed_logger(Box::new(SimpleLogger)) //! .map(|()| log::set_max_level(LevelFilter::Info)) //! } //! ``` //! //! # Compile time filters //! //! Log levels can be statically disabled at compile time by enabling one of these Cargo features: //! //! * `max_level_off` //! * `max_level_error` //! * `max_level_warn` //! * `max_level_info` //! * `max_level_debug` //! * `max_level_trace` //! //! Log invocations at disabled levels will be skipped and will not even be present in the //! resulting binary. These features control the value of the `STATIC_MAX_LEVEL` constant. The //! logging macros check this value before logging a message. By default, no levels are disabled. //! //! It is possible to override this level for release builds only with the following features: //! //! * `release_max_level_off` //! * `release_max_level_error` //! * `release_max_level_warn` //! * `release_max_level_info` //! * `release_max_level_debug` //! * `release_max_level_trace` //! //! Libraries should avoid using the max level features because they're global and can't be changed //! once they're set. //! //! For example, a crate can disable trace level logs in debug builds and trace, debug, and info //! level logs in release builds with the following configuration: //! //! ```toml //! [dependencies] //! log = { version = "0.4", features = ["max_level_debug", "release_max_level_warn"] } //! ``` //! # Crate Feature Flags //! //! The following crate feature flags are available in addition to the filters. They are //! configured in your `Cargo.toml`. //! //! * `std` allows use of `std` crate instead of the default `core`. Enables using `std::error` and //! `set_boxed_logger` functionality. //! * `serde` enables support for serialization and deserialization of `Level` and `LevelFilter`. //! //! ```toml //! [dependencies] //! log = { version = "0.4", features = ["std", "serde"] } //! ``` //! //! # Version compatibility //! //! The 0.3 and 0.4 versions of the `log` crate are almost entirely compatible. Log messages //! made using `log` 0.3 will forward transparently to a logger implementation using `log` 0.4. Log //! messages made using `log` 0.4 will forward to a logger implementation using `log` 0.3, but the //! module path and file name information associated with the message will unfortunately be lost. //! //! [`Log`]: trait.Log.html //! [level_link]: enum.Level.html //! [filter_link]: enum.LevelFilter.html //! [`set_logger`]: fn.set_logger.html //! [`set_max_level`]: fn.set_max_level.html //! [`try_set_logger_raw`]: fn.try_set_logger_raw.html //! [`shutdown_logger_raw`]: fn.shutdown_logger_raw.html //! [env_logger]: https://docs.rs/env_logger/*/env_logger/ //! [colog]: https://docs.rs/colog/*/colog/ //! [simple_logger]: https://github.com/borntyping/rust-simple_logger //! [simplelog]: https://github.com/drakulix/simplelog.rs //! [pretty_env_logger]: https://docs.rs/pretty_env_logger/*/pretty_env_logger/ //! [stderrlog]: https://docs.rs/stderrlog/*/stderrlog/ //! [flexi_logger]: https://docs.rs/flexi_logger/*/flexi_logger/ //! [call_logger]: https://docs.rs/call_logger/*/call_logger/ //! [syslog]: https://docs.rs/syslog/*/syslog/ //! [slog-stdlog]: https://docs.rs/slog-stdlog/*/slog_stdlog/ //! [log4rs]: https://docs.rs/log4rs/*/log4rs/ //! [logforth]: https://docs.rs/logforth/*/logforth/ //! [fern]: https://docs.rs/fern/*/fern/ //! [spdlog-rs]: https://docs.rs/spdlog-rs/*/spdlog/ //! [systemd-journal-logger]: https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/ //! [android_log]: https://docs.rs/android_log/*/android_log/ //! [win_dbg_logger]: https://docs.rs/win_dbg_logger/*/win_dbg_logger/ //! [db_logger]: https://docs.rs/db_logger/*/db_logger/ //! [log-to-defmt]: https://docs.rs/log-to-defmt/*/log_to_defmt/ //! [console_log]: https://docs.rs/console_log/*/console_log/ //! [structured-logger]: https://docs.rs/structured-logger/latest/structured_logger/ //! [logcontrol-log]: https://docs.rs/logcontrol-log/*/logcontrol_log/ //! [log_err]: https://docs.rs/log_err/*/log_err/ //! [log-reload]: https://docs.rs/log-reload/*/log_reload/ //! [clang_log]: https://docs.rs/clang_log/latest/clang_log //! [ftail]: https://docs.rs/ftail/latest/ftail #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://docs.rs/log/0.4.26" )] #![warn(missing_docs)] #![deny(missing_debug_implementations, unconditional_recursion)] #![cfg_attr(all(not(feature = "std"), not(test)), no_std)] #[cfg(any( all(feature = "max_level_off", feature = "max_level_error"), all(feature = "max_level_off", feature = "max_level_warn"), all(feature = "max_level_off", feature = "max_level_info"), all(feature = "max_level_off", feature = "max_level_debug"), all(feature = "max_level_off", feature = "max_level_trace"), all(feature = "max_level_error", feature = "max_level_warn"), all(feature = "max_level_error", feature = "max_level_info"), all(feature = "max_level_error", feature = "max_level_debug"), all(feature = "max_level_error", feature = "max_level_trace"), all(feature = "max_level_warn", feature = "max_level_info"), all(feature = "max_level_warn", feature = "max_level_debug"), all(feature = "max_level_warn", feature = "max_level_trace"), all(feature = "max_level_info", feature = "max_level_debug"), all(feature = "max_level_info", feature = "max_level_trace"), all(feature = "max_level_debug", feature = "max_level_trace"), ))] compile_error!("multiple max_level_* features set"); #[rustfmt::skip] #[cfg(any( all(feature = "release_max_level_off", feature = "release_max_level_error"), all(feature = "release_max_level_off", feature = "release_max_level_warn"), all(feature = "release_max_level_off", feature = "release_max_level_info"), all(feature = "release_max_level_off", feature = "release_max_level_debug"), all(feature = "release_max_level_off", feature = "release_max_level_trace"), all(feature = "release_max_level_error", feature = "release_max_level_warn"), all(feature = "release_max_level_error", feature = "release_max_level_info"), all(feature = "release_max_level_error", feature = "release_max_level_debug"), all(feature = "release_max_level_error", feature = "release_max_level_trace"), all(feature = "release_max_level_warn", feature = "release_max_level_info"), all(feature = "release_max_level_warn", feature = "release_max_level_debug"), all(feature = "release_max_level_warn", feature = "release_max_level_trace"), all(feature = "release_max_level_info", feature = "release_max_level_debug"), all(feature = "release_max_level_info", feature = "release_max_level_trace"), all(feature = "release_max_level_debug", feature = "release_max_level_trace"), ))] compile_error!("multiple release_max_level_* features set"); #[cfg(all(not(feature = "std"), not(test)))] extern crate core as std; use std::cfg; #[cfg(feature = "std")] use std::error; use std::str::FromStr; use std::{cmp, fmt, mem}; #[macro_use] mod macros; mod serde; #[cfg(feature = "kv")] pub mod kv; #[cfg(target_has_atomic = "ptr")] use std::sync::atomic::{AtomicUsize, Ordering}; #[cfg(not(target_has_atomic = "ptr"))] use std::cell::Cell; #[cfg(not(target_has_atomic = "ptr"))] use std::sync::atomic::Ordering; #[cfg(not(target_has_atomic = "ptr"))] struct AtomicUsize { v: Cell, } #[cfg(not(target_has_atomic = "ptr"))] impl AtomicUsize { const fn new(v: usize) -> AtomicUsize { AtomicUsize { v: Cell::new(v) } } fn load(&self, _order: Ordering) -> usize { self.v.get() } fn store(&self, val: usize, _order: Ordering) { self.v.set(val) } #[cfg(target_has_atomic = "ptr")] fn compare_exchange( &self, current: usize, new: usize, _success: Ordering, _failure: Ordering, ) -> Result { let prev = self.v.get(); if current == prev { self.v.set(new); } Ok(prev) } } // Any platform without atomics is unlikely to have multiple cores, so // writing via Cell will not be a race condition. #[cfg(not(target_has_atomic = "ptr"))] unsafe impl Sync for AtomicUsize {} // The LOGGER static holds a pointer to the global logger. It is protected by // the STATE static which determines whether LOGGER has been initialized yet. static mut LOGGER: &dyn Log = &NopLogger; static STATE: AtomicUsize = AtomicUsize::new(0); // There are three different states that we care about: the logger's // uninitialized, the logger's initializing (set_logger's been called but // LOGGER hasn't actually been set yet), or the logger's active. const UNINITIALIZED: usize = 0; const INITIALIZING: usize = 1; const INITIALIZED: usize = 2; static MAX_LOG_LEVEL_FILTER: AtomicUsize = AtomicUsize::new(0); static LOG_LEVEL_NAMES: [&str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; static SET_LOGGER_ERROR: &str = "attempted to set a logger after the logging system \ was already initialized"; static LEVEL_PARSE_ERROR: &str = "attempted to convert a string that doesn't match an existing log level"; /// An enum representing the available verbosity levels of the logger. /// /// Typical usage includes: checking if a certain `Level` is enabled with /// [`log_enabled!`](macro.log_enabled.html), specifying the `Level` of /// [`log!`](macro.log.html), and comparing a `Level` directly to a /// [`LevelFilter`](enum.LevelFilter.html). #[repr(usize)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub enum Level { /// The "error" level. /// /// Designates very serious errors. // This way these line up with the discriminants for LevelFilter below // This works because Rust treats field-less enums the same way as C does: // https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations Error = 1, /// The "warn" level. /// /// Designates hazardous situations. Warn, /// The "info" level. /// /// Designates useful information. Info, /// The "debug" level. /// /// Designates lower priority information. Debug, /// The "trace" level. /// /// Designates very low priority, often extremely verbose, information. Trace, } impl PartialEq for Level { #[inline] fn eq(&self, other: &LevelFilter) -> bool { *self as usize == *other as usize } } impl PartialOrd for Level { #[inline] fn partial_cmp(&self, other: &LevelFilter) -> Option { Some((*self as usize).cmp(&(*other as usize))) } } impl FromStr for Level { type Err = ParseLevelError; fn from_str(level: &str) -> Result { LOG_LEVEL_NAMES .iter() .position(|&name| name.eq_ignore_ascii_case(level)) .into_iter() .filter(|&idx| idx != 0) .map(|idx| Level::from_usize(idx).unwrap()) .next() .ok_or(ParseLevelError(())) } } impl fmt::Display for Level { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.pad(self.as_str()) } } impl Level { fn from_usize(u: usize) -> Option { match u { 1 => Some(Level::Error), 2 => Some(Level::Warn), 3 => Some(Level::Info), 4 => Some(Level::Debug), 5 => Some(Level::Trace), _ => None, } } /// Returns the most verbose logging level. #[inline] pub fn max() -> Level { Level::Trace } /// Converts the `Level` to the equivalent `LevelFilter`. #[inline] pub fn to_level_filter(&self) -> LevelFilter { LevelFilter::from_usize(*self as usize).unwrap() } /// Returns the string representation of the `Level`. /// /// This returns the same string as the `fmt::Display` implementation. pub fn as_str(&self) -> &'static str { LOG_LEVEL_NAMES[*self as usize] } /// Iterate through all supported logging levels. /// /// The order of iteration is from more severe to less severe log messages. /// /// # Examples /// /// ``` /// use log::Level; /// /// let mut levels = Level::iter(); /// /// assert_eq!(Some(Level::Error), levels.next()); /// assert_eq!(Some(Level::Trace), levels.last()); /// ``` pub fn iter() -> impl Iterator { (1..6).map(|i| Self::from_usize(i).unwrap()) } } /// An enum representing the available verbosity level filters of the logger. /// /// A `LevelFilter` may be compared directly to a [`Level`]. Use this type /// to get and set the maximum log level with [`max_level()`] and [`set_max_level`]. /// /// [`Level`]: enum.Level.html /// [`max_level()`]: fn.max_level.html /// [`set_max_level`]: fn.set_max_level.html #[repr(usize)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub enum LevelFilter { /// A level lower than all log levels. Off, /// Corresponds to the `Error` log level. Error, /// Corresponds to the `Warn` log level. Warn, /// Corresponds to the `Info` log level. Info, /// Corresponds to the `Debug` log level. Debug, /// Corresponds to the `Trace` log level. Trace, } impl PartialEq for LevelFilter { #[inline] fn eq(&self, other: &Level) -> bool { other.eq(self) } } impl PartialOrd for LevelFilter { #[inline] fn partial_cmp(&self, other: &Level) -> Option { Some((*self as usize).cmp(&(*other as usize))) } } impl FromStr for LevelFilter { type Err = ParseLevelError; fn from_str(level: &str) -> Result { LOG_LEVEL_NAMES .iter() .position(|&name| name.eq_ignore_ascii_case(level)) .map(|p| LevelFilter::from_usize(p).unwrap()) .ok_or(ParseLevelError(())) } } impl fmt::Display for LevelFilter { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.pad(self.as_str()) } } impl LevelFilter { fn from_usize(u: usize) -> Option { match u { 0 => Some(LevelFilter::Off), 1 => Some(LevelFilter::Error), 2 => Some(LevelFilter::Warn), 3 => Some(LevelFilter::Info), 4 => Some(LevelFilter::Debug), 5 => Some(LevelFilter::Trace), _ => None, } } /// Returns the most verbose logging level filter. #[inline] pub fn max() -> LevelFilter { LevelFilter::Trace } /// Converts `self` to the equivalent `Level`. /// /// Returns `None` if `self` is `LevelFilter::Off`. #[inline] pub fn to_level(&self) -> Option { Level::from_usize(*self as usize) } /// Returns the string representation of the `LevelFilter`. /// /// This returns the same string as the `fmt::Display` implementation. pub fn as_str(&self) -> &'static str { LOG_LEVEL_NAMES[*self as usize] } /// Iterate through all supported filtering levels. /// /// The order of iteration is from less to more verbose filtering. /// /// # Examples /// /// ``` /// use log::LevelFilter; /// /// let mut levels = LevelFilter::iter(); /// /// assert_eq!(Some(LevelFilter::Off), levels.next()); /// assert_eq!(Some(LevelFilter::Trace), levels.last()); /// ``` pub fn iter() -> impl Iterator { (0..6).map(|i| Self::from_usize(i).unwrap()) } } #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] enum MaybeStaticStr<'a> { Static(&'static str), Borrowed(&'a str), } impl<'a> MaybeStaticStr<'a> { #[inline] fn get(&self) -> &'a str { match *self { MaybeStaticStr::Static(s) => s, MaybeStaticStr::Borrowed(s) => s, } } } /// The "payload" of a log message. /// /// # Use /// /// `Record` structures are passed as parameters to the [`log`][method.log] /// method of the [`Log`] trait. Logger implementors manipulate these /// structures in order to display log messages. `Record`s are automatically /// created by the [`log!`] macro and so are not seen by log users. /// /// Note that the [`level()`] and [`target()`] accessors are equivalent to /// `self.metadata().level()` and `self.metadata().target()` respectively. /// These methods are provided as a convenience for users of this structure. /// /// # Example /// /// The following example shows a simple logger that displays the level, /// module path, and message of any `Record` that is passed to it. /// /// ``` /// struct SimpleLogger; /// /// impl log::Log for SimpleLogger { /// fn enabled(&self, _metadata: &log::Metadata) -> bool { /// true /// } /// /// fn log(&self, record: &log::Record) { /// if !self.enabled(record.metadata()) { /// return; /// } /// /// println!("{}:{} -- {}", /// record.level(), /// record.target(), /// record.args()); /// } /// fn flush(&self) {} /// } /// ``` /// /// [method.log]: trait.Log.html#tymethod.log /// [`Log`]: trait.Log.html /// [`log!`]: macro.log.html /// [`level()`]: struct.Record.html#method.level /// [`target()`]: struct.Record.html#method.target #[derive(Clone, Debug)] pub struct Record<'a> { metadata: Metadata<'a>, args: fmt::Arguments<'a>, module_path: Option>, file: Option>, line: Option, #[cfg(feature = "kv")] key_values: KeyValues<'a>, } // This wrapper type is only needed so we can // `#[derive(Debug)]` on `Record`. It also // provides a useful `Debug` implementation for // the underlying `Source`. #[cfg(feature = "kv")] #[derive(Clone)] struct KeyValues<'a>(&'a dyn kv::Source); #[cfg(feature = "kv")] impl<'a> fmt::Debug for KeyValues<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut visitor = f.debug_map(); self.0.visit(&mut visitor).map_err(|_| fmt::Error)?; visitor.finish() } } impl<'a> Record<'a> { /// Returns a new builder. #[inline] pub fn builder() -> RecordBuilder<'a> { RecordBuilder::new() } /// The message body. #[inline] pub fn args(&self) -> &fmt::Arguments<'a> { &self.args } /// Metadata about the log directive. #[inline] pub fn metadata(&self) -> &Metadata<'a> { &self.metadata } /// The verbosity level of the message. #[inline] pub fn level(&self) -> Level { self.metadata.level() } /// The name of the target of the directive. #[inline] pub fn target(&self) -> &'a str { self.metadata.target() } /// The module path of the message. #[inline] pub fn module_path(&self) -> Option<&'a str> { self.module_path.map(|s| s.get()) } /// The module path of the message, if it is a `'static` string. #[inline] pub fn module_path_static(&self) -> Option<&'static str> { match self.module_path { Some(MaybeStaticStr::Static(s)) => Some(s), _ => None, } } /// The source file containing the message. #[inline] pub fn file(&self) -> Option<&'a str> { self.file.map(|s| s.get()) } /// The source file containing the message, if it is a `'static` string. #[inline] pub fn file_static(&self) -> Option<&'static str> { match self.file { Some(MaybeStaticStr::Static(s)) => Some(s), _ => None, } } /// The line containing the message. #[inline] pub fn line(&self) -> Option { self.line } /// The structured key-value pairs associated with the message. #[cfg(feature = "kv")] #[inline] pub fn key_values(&self) -> &dyn kv::Source { self.key_values.0 } /// Create a new [`RecordBuilder`](struct.RecordBuilder.html) based on this record. #[cfg(feature = "kv")] #[inline] pub fn to_builder(&self) -> RecordBuilder { RecordBuilder { record: Record { metadata: Metadata { level: self.metadata.level, target: self.metadata.target, }, args: self.args, module_path: self.module_path, file: self.file, line: self.line, key_values: self.key_values.clone(), }, } } } /// Builder for [`Record`](struct.Record.html). /// /// Typically should only be used by log library creators or for testing and "shim loggers". /// The `RecordBuilder` can set the different parameters of `Record` object, and returns /// the created object when `build` is called. /// /// # Examples /// /// ``` /// use log::{Level, Record}; /// /// let record = Record::builder() /// .args(format_args!("Error!")) /// .level(Level::Error) /// .target("myApp") /// .file(Some("server.rs")) /// .line(Some(144)) /// .module_path(Some("server")) /// .build(); /// ``` /// /// Alternatively, use [`MetadataBuilder`](struct.MetadataBuilder.html): /// /// ``` /// use log::{Record, Level, MetadataBuilder}; /// /// let error_metadata = MetadataBuilder::new() /// .target("myApp") /// .level(Level::Error) /// .build(); /// /// let record = Record::builder() /// .metadata(error_metadata) /// .args(format_args!("Error!")) /// .line(Some(433)) /// .file(Some("app.rs")) /// .module_path(Some("server")) /// .build(); /// ``` #[derive(Debug)] pub struct RecordBuilder<'a> { record: Record<'a>, } impl<'a> RecordBuilder<'a> { /// Construct new `RecordBuilder`. /// /// The default options are: /// /// - `args`: [`format_args!("")`] /// - `metadata`: [`Metadata::builder().build()`] /// - `module_path`: `None` /// - `file`: `None` /// - `line`: `None` /// /// [`format_args!("")`]: https://doc.rust-lang.org/std/macro.format_args.html /// [`Metadata::builder().build()`]: struct.MetadataBuilder.html#method.build #[inline] pub fn new() -> RecordBuilder<'a> { RecordBuilder { record: Record { args: format_args!(""), metadata: Metadata::builder().build(), module_path: None, file: None, line: None, #[cfg(feature = "kv")] key_values: KeyValues(&None::<(kv::Key, kv::Value)>), }, } } /// Set [`args`](struct.Record.html#method.args). #[inline] pub fn args(&mut self, args: fmt::Arguments<'a>) -> &mut RecordBuilder<'a> { self.record.args = args; self } /// Set [`metadata`](struct.Record.html#method.metadata). Construct a `Metadata` object with [`MetadataBuilder`](struct.MetadataBuilder.html). #[inline] pub fn metadata(&mut self, metadata: Metadata<'a>) -> &mut RecordBuilder<'a> { self.record.metadata = metadata; self } /// Set [`Metadata::level`](struct.Metadata.html#method.level). #[inline] pub fn level(&mut self, level: Level) -> &mut RecordBuilder<'a> { self.record.metadata.level = level; self } /// Set [`Metadata::target`](struct.Metadata.html#method.target) #[inline] pub fn target(&mut self, target: &'a str) -> &mut RecordBuilder<'a> { self.record.metadata.target = target; self } /// Set [`module_path`](struct.Record.html#method.module_path) #[inline] pub fn module_path(&mut self, path: Option<&'a str>) -> &mut RecordBuilder<'a> { self.record.module_path = path.map(MaybeStaticStr::Borrowed); self } /// Set [`module_path`](struct.Record.html#method.module_path) to a `'static` string #[inline] pub fn module_path_static(&mut self, path: Option<&'static str>) -> &mut RecordBuilder<'a> { self.record.module_path = path.map(MaybeStaticStr::Static); self } /// Set [`file`](struct.Record.html#method.file) #[inline] pub fn file(&mut self, file: Option<&'a str>) -> &mut RecordBuilder<'a> { self.record.file = file.map(MaybeStaticStr::Borrowed); self } /// Set [`file`](struct.Record.html#method.file) to a `'static` string. #[inline] pub fn file_static(&mut self, file: Option<&'static str>) -> &mut RecordBuilder<'a> { self.record.file = file.map(MaybeStaticStr::Static); self } /// Set [`line`](struct.Record.html#method.line) #[inline] pub fn line(&mut self, line: Option) -> &mut RecordBuilder<'a> { self.record.line = line; self } /// Set [`key_values`](struct.Record.html#method.key_values) #[cfg(feature = "kv")] #[inline] pub fn key_values(&mut self, kvs: &'a dyn kv::Source) -> &mut RecordBuilder<'a> { self.record.key_values = KeyValues(kvs); self } /// Invoke the builder and return a `Record` #[inline] pub fn build(&self) -> Record<'a> { self.record.clone() } } impl<'a> Default for RecordBuilder<'a> { fn default() -> Self { Self::new() } } /// Metadata about a log message. /// /// # Use /// /// `Metadata` structs are created when users of the library use /// logging macros. /// /// They are consumed by implementations of the `Log` trait in the /// `enabled` method. /// /// `Record`s use `Metadata` to determine the log message's severity /// and target. /// /// Users should use the `log_enabled!` macro in their code to avoid /// constructing expensive log messages. /// /// # Examples /// /// ``` /// use log::{Record, Level, Metadata}; /// /// struct MyLogger; /// /// impl log::Log for MyLogger { /// fn enabled(&self, metadata: &Metadata) -> bool { /// metadata.level() <= Level::Info /// } /// /// fn log(&self, record: &Record) { /// if self.enabled(record.metadata()) { /// println!("{} - {}", record.level(), record.args()); /// } /// } /// fn flush(&self) {} /// } /// /// # fn main(){} /// ``` #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct Metadata<'a> { level: Level, target: &'a str, } impl<'a> Metadata<'a> { /// Returns a new builder. #[inline] pub fn builder() -> MetadataBuilder<'a> { MetadataBuilder::new() } /// The verbosity level of the message. #[inline] pub fn level(&self) -> Level { self.level } /// The name of the target of the directive. #[inline] pub fn target(&self) -> &'a str { self.target } } /// Builder for [`Metadata`](struct.Metadata.html). /// /// Typically should only be used by log library creators or for testing and "shim loggers". /// The `MetadataBuilder` can set the different parameters of a `Metadata` object, and returns /// the created object when `build` is called. /// /// # Example /// /// ``` /// let target = "myApp"; /// use log::{Level, MetadataBuilder}; /// let metadata = MetadataBuilder::new() /// .level(Level::Debug) /// .target(target) /// .build(); /// ``` #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct MetadataBuilder<'a> { metadata: Metadata<'a>, } impl<'a> MetadataBuilder<'a> { /// Construct a new `MetadataBuilder`. /// /// The default options are: /// /// - `level`: `Level::Info` /// - `target`: `""` #[inline] pub fn new() -> MetadataBuilder<'a> { MetadataBuilder { metadata: Metadata { level: Level::Info, target: "", }, } } /// Setter for [`level`](struct.Metadata.html#method.level). #[inline] pub fn level(&mut self, arg: Level) -> &mut MetadataBuilder<'a> { self.metadata.level = arg; self } /// Setter for [`target`](struct.Metadata.html#method.target). #[inline] pub fn target(&mut self, target: &'a str) -> &mut MetadataBuilder<'a> { self.metadata.target = target; self } /// Returns a `Metadata` object. #[inline] pub fn build(&self) -> Metadata<'a> { self.metadata.clone() } } impl<'a> Default for MetadataBuilder<'a> { fn default() -> Self { Self::new() } } /// A trait encapsulating the operations required of a logger. pub trait Log: Sync + Send { /// Determines if a log message with the specified metadata would be /// logged. /// /// This is used by the `log_enabled!` macro to allow callers to avoid /// expensive computation of log message arguments if the message would be /// discarded anyway. /// /// # For implementors /// /// This method isn't called automatically by the `log!` macros. /// It's up to an implementation of the `Log` trait to call `enabled` in its own /// `log` method implementation to guarantee that filtering is applied. fn enabled(&self, metadata: &Metadata) -> bool; /// Logs the `Record`. /// /// # For implementors /// /// Note that `enabled` is *not* necessarily called before this method. /// Implementations of `log` should perform all necessary filtering /// internally. fn log(&self, record: &Record); /// Flushes any buffered records. /// /// # For implementors /// /// This method isn't called automatically by the `log!` macros. /// It can be called manually on shut-down to ensure any in-flight records are flushed. fn flush(&self); } // Just used as a dummy initial value for LOGGER struct NopLogger; impl Log for NopLogger { fn enabled(&self, _: &Metadata) -> bool { false } fn log(&self, _: &Record) {} fn flush(&self) {} } impl Log for &'_ T where T: ?Sized + Log, { fn enabled(&self, metadata: &Metadata) -> bool { (**self).enabled(metadata) } fn log(&self, record: &Record) { (**self).log(record); } fn flush(&self) { (**self).flush(); } } #[cfg(feature = "std")] impl Log for std::boxed::Box where T: ?Sized + Log, { fn enabled(&self, metadata: &Metadata) -> bool { self.as_ref().enabled(metadata) } fn log(&self, record: &Record) { self.as_ref().log(record); } fn flush(&self) { self.as_ref().flush(); } } #[cfg(feature = "std")] impl Log for std::sync::Arc where T: ?Sized + Log, { fn enabled(&self, metadata: &Metadata) -> bool { self.as_ref().enabled(metadata) } fn log(&self, record: &Record) { self.as_ref().log(record); } fn flush(&self) { self.as_ref().flush(); } } /// Sets the global maximum log level. /// /// Generally, this should only be called by the active logging implementation. /// /// Note that `Trace` is the maximum level, because it provides the maximum amount of detail in the emitted logs. #[inline] #[cfg(target_has_atomic = "ptr")] pub fn set_max_level(level: LevelFilter) { MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed); } /// A thread-unsafe version of [`set_max_level`]. /// /// This function is available on all platforms, even those that do not have /// support for atomics that is needed by [`set_max_level`]. /// /// In almost all cases, [`set_max_level`] should be preferred. /// /// # Safety /// /// This function is only safe to call when it cannot race with any other /// calls to `set_max_level` or `set_max_level_racy`. /// /// This can be upheld by (for example) making sure that **there are no other /// threads**, and (on embedded) that **interrupts are disabled**. /// /// It is safe to use all other logging functions while this function runs /// (including all logging macros). /// /// [`set_max_level`]: fn.set_max_level.html #[inline] pub unsafe fn set_max_level_racy(level: LevelFilter) { // `MAX_LOG_LEVEL_FILTER` uses a `Cell` as the underlying primitive when a // platform doesn't support `target_has_atomic = "ptr"`, so even though this looks the same // as `set_max_level` it may have different safety properties. MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed); } /// Returns the current maximum log level. /// /// The [`log!`], [`error!`], [`warn!`], [`info!`], [`debug!`], and [`trace!`] macros check /// this value and discard any message logged at a higher level. The maximum /// log level is set by the [`set_max_level`] function. /// /// [`log!`]: macro.log.html /// [`error!`]: macro.error.html /// [`warn!`]: macro.warn.html /// [`info!`]: macro.info.html /// [`debug!`]: macro.debug.html /// [`trace!`]: macro.trace.html /// [`set_max_level`]: fn.set_max_level.html #[inline(always)] pub fn max_level() -> LevelFilter { // Since `LevelFilter` is `repr(usize)`, // this transmute is sound if and only if `MAX_LOG_LEVEL_FILTER` // is set to a usize that is a valid discriminant for `LevelFilter`. // Since `MAX_LOG_LEVEL_FILTER` is private, the only time it's set // is by `set_max_level` above, i.e. by casting a `LevelFilter` to `usize`. // So any usize stored in `MAX_LOG_LEVEL_FILTER` is a valid discriminant. unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) } } /// Sets the global logger to a `Box`. /// /// This is a simple convenience wrapper over `set_logger`, which takes a /// `Box` rather than a `&'static Log`. See the documentation for /// [`set_logger`] for more details. /// /// Requires the `std` feature. /// /// # Errors /// /// An error is returned if a logger has already been set. /// /// [`set_logger`]: fn.set_logger.html #[cfg(all(feature = "std", target_has_atomic = "ptr"))] pub fn set_boxed_logger(logger: Box) -> Result<(), SetLoggerError> { set_logger_inner(|| Box::leak(logger)) } /// Sets the global logger to a `&'static Log`. /// /// This function may only be called once in the lifetime of a program. Any log /// events that occur before the call to `set_logger` completes will be ignored. /// /// This function does not typically need to be called manually. Logger /// implementations should provide an initialization method that installs the /// logger internally. /// /// # Availability /// /// This method is available even when the `std` feature is disabled. However, /// it is currently unavailable on `thumbv6` targets, which lack support for /// some atomic operations which are used by this function. Even on those /// targets, [`set_logger_racy`] will be available. /// /// # Errors /// /// An error is returned if a logger has already been set. /// /// # Examples /// /// ``` /// use log::{error, info, warn, Record, Level, Metadata, LevelFilter}; /// /// static MY_LOGGER: MyLogger = MyLogger; /// /// struct MyLogger; /// /// impl log::Log for MyLogger { /// fn enabled(&self, metadata: &Metadata) -> bool { /// metadata.level() <= Level::Info /// } /// /// fn log(&self, record: &Record) { /// if self.enabled(record.metadata()) { /// println!("{} - {}", record.level(), record.args()); /// } /// } /// fn flush(&self) {} /// } /// /// # fn main(){ /// log::set_logger(&MY_LOGGER).unwrap(); /// log::set_max_level(LevelFilter::Info); /// /// info!("hello log"); /// warn!("warning"); /// error!("oops"); /// # } /// ``` /// /// [`set_logger_racy`]: fn.set_logger_racy.html #[cfg(target_has_atomic = "ptr")] pub fn set_logger(logger: &'static dyn Log) -> Result<(), SetLoggerError> { set_logger_inner(|| logger) } #[cfg(target_has_atomic = "ptr")] fn set_logger_inner(make_logger: F) -> Result<(), SetLoggerError> where F: FnOnce() -> &'static dyn Log, { match STATE.compare_exchange( UNINITIALIZED, INITIALIZING, Ordering::Acquire, Ordering::Relaxed, ) { Ok(UNINITIALIZED) => { unsafe { LOGGER = make_logger(); } STATE.store(INITIALIZED, Ordering::Release); Ok(()) } Err(INITIALIZING) => { while STATE.load(Ordering::Relaxed) == INITIALIZING { std::hint::spin_loop(); } Err(SetLoggerError(())) } _ => Err(SetLoggerError(())), } } /// A thread-unsafe version of [`set_logger`]. /// /// This function is available on all platforms, even those that do not have /// support for atomics that is needed by [`set_logger`]. /// /// In almost all cases, [`set_logger`] should be preferred. /// /// # Safety /// /// This function is only safe to call when it cannot race with any other /// calls to `set_logger` or `set_logger_racy`. /// /// This can be upheld by (for example) making sure that **there are no other /// threads**, and (on embedded) that **interrupts are disabled**. /// /// It is safe to use other logging functions while this function runs /// (including all logging macros). /// /// [`set_logger`]: fn.set_logger.html pub unsafe fn set_logger_racy(logger: &'static dyn Log) -> Result<(), SetLoggerError> { match STATE.load(Ordering::Acquire) { UNINITIALIZED => { LOGGER = logger; STATE.store(INITIALIZED, Ordering::Release); Ok(()) } INITIALIZING => { // This is just plain UB, since we were racing another initialization function unreachable!("set_logger_racy must not be used with other initialization functions") } _ => Err(SetLoggerError(())), } } /// The type returned by [`set_logger`] if [`set_logger`] has already been called. /// /// [`set_logger`]: fn.set_logger.html #[allow(missing_copy_implementations)] #[derive(Debug)] pub struct SetLoggerError(()); impl fmt::Display for SetLoggerError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.write_str(SET_LOGGER_ERROR) } } // The Error trait is not available in libcore #[cfg(feature = "std")] impl error::Error for SetLoggerError {} /// The type returned by [`from_str`] when the string doesn't match any of the log levels. /// /// [`from_str`]: https://doc.rust-lang.org/std/str/trait.FromStr.html#tymethod.from_str #[allow(missing_copy_implementations)] #[derive(Debug, PartialEq, Eq)] pub struct ParseLevelError(()); impl fmt::Display for ParseLevelError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.write_str(LEVEL_PARSE_ERROR) } } // The Error trait is not available in libcore #[cfg(feature = "std")] impl error::Error for ParseLevelError {} /// Returns a reference to the logger. /// /// If a logger has not been set, a no-op implementation is returned. pub fn logger() -> &'static dyn Log { // Acquire memory ordering guarantees that current thread would see any // memory writes that happened before store of the value // into `STATE` with memory ordering `Release` or stronger. // // Since the value `INITIALIZED` is written only after `LOGGER` was // initialized, observing it after `Acquire` load here makes both // write to the `LOGGER` static and initialization of the logger // internal state synchronized with current thread. if STATE.load(Ordering::Acquire) != INITIALIZED { static NOP: NopLogger = NopLogger; &NOP } else { unsafe { LOGGER } } } // WARNING: this is not part of the crate's public API and is subject to change at any time #[doc(hidden)] pub mod __private_api; /// The statically resolved maximum log level. /// /// See the crate level documentation for information on how to configure this. /// /// This value is checked by the log macros, but not by the `Log`ger returned by /// the [`logger`] function. Code that manually calls functions on that value /// should compare the level against this value. /// /// [`logger`]: fn.logger.html pub const STATIC_MAX_LEVEL: LevelFilter = match cfg!(debug_assertions) { false if cfg!(feature = "release_max_level_off") => LevelFilter::Off, false if cfg!(feature = "release_max_level_error") => LevelFilter::Error, false if cfg!(feature = "release_max_level_warn") => LevelFilter::Warn, false if cfg!(feature = "release_max_level_info") => LevelFilter::Info, false if cfg!(feature = "release_max_level_debug") => LevelFilter::Debug, false if cfg!(feature = "release_max_level_trace") => LevelFilter::Trace, _ if cfg!(feature = "max_level_off") => LevelFilter::Off, _ if cfg!(feature = "max_level_error") => LevelFilter::Error, _ if cfg!(feature = "max_level_warn") => LevelFilter::Warn, _ if cfg!(feature = "max_level_info") => LevelFilter::Info, _ if cfg!(feature = "max_level_debug") => LevelFilter::Debug, _ => LevelFilter::Trace, }; #[cfg(test)] mod tests { use super::{Level, LevelFilter, ParseLevelError, STATIC_MAX_LEVEL}; #[test] fn test_levelfilter_from_str() { let tests = [ ("off", Ok(LevelFilter::Off)), ("error", Ok(LevelFilter::Error)), ("warn", Ok(LevelFilter::Warn)), ("info", Ok(LevelFilter::Info)), ("debug", Ok(LevelFilter::Debug)), ("trace", Ok(LevelFilter::Trace)), ("OFF", Ok(LevelFilter::Off)), ("ERROR", Ok(LevelFilter::Error)), ("WARN", Ok(LevelFilter::Warn)), ("INFO", Ok(LevelFilter::Info)), ("DEBUG", Ok(LevelFilter::Debug)), ("TRACE", Ok(LevelFilter::Trace)), ("asdf", Err(ParseLevelError(()))), ]; for &(s, ref expected) in &tests { assert_eq!(expected, &s.parse()); } } #[test] fn test_level_from_str() { let tests = [ ("OFF", Err(ParseLevelError(()))), ("error", Ok(Level::Error)), ("warn", Ok(Level::Warn)), ("info", Ok(Level::Info)), ("debug", Ok(Level::Debug)), ("trace", Ok(Level::Trace)), ("ERROR", Ok(Level::Error)), ("WARN", Ok(Level::Warn)), ("INFO", Ok(Level::Info)), ("DEBUG", Ok(Level::Debug)), ("TRACE", Ok(Level::Trace)), ("asdf", Err(ParseLevelError(()))), ]; for &(s, ref expected) in &tests { assert_eq!(expected, &s.parse()); } } #[test] fn test_level_as_str() { let tests = &[ (Level::Error, "ERROR"), (Level::Warn, "WARN"), (Level::Info, "INFO"), (Level::Debug, "DEBUG"), (Level::Trace, "TRACE"), ]; for (input, expected) in tests { assert_eq!(*expected, input.as_str()); } } #[test] fn test_level_show() { assert_eq!("INFO", Level::Info.to_string()); assert_eq!("ERROR", Level::Error.to_string()); } #[test] fn test_levelfilter_show() { assert_eq!("OFF", LevelFilter::Off.to_string()); assert_eq!("ERROR", LevelFilter::Error.to_string()); } #[test] fn test_cross_cmp() { assert!(Level::Debug > LevelFilter::Error); assert!(LevelFilter::Warn < Level::Trace); assert!(LevelFilter::Off < Level::Error); } #[test] fn test_cross_eq() { assert!(Level::Error == LevelFilter::Error); assert!(LevelFilter::Off != Level::Error); assert!(Level::Trace == LevelFilter::Trace); } #[test] fn test_to_level() { assert_eq!(Some(Level::Error), LevelFilter::Error.to_level()); assert_eq!(None, LevelFilter::Off.to_level()); assert_eq!(Some(Level::Debug), LevelFilter::Debug.to_level()); } #[test] fn test_to_level_filter() { assert_eq!(LevelFilter::Error, Level::Error.to_level_filter()); assert_eq!(LevelFilter::Trace, Level::Trace.to_level_filter()); } #[test] fn test_level_filter_as_str() { let tests = &[ (LevelFilter::Off, "OFF"), (LevelFilter::Error, "ERROR"), (LevelFilter::Warn, "WARN"), (LevelFilter::Info, "INFO"), (LevelFilter::Debug, "DEBUG"), (LevelFilter::Trace, "TRACE"), ]; for (input, expected) in tests { assert_eq!(*expected, input.as_str()); } } #[test] #[cfg_attr(not(debug_assertions), ignore)] fn test_static_max_level_debug() { if cfg!(feature = "max_level_off") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off); } else if cfg!(feature = "max_level_error") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error); } else if cfg!(feature = "max_level_warn") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn); } else if cfg!(feature = "max_level_info") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info); } else if cfg!(feature = "max_level_debug") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug); } else { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace); } } #[test] #[cfg_attr(debug_assertions, ignore)] fn test_static_max_level_release() { if cfg!(feature = "release_max_level_off") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off); } else if cfg!(feature = "release_max_level_error") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error); } else if cfg!(feature = "release_max_level_warn") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn); } else if cfg!(feature = "release_max_level_info") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info); } else if cfg!(feature = "release_max_level_debug") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug); } else if cfg!(feature = "release_max_level_trace") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace); } else if cfg!(feature = "max_level_off") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off); } else if cfg!(feature = "max_level_error") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error); } else if cfg!(feature = "max_level_warn") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn); } else if cfg!(feature = "max_level_info") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info); } else if cfg!(feature = "max_level_debug") { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug); } else { assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace); } } #[test] #[cfg(feature = "std")] fn test_error_trait() { use super::SetLoggerError; let e = SetLoggerError(()); assert_eq!( &e.to_string(), "attempted to set a logger after the logging system \ was already initialized" ); } #[test] fn test_metadata_builder() { use super::MetadataBuilder; let target = "myApp"; let metadata_test = MetadataBuilder::new() .level(Level::Debug) .target(target) .build(); assert_eq!(metadata_test.level(), Level::Debug); assert_eq!(metadata_test.target(), "myApp"); } #[test] fn test_metadata_convenience_builder() { use super::Metadata; let target = "myApp"; let metadata_test = Metadata::builder() .level(Level::Debug) .target(target) .build(); assert_eq!(metadata_test.level(), Level::Debug); assert_eq!(metadata_test.target(), "myApp"); } #[test] fn test_record_builder() { use super::{MetadataBuilder, RecordBuilder}; let target = "myApp"; let metadata = MetadataBuilder::new().target(target).build(); let fmt_args = format_args!("hello"); let record_test = RecordBuilder::new() .args(fmt_args) .metadata(metadata) .module_path(Some("foo")) .file(Some("bar")) .line(Some(30)) .build(); assert_eq!(record_test.metadata().target(), "myApp"); assert_eq!(record_test.module_path(), Some("foo")); assert_eq!(record_test.file(), Some("bar")); assert_eq!(record_test.line(), Some(30)); } #[test] fn test_record_convenience_builder() { use super::{Metadata, Record}; let target = "myApp"; let metadata = Metadata::builder().target(target).build(); let fmt_args = format_args!("hello"); let record_test = Record::builder() .args(fmt_args) .metadata(metadata) .module_path(Some("foo")) .file(Some("bar")) .line(Some(30)) .build(); assert_eq!(record_test.target(), "myApp"); assert_eq!(record_test.module_path(), Some("foo")); assert_eq!(record_test.file(), Some("bar")); assert_eq!(record_test.line(), Some(30)); } #[test] fn test_record_complete_builder() { use super::{Level, Record}; let target = "myApp"; let record_test = Record::builder() .module_path(Some("foo")) .file(Some("bar")) .line(Some(30)) .target(target) .level(Level::Error) .build(); assert_eq!(record_test.target(), "myApp"); assert_eq!(record_test.level(), Level::Error); assert_eq!(record_test.module_path(), Some("foo")); assert_eq!(record_test.file(), Some("bar")); assert_eq!(record_test.line(), Some(30)); } #[test] #[cfg(feature = "kv")] fn test_record_key_values_builder() { use super::Record; use crate::kv::{self, VisitSource}; struct TestVisitSource { seen_pairs: usize, } impl<'kvs> VisitSource<'kvs> for TestVisitSource { fn visit_pair( &mut self, _: kv::Key<'kvs>, _: kv::Value<'kvs>, ) -> Result<(), kv::Error> { self.seen_pairs += 1; Ok(()) } } let kvs: &[(&str, i32)] = &[("a", 1), ("b", 2)]; let record_test = Record::builder().key_values(&kvs).build(); let mut visitor = TestVisitSource { seen_pairs: 0 }; record_test.key_values().visit(&mut visitor).unwrap(); assert_eq!(2, visitor.seen_pairs); } #[test] #[cfg(feature = "kv")] fn test_record_key_values_get_coerce() { use super::Record; let kvs: &[(&str, &str)] = &[("a", "1"), ("b", "2")]; let record = Record::builder().key_values(&kvs).build(); assert_eq!( "2", record .key_values() .get("b".into()) .expect("missing key") .to_borrowed_str() .expect("invalid value") ); } // Test that the `impl Log for Foo` blocks work // This test mostly operates on a type level, so failures will be compile errors #[test] fn test_foreign_impl() { use super::Log; #[cfg(feature = "std")] use std::sync::Arc; fn assert_is_log() {} assert_is_log::<&dyn Log>(); #[cfg(feature = "std")] assert_is_log::>(); #[cfg(feature = "std")] assert_is_log::>(); // Assert these statements for all T: Log + ?Sized #[allow(unused)] fn forall() { #[cfg(feature = "std")] assert_is_log::>(); assert_is_log::<&T>(); #[cfg(feature = "std")] assert_is_log::>(); } } } log-0.4.26/src/macros.rs000064400000000000000000000244121046102023000131220ustar 00000000000000// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. /// The standard logging macro. /// /// This macro will generically log with the specified `Level` and `format!` /// based argument list. /// /// # Examples /// /// ``` /// use log::{log, Level}; /// /// # fn main() { /// let data = (42, "Forty-two"); /// let private_data = "private"; /// /// log!(Level::Error, "Received errors: {}, {}", data.0, data.1); /// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}", /// data.0, data.1, private_data); /// # } /// ``` #[macro_export] macro_rules! log { // log!(target: "my_target", Level::Info, key1:? = 42, key2 = true; "a {} event", "log"); (target: $target:expr, $lvl:expr, $($key:tt $(:$capture:tt)? $(= $value:expr)?),+; $($arg:tt)+) => ({ let lvl = $lvl; if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { $crate::__private_api::log::<&_>( $crate::__private_api::format_args!($($arg)+), lvl, &($target, $crate::__private_api::module_path!(), $crate::__private_api::loc()), &[$(($crate::__log_key!($key), $crate::__log_value!($key $(:$capture)* = $($value)*))),+] ); } }); // log!(target: "my_target", Level::Info, "a {} event", "log"); (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ let lvl = $lvl; if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { $crate::__private_api::log( $crate::__private_api::format_args!($($arg)+), lvl, &($target, $crate::__private_api::module_path!(), $crate::__private_api::loc()), (), ); } }); // log!(Level::Info, "a log event") ($lvl:expr, $($arg:tt)+) => ($crate::log!(target: $crate::__private_api::module_path!(), $lvl, $($arg)+)); } /// Logs a message at the error level. /// /// # Examples /// /// ``` /// use log::error; /// /// # fn main() { /// let (err_info, port) = ("No connection", 22); /// /// error!("Error: {err_info} on port {port}"); /// error!(target: "app_events", "App Error: {err_info}, Port: {port}"); /// # } /// ``` #[macro_export] macro_rules! error { // error!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") // error!(target: "my_target", "a {} event", "log") (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Error, $($arg)+)); // error!("a {} event", "log") ($($arg:tt)+) => ($crate::log!($crate::Level::Error, $($arg)+)) } /// Logs a message at the warn level. /// /// # Examples /// /// ``` /// use log::warn; /// /// # fn main() { /// let warn_description = "Invalid Input"; /// /// warn!("Warning! {warn_description}!"); /// warn!(target: "input_events", "App received warning: {warn_description}"); /// # } /// ``` #[macro_export] macro_rules! warn { // warn!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") // warn!(target: "my_target", "a {} event", "log") (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Warn, $($arg)+)); // warn!("a {} event", "log") ($($arg:tt)+) => ($crate::log!($crate::Level::Warn, $($arg)+)) } /// Logs a message at the info level. /// /// # Examples /// /// ``` /// use log::info; /// /// # fn main() { /// # struct Connection { port: u32, speed: f32 } /// let conn_info = Connection { port: 40, speed: 3.20 }; /// /// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed); /// info!(target: "connection_events", "Successful connection, port: {}, speed: {}", /// conn_info.port, conn_info.speed); /// # } /// ``` #[macro_export] macro_rules! info { // info!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") // info!(target: "my_target", "a {} event", "log") (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Info, $($arg)+)); // info!("a {} event", "log") ($($arg:tt)+) => ($crate::log!($crate::Level::Info, $($arg)+)) } /// Logs a message at the debug level. /// /// # Examples /// /// ``` /// use log::debug; /// /// # fn main() { /// # struct Position { x: f32, y: f32 } /// let pos = Position { x: 3.234, y: -1.223 }; /// /// debug!("New position: x: {}, y: {}", pos.x, pos.y); /// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y); /// # } /// ``` #[macro_export] macro_rules! debug { // debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") // debug!(target: "my_target", "a {} event", "log") (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Debug, $($arg)+)); // debug!("a {} event", "log") ($($arg:tt)+) => ($crate::log!($crate::Level::Debug, $($arg)+)) } /// Logs a message at the trace level. /// /// # Examples /// /// ``` /// use log::trace; /// /// # fn main() { /// # struct Position { x: f32, y: f32 } /// let pos = Position { x: 3.234, y: -1.223 }; /// /// trace!("Position is: x: {}, y: {}", pos.x, pos.y); /// trace!(target: "app_events", "x is {} and y is {}", /// if pos.x >= 0.0 { "positive" } else { "negative" }, /// if pos.y >= 0.0 { "positive" } else { "negative" }); /// # } /// ``` #[macro_export] macro_rules! trace { // trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") // trace!(target: "my_target", "a {} event", "log") (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Trace, $($arg)+)); // trace!("a {} event", "log") ($($arg:tt)+) => ($crate::log!($crate::Level::Trace, $($arg)+)) } /// Determines if a message logged at the specified level in that module will /// be logged. /// /// This can be used to avoid expensive computation of log message arguments if /// the message would be ignored anyway. /// /// # Examples /// /// ``` /// use log::Level::Debug; /// use log::{debug, log_enabled}; /// /// # fn foo() { /// if log_enabled!(Debug) { /// let data = expensive_call(); /// debug!("expensive debug data: {} {}", data.x, data.y); /// } /// if log_enabled!(target: "Global", Debug) { /// let data = expensive_call(); /// debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y); /// } /// # } /// # struct Data { x: u32, y: u32 } /// # fn expensive_call() -> Data { Data { x: 0, y: 0 } } /// # fn main() {} /// ``` #[macro_export] macro_rules! log_enabled { (target: $target:expr, $lvl:expr) => {{ let lvl = $lvl; lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() && $crate::__private_api::enabled(lvl, $target) }}; ($lvl:expr) => { $crate::log_enabled!(target: $crate::__private_api::module_path!(), $lvl) }; } // These macros use a pattern of #[cfg]s to produce nicer error // messages when log features aren't available #[doc(hidden)] #[macro_export] #[cfg(feature = "kv")] macro_rules! __log_key { // key1 = 42 ($($args:ident)*) => { $crate::__private_api::stringify!($($args)*) }; // "key1" = 42 ($($args:expr)*) => { $($args)* }; } #[doc(hidden)] #[macro_export] #[cfg(not(feature = "kv"))] macro_rules! __log_key { ($($args:tt)*) => { compile_error!("key value support requires the `kv` feature of `log`") }; } #[doc(hidden)] #[macro_export] #[cfg(feature = "kv")] macro_rules! __log_value { // Entrypoint ($key:tt = $args:expr) => { $crate::__log_value!(($args):value) }; ($key:tt :$capture:tt = $args:expr) => { $crate::__log_value!(($args):$capture) }; ($key:ident =) => { $crate::__log_value!(($key):value) }; ($key:ident :$capture:tt =) => { $crate::__log_value!(($key):$capture) }; // ToValue (($args:expr):value) => { $crate::__private_api::capture_to_value(&&$args) }; // Debug (($args:expr):?) => { $crate::__private_api::capture_debug(&&$args) }; (($args:expr):debug) => { $crate::__private_api::capture_debug(&&$args) }; // Display (($args:expr):%) => { $crate::__private_api::capture_display(&&$args) }; (($args:expr):display) => { $crate::__private_api::capture_display(&&$args) }; //Error (($args:expr):err) => { $crate::__log_value_error!($args) }; // sval::Value (($args:expr):sval) => { $crate::__log_value_sval!($args) }; // serde::Serialize (($args:expr):serde) => { $crate::__log_value_serde!($args) }; } #[doc(hidden)] #[macro_export] #[cfg(not(feature = "kv"))] macro_rules! __log_value { ($($args:tt)*) => { compile_error!("key value support requires the `kv` feature of `log`") }; } #[doc(hidden)] #[macro_export] #[cfg(feature = "kv_sval")] macro_rules! __log_value_sval { ($args:expr) => { $crate::__private_api::capture_sval(&&$args) }; } #[doc(hidden)] #[macro_export] #[cfg(not(feature = "kv_sval"))] macro_rules! __log_value_sval { ($args:expr) => { compile_error!("capturing values as `sval::Value` requites the `kv_sval` feature of `log`") }; } #[doc(hidden)] #[macro_export] #[cfg(feature = "kv_serde")] macro_rules! __log_value_serde { ($args:expr) => { $crate::__private_api::capture_serde(&&$args) }; } #[doc(hidden)] #[macro_export] #[cfg(not(feature = "kv_serde"))] macro_rules! __log_value_serde { ($args:expr) => { compile_error!( "capturing values as `serde::Serialize` requites the `kv_serde` feature of `log`" ) }; } #[doc(hidden)] #[macro_export] #[cfg(feature = "kv_std")] macro_rules! __log_value_error { ($args:expr) => { $crate::__private_api::capture_error(&$args) }; } #[doc(hidden)] #[macro_export] #[cfg(not(feature = "kv_std"))] macro_rules! __log_value_error { ($args:expr) => { compile_error!( "capturing values as `std::error::Error` requites the `kv_std` feature of `log`" ) }; } log-0.4.26/src/serde.rs000064400000000000000000000305301046102023000127360ustar 00000000000000#![cfg(feature = "serde")] use serde::de::{ Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, Unexpected, VariantAccess, Visitor, }; use serde::ser::{Serialize, Serializer}; use crate::{Level, LevelFilter, LOG_LEVEL_NAMES}; use std::fmt; use std::str::{self, FromStr}; // The Deserialize impls are handwritten to be case-insensitive using FromStr. impl Serialize for Level { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match *self { Level::Error => serializer.serialize_unit_variant("Level", 0, "ERROR"), Level::Warn => serializer.serialize_unit_variant("Level", 1, "WARN"), Level::Info => serializer.serialize_unit_variant("Level", 2, "INFO"), Level::Debug => serializer.serialize_unit_variant("Level", 3, "DEBUG"), Level::Trace => serializer.serialize_unit_variant("Level", 4, "TRACE"), } } } impl<'de> Deserialize<'de> for Level { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct LevelIdentifier; impl<'de> Visitor<'de> for LevelIdentifier { type Value = Level; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("log level") } fn visit_u64(self, v: u64) -> Result where E: Error, { let variant = LOG_LEVEL_NAMES[1..] .get(v as usize) .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?; self.visit_str(variant) } fn visit_str(self, s: &str) -> Result where E: Error, { // Case-insensitive. FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES[1..])) } fn visit_bytes(self, value: &[u8]) -> Result where E: Error, { let variant = str::from_utf8(value) .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?; self.visit_str(variant) } } impl<'de> DeserializeSeed<'de> for LevelIdentifier { type Value = Level; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_identifier(LevelIdentifier) } } struct LevelEnum; impl<'de> Visitor<'de> for LevelEnum { type Value = Level; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("log level") } fn visit_enum(self, value: A) -> Result where A: EnumAccess<'de>, { let (level, variant) = value.variant_seed(LevelIdentifier)?; // Every variant is a unit variant. variant.unit_variant()?; Ok(level) } } deserializer.deserialize_enum("Level", &LOG_LEVEL_NAMES[1..], LevelEnum) } } impl Serialize for LevelFilter { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match *self { LevelFilter::Off => serializer.serialize_unit_variant("LevelFilter", 0, "OFF"), LevelFilter::Error => serializer.serialize_unit_variant("LevelFilter", 1, "ERROR"), LevelFilter::Warn => serializer.serialize_unit_variant("LevelFilter", 2, "WARN"), LevelFilter::Info => serializer.serialize_unit_variant("LevelFilter", 3, "INFO"), LevelFilter::Debug => serializer.serialize_unit_variant("LevelFilter", 4, "DEBUG"), LevelFilter::Trace => serializer.serialize_unit_variant("LevelFilter", 5, "TRACE"), } } } impl<'de> Deserialize<'de> for LevelFilter { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct LevelFilterIdentifier; impl<'de> Visitor<'de> for LevelFilterIdentifier { type Value = LevelFilter; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("log level filter") } fn visit_u64(self, v: u64) -> Result where E: Error, { let variant = LOG_LEVEL_NAMES .get(v as usize) .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?; self.visit_str(variant) } fn visit_str(self, s: &str) -> Result where E: Error, { // Case-insensitive. FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES)) } fn visit_bytes(self, value: &[u8]) -> Result where E: Error, { let variant = str::from_utf8(value) .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?; self.visit_str(variant) } } impl<'de> DeserializeSeed<'de> for LevelFilterIdentifier { type Value = LevelFilter; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_identifier(LevelFilterIdentifier) } } struct LevelFilterEnum; impl<'de> Visitor<'de> for LevelFilterEnum { type Value = LevelFilter; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("log level filter") } fn visit_enum(self, value: A) -> Result where A: EnumAccess<'de>, { let (level_filter, variant) = value.variant_seed(LevelFilterIdentifier)?; // Every variant is a unit variant. variant.unit_variant()?; Ok(level_filter) } } deserializer.deserialize_enum("LevelFilter", &LOG_LEVEL_NAMES, LevelFilterEnum) } } #[cfg(test)] mod tests { use crate::{Level, LevelFilter}; use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token}; fn level_token(variant: &'static str) -> Token { Token::UnitVariant { name: "Level", variant, } } fn level_bytes_tokens(variant: &'static [u8]) -> [Token; 3] { [ Token::Enum { name: "Level" }, Token::Bytes(variant), Token::Unit, ] } fn level_variant_tokens(variant: u32) -> [Token; 3] { [ Token::Enum { name: "Level" }, Token::U32(variant), Token::Unit, ] } fn level_filter_token(variant: &'static str) -> Token { Token::UnitVariant { name: "LevelFilter", variant, } } fn level_filter_bytes_tokens(variant: &'static [u8]) -> [Token; 3] { [ Token::Enum { name: "LevelFilter", }, Token::Bytes(variant), Token::Unit, ] } fn level_filter_variant_tokens(variant: u32) -> [Token; 3] { [ Token::Enum { name: "LevelFilter", }, Token::U32(variant), Token::Unit, ] } #[test] fn test_level_ser_de() { let cases = &[ (Level::Error, [level_token("ERROR")]), (Level::Warn, [level_token("WARN")]), (Level::Info, [level_token("INFO")]), (Level::Debug, [level_token("DEBUG")]), (Level::Trace, [level_token("TRACE")]), ]; for (s, expected) in cases { assert_tokens(s, expected); } } #[test] fn test_level_case_insensitive() { let cases = &[ (Level::Error, [level_token("error")]), (Level::Warn, [level_token("warn")]), (Level::Info, [level_token("info")]), (Level::Debug, [level_token("debug")]), (Level::Trace, [level_token("trace")]), ]; for (s, expected) in cases { assert_de_tokens(s, expected); } } #[test] fn test_level_de_bytes() { let cases = &[ (Level::Error, level_bytes_tokens(b"ERROR")), (Level::Warn, level_bytes_tokens(b"WARN")), (Level::Info, level_bytes_tokens(b"INFO")), (Level::Debug, level_bytes_tokens(b"DEBUG")), (Level::Trace, level_bytes_tokens(b"TRACE")), ]; for (value, tokens) in cases { assert_de_tokens(value, tokens); } } #[test] fn test_level_de_variant_index() { let cases = &[ (Level::Error, level_variant_tokens(0)), (Level::Warn, level_variant_tokens(1)), (Level::Info, level_variant_tokens(2)), (Level::Debug, level_variant_tokens(3)), (Level::Trace, level_variant_tokens(4)), ]; for (value, tokens) in cases { assert_de_tokens(value, tokens); } } #[test] fn test_level_de_error() { let msg = "unknown variant `errorx`, expected one of \ `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`"; assert_de_tokens_error::(&[level_token("errorx")], msg); } #[test] fn test_level_filter_ser_de() { let cases = &[ (LevelFilter::Off, [level_filter_token("OFF")]), (LevelFilter::Error, [level_filter_token("ERROR")]), (LevelFilter::Warn, [level_filter_token("WARN")]), (LevelFilter::Info, [level_filter_token("INFO")]), (LevelFilter::Debug, [level_filter_token("DEBUG")]), (LevelFilter::Trace, [level_filter_token("TRACE")]), ]; for (s, expected) in cases { assert_tokens(s, expected); } } #[test] fn test_level_filter_case_insensitive() { let cases = &[ (LevelFilter::Off, [level_filter_token("off")]), (LevelFilter::Error, [level_filter_token("error")]), (LevelFilter::Warn, [level_filter_token("warn")]), (LevelFilter::Info, [level_filter_token("info")]), (LevelFilter::Debug, [level_filter_token("debug")]), (LevelFilter::Trace, [level_filter_token("trace")]), ]; for (s, expected) in cases { assert_de_tokens(s, expected); } } #[test] fn test_level_filter_de_bytes() { let cases = &[ (LevelFilter::Off, level_filter_bytes_tokens(b"OFF")), (LevelFilter::Error, level_filter_bytes_tokens(b"ERROR")), (LevelFilter::Warn, level_filter_bytes_tokens(b"WARN")), (LevelFilter::Info, level_filter_bytes_tokens(b"INFO")), (LevelFilter::Debug, level_filter_bytes_tokens(b"DEBUG")), (LevelFilter::Trace, level_filter_bytes_tokens(b"TRACE")), ]; for (value, tokens) in cases { assert_de_tokens(value, tokens); } } #[test] fn test_level_filter_de_variant_index() { let cases = &[ (LevelFilter::Off, level_filter_variant_tokens(0)), (LevelFilter::Error, level_filter_variant_tokens(1)), (LevelFilter::Warn, level_filter_variant_tokens(2)), (LevelFilter::Info, level_filter_variant_tokens(3)), (LevelFilter::Debug, level_filter_variant_tokens(4)), (LevelFilter::Trace, level_filter_variant_tokens(5)), ]; for (value, tokens) in cases { assert_de_tokens(value, tokens); } } #[test] fn test_level_filter_de_error() { let msg = "unknown variant `errorx`, expected one of \ `OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`"; assert_de_tokens_error::(&[level_filter_token("errorx")], msg); } } log-0.4.26/triagebot.toml000064400000000000000000000000111046102023000133430ustar 00000000000000[assign]