Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/tracing-log/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/tracing-log/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"CHANGELOG.md":"cfe37d5721203d44066829fc75e6d97183b23cd936489cdb22bd89cdf3e4a1bc","Cargo.toml":"edd0ac06732dcfc497966f660f407057f0efa18e9b7ae8b0cb52ad26be54fdca","LICENSE":"898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1","README.md":"521c718a9badf8b2cc14389b207d71fad1a1eb5386d06e5936aa82295b83424b","benches/logging.rs":"d4d0ceb4bf0fcf0c139c48bece64cad22c04b0c83fa2754983b5d4f141c817b5","src/interest_cache.rs":"90b516d5afc2e7000eaf3691fb37cd0e20f545cf08b7653b8f518cb207a19dc4","src/lib.rs":"f095c783440357112be230b4b40b8c3cb0def63fd1e15776cffb74506c5efe96","src/log_tracer.rs":"679c0a84896598439bcb8a01bc49ae58148039df642f43c70fd665b9c687a05a","tests/log_tracer.rs":"2d4725822b19c47c0cbcfaf2f9af3f939f55b4b0d9b3a2c5584af2b77453854b","tests/reexport_log_crate.rs":"1eb4672784ecda75743494b0662d90fd48b1252b44b68afa898fa0bec3699683"},"package":"ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"}
|
||||
101
third-party/vendor/tracing-log/CHANGELOG.md
vendored
Normal file
101
third-party/vendor/tracing-log/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# 0.2.0 (October 24th, 2023)
|
||||
|
||||
This release contains two breaking changes: the removal of the `env_logger`
|
||||
and `trace_logger` features. Below are the suggested migration paths:
|
||||
|
||||
- `env_logger`: users should use [`tracing_subscriber::fmt::Subscriber`]
|
||||
or [`tracing_subscriber::fmt::Layer`] with the [`Targets`] or
|
||||
[`EnvFilter`] filters instead.
|
||||
- `trace_logger`: users should use the `tracing` crate's
|
||||
["log" feature flag][log-feature] instead.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- Remove deprecated `env_logger` feature. This removes the dependency
|
||||
on the unmaintained `atty` crate, resolving the security advisory
|
||||
[GHSA-g98v-hv3f-hcfr]/[RUSTSEC-2021-0145]. ([#2771])
|
||||
- Remove deprecated `trace_logger` feature. ([#2771])
|
||||
|
||||
[#2771]: https://github.com/tokio-rs/tracing/pull/2771
|
||||
[`tracing_subscriber::fmt::Subscriber`]: https://docs.rs/tracing-subscriber/0.3.17/tracing_subscriber/fmt/struct.Subscriber.html
|
||||
[`tracing_subscriber::fmt::Layer`]: https://docs.rs/tracing-subscriber/0.3.17/tracing_subscriber/fmt/struct.Layer.html
|
||||
[`Targets`]: https://docs.rs/tracing-subscriber/0.3.17/tracing_subscriber/filter/targets/struct.Targets.html
|
||||
[`EnvFilter`]: https://docs.rs/tracing-subscriber/0.3.17/tracing_subscriber/filter/struct.EnvFilter.html
|
||||
[log-feature]: https://docs.rs/tracing/latest/tracing/#emitting-log-records
|
||||
[GHSA-g98v-hv3f-hcfr]: https://github.com/advisories/GHSA-g98v-hv3f-hcfr
|
||||
[RUSTSEC-2021-0145]: https://rustsec.org/advisories/RUSTSEC-2021-0145.html
|
||||
|
||||
# 0.1.4 (October 23rd, 2023)
|
||||
|
||||
### Changes
|
||||
|
||||
- Deprecated `env_logger` feature in favor of `tracing_subscriber::fmt::Subscriber` ([#2752])
|
||||
|
||||
#[2752]: https://github.com/tokio-rs/tracing/pull/2752
|
||||
|
||||
# 0.1.3 (April 21st, 2022)
|
||||
|
||||
### Added
|
||||
|
||||
- **log-tracer**: Added `LogTracer::with_interest_cache` to enable a limited
|
||||
form of per-record `Interest` caching for `log` records ([#1636])
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated minimum supported Rust version (MSRV) to Rust 1.49.0 ([#1913])
|
||||
|
||||
### Fixed
|
||||
|
||||
- **log-tracer**: Fixed `LogTracer` not honoring `tracing` max level filters
|
||||
([#1543])
|
||||
- Broken links in documentation ([#2068], [#2077])
|
||||
|
||||
Thanks to @Millione, @teozkr, @koute, @Folyd, and @ben0x539 for contributing to
|
||||
this release!
|
||||
|
||||
[#1636]: https://github.com/tokio-rs/tracing/pulls/1636
|
||||
[#1913]: https://github.com/tokio-rs/tracing/pulls/1913
|
||||
[#1543]: https://github.com/tokio-rs/tracing/pulls/1543
|
||||
[#2068]: https://github.com/tokio-rs/tracing/pulls/2068
|
||||
[#2077]: https://github.com/tokio-rs/tracing/pulls/2077
|
||||
|
||||
# 0.1.2 (February 19th, 2020)
|
||||
|
||||
### Added
|
||||
|
||||
- Re-export the `log` crate so that users can ensure consistent versions ([#602])
|
||||
- `AsLog` implementation for `tracing::LevelFilter` ([#1248])
|
||||
- `AsTrace` implementation for `log::LevelFilter` ([#1248])
|
||||
|
||||
### Fixed
|
||||
|
||||
- **log-tracer**: Fixed `Log::enabled` implementation for `LogTracer` not
|
||||
calling `Subscriber::enabled` ([#1254])
|
||||
- **log-tracer**: Fixed `Log::enabled` implementation for `LogTracer` not
|
||||
checking the max level hint ([#1247])
|
||||
- Several documentation fixes ([#483], [#485], [#537], [#595], [#941], [#981])
|
||||
|
||||
[#483]: https://github.com/tokio-rs/tracing/pulls/483
|
||||
[#485]: https://github.com/tokio-rs/tracing/pulls/485
|
||||
[#537]: https://github.com/tokio-rs/tracing/pulls/537
|
||||
[#595]: https://github.com/tokio-rs/tracing/pulls/595
|
||||
[#605]: https://github.com/tokio-rs/tracing/pulls/604
|
||||
[#941]: https://github.com/tokio-rs/tracing/pulls/941
|
||||
[#1247]: https://github.com/tokio-rs/tracing/pulls/1247
|
||||
[#1248]: https://github.com/tokio-rs/tracing/pulls/1248
|
||||
[#1254]: https://github.com/tokio-rs/tracing/pulls/1254
|
||||
|
||||
# 0.1.1 (October 29, 2019)
|
||||
|
||||
### Deprecated
|
||||
|
||||
- `TraceLogger` (use `tracing`'s "log" and "log-always" feature flags instead)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Issues with `log/std` feature flag (#406)
|
||||
- Minor documentation issues (#405, #408)
|
||||
|
||||
# 0.1.0 (September 3, 2019)
|
||||
|
||||
- Initial release
|
||||
83
third-party/vendor/tracing-log/Cargo.toml
vendored
Normal file
83
third-party/vendor/tracing-log/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# 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 = "2018"
|
||||
rust-version = "1.56.0"
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
authors = ["Tokio Contributors <team@tokio.rs>"]
|
||||
description = """
|
||||
Provides compatibility between `tracing` and the `log` crate.
|
||||
"""
|
||||
homepage = "https://tokio.rs"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"logging",
|
||||
"tracing",
|
||||
"log",
|
||||
]
|
||||
categories = [
|
||||
"development-tools::debugging",
|
||||
"asynchronous",
|
||||
]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/tokio-rs/tracing"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docsrs",
|
||||
]
|
||||
|
||||
[[bench]]
|
||||
name = "logging"
|
||||
harness = false
|
||||
|
||||
[dependencies.ahash]
|
||||
version = "0.7.6"
|
||||
optional = true
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4.17"
|
||||
|
||||
[dependencies.lru]
|
||||
version = "0.7.7"
|
||||
optional = true
|
||||
|
||||
[dependencies.once_cell]
|
||||
version = "1.13.0"
|
||||
|
||||
[dependencies.tracing-core]
|
||||
version = "0.1.28"
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.3.6"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.tracing]
|
||||
version = "0.1.35"
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"log-tracer",
|
||||
"std",
|
||||
]
|
||||
interest-cache = [
|
||||
"lru",
|
||||
"ahash",
|
||||
]
|
||||
log-tracer = []
|
||||
std = ["log/std"]
|
||||
|
||||
[badges.maintenance]
|
||||
status = "actively-maintained"
|
||||
25
third-party/vendor/tracing-log/LICENSE
vendored
Normal file
25
third-party/vendor/tracing-log/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2019 Tokio Contributors
|
||||
|
||||
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.
|
||||
83
third-party/vendor/tracing-log/README.md
vendored
Normal file
83
third-party/vendor/tracing-log/README.md
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
![Tracing — Structured, application-level diagnostics][splash]
|
||||
|
||||
[splash]: https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/splash.svg
|
||||
|
||||
# tracing-log
|
||||
|
||||
[`log`] compatibility for [`tracing`].
|
||||
|
||||
[![Crates.io][crates-badge]][crates-url]
|
||||
[![Documentation][docs-badge]][docs-url]
|
||||
[![Documentation (master)][docs-master-badge]][docs-master-url]
|
||||
[![MIT licensed][mit-badge]][mit-url]
|
||||
[![Build Status][actions-badge]][actions-url]
|
||||
[![Discord chat][discord-badge]][discord-url]
|
||||
![maintenance status][maint-badge]
|
||||
|
||||
[Documentation][docs-url] | [Chat (discord)][discord-url]
|
||||
|
||||
|
||||
[crates-badge]: https://img.shields.io/crates/v/tracing-log.svg
|
||||
[crates-url]: https://crates.io/crates/tracing-log
|
||||
[docs-badge]: https://docs.rs/tracing-log/badge.svg
|
||||
[docs-url]: https://docs.rs/tracing-log
|
||||
[docs-master-badge]: https://img.shields.io/badge/docs-master-blue
|
||||
[docs-master-url]: https://tracing-rs.netlify.com/tracing_log
|
||||
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||
[mit-url]: LICENSE
|
||||
[actions-badge]: https://github.com/tokio-rs/tracing/workflows/CI/badge.svg
|
||||
[actions-url]:https://github.com/tokio-rs/tracing/actions?query=workflow%3ACI
|
||||
[discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white
|
||||
[discord-url]: https://discord.gg/EeF3cQw
|
||||
[maint-badge]: https://img.shields.io/badge/maintenance-experimental-blue.svg
|
||||
|
||||
## Overview
|
||||
|
||||
[`tracing`] is a framework for instrumenting Rust programs with context-aware,
|
||||
structured, event-based diagnostic information. This crate provides
|
||||
compatibility layers for using `tracing` alongside the logging facade provided
|
||||
by the [`log`] crate.
|
||||
|
||||
This crate provides:
|
||||
|
||||
- [`AsTrace`] and [`AsLog`] traits for converting between `tracing` and `log` types.
|
||||
- [`LogTracer`], a [`log::Log`] implementation that consumes [`log::Record`]s
|
||||
and outputs them as [`tracing::Event`]s.
|
||||
|
||||
[`tracing`]: https://crates.io/crates/tracing
|
||||
[`log`]: https://crates.io/crates/log
|
||||
[`AsTrace`]: https://docs.rs/tracing-log/latest/tracing_log/trait.AsTrace.html
|
||||
[`AsLog`]: https://docs.rs/tracing-log/latest/tracing_log/trait.AsLog.html
|
||||
[`LogTracer`]: https://docs.rs/tracing-log/latest/tracing_log/struct.LogTracer.html
|
||||
[`log::Log`]: https://docs.rs/log/latest/log/trait.Log.html
|
||||
[`log::Record`]: https://docs.rs/log/latest/log/struct.Record.html
|
||||
[`tracing::Subscriber`]: https://docs.rs/tracing/latest/tracing/trait.Subscriber.html
|
||||
[`tracing::Event`]: https://docs.rs/tracing/latest/tracing/struct.Event.html
|
||||
|
||||
*Compiler support: [requires `rustc` 1.56+][msrv]*
|
||||
|
||||
[msrv]: #supported-rust-versions
|
||||
|
||||
## Supported Rust Versions
|
||||
|
||||
Tracing is built against the latest stable release. The minimum supported
|
||||
version is 1.56. The current Tracing version is not guaranteed to build on Rust
|
||||
versions earlier than the minimum supported version.
|
||||
|
||||
Tracing follows the same compiler support policies as the rest of the Tokio
|
||||
project. The current stable Rust compiler and the three most recent minor
|
||||
versions before it will always be supported. For example, if the current stable
|
||||
compiler version is 1.69, the minimum supported version will not be increased
|
||||
past 1.66, three minor versions prior. Increasing the minimum supported compiler
|
||||
version is not considered a semver breaking change as long as doing so complies
|
||||
with this policy.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [MIT license](LICENSE).
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in Tracing by you, shall be licensed as MIT, without any additional
|
||||
terms or conditions.
|
||||
91
third-party/vendor/tracing-log/benches/logging.rs
vendored
Normal file
91
third-party/vendor/tracing-log/benches/logging.rs
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use log::trace;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use tracing_subscriber::{EnvFilter, FmtSubscriber};
|
||||
|
||||
// This creates a bunch of threads and makes sure they start executing
|
||||
// a given callback almost exactly at the same time.
|
||||
fn run_on_many_threads<F, R>(thread_count: usize, callback: F) -> Vec<R>
|
||||
where
|
||||
F: Fn() -> R + 'static + Send + Clone,
|
||||
R: Send + 'static,
|
||||
{
|
||||
let started_count = Arc::new(AtomicUsize::new(0));
|
||||
let barrier = Arc::new(AtomicBool::new(false));
|
||||
#[allow(clippy::needless_collect)]
|
||||
let threads: Vec<_> = (0..thread_count)
|
||||
.map(|_| {
|
||||
let started_count = started_count.clone();
|
||||
let barrier = barrier.clone();
|
||||
let callback = callback.clone();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
started_count.fetch_add(1, Ordering::SeqCst);
|
||||
while !barrier.load(Ordering::SeqCst) {
|
||||
std::thread::yield_now();
|
||||
}
|
||||
|
||||
callback()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
while started_count.load(Ordering::SeqCst) != thread_count {
|
||||
std::thread::yield_now();
|
||||
}
|
||||
barrier.store(true, Ordering::SeqCst);
|
||||
|
||||
threads
|
||||
.into_iter()
|
||||
.map(|handle| handle.join())
|
||||
.collect::<Result<Vec<R>, _>>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn bench_logger(c: &mut Criterion) {
|
||||
let env_filter = EnvFilter::default()
|
||||
.add_directive("info".parse().unwrap())
|
||||
.add_directive("ws=off".parse().unwrap())
|
||||
.add_directive("yamux=off".parse().unwrap())
|
||||
.add_directive("regalloc=off".parse().unwrap())
|
||||
.add_directive("cranelift_codegen=off".parse().unwrap())
|
||||
.add_directive("cranelift_wasm=warn".parse().unwrap())
|
||||
.add_directive("hyper=warn".parse().unwrap())
|
||||
.add_directive("dummy=trace".parse().unwrap());
|
||||
|
||||
let builder = tracing_log::LogTracer::builder().with_max_level(log::LevelFilter::Trace);
|
||||
|
||||
#[cfg(feature = "interest-cache")]
|
||||
let builder = builder.with_interest_cache(tracing_log::InterestCacheConfig::default());
|
||||
|
||||
builder.init().unwrap();
|
||||
|
||||
let builder = FmtSubscriber::builder()
|
||||
.with_env_filter(env_filter)
|
||||
.with_filter_reloading();
|
||||
|
||||
let subscriber = builder.finish();
|
||||
tracing::subscriber::set_global_default(subscriber).unwrap();
|
||||
|
||||
const THREAD_COUNT: usize = 8;
|
||||
|
||||
c.bench_function("log_from_multiple_threads", |b| {
|
||||
b.iter_custom(|count| {
|
||||
let durations = run_on_many_threads(THREAD_COUNT, move || {
|
||||
let start = Instant::now();
|
||||
for _ in 0..count {
|
||||
trace!("A dummy log!");
|
||||
}
|
||||
start.elapsed()
|
||||
});
|
||||
|
||||
let total_time: Duration = durations.into_iter().sum();
|
||||
Duration::from_nanos((total_time.as_nanos() / THREAD_COUNT as u128) as u64)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_logger);
|
||||
criterion_main!(benches);
|
||||
538
third-party/vendor/tracing-log/src/interest_cache.rs
vendored
Normal file
538
third-party/vendor/tracing-log/src/interest_cache.rs
vendored
Normal file
|
|
@ -0,0 +1,538 @@
|
|||
use ahash::AHasher;
|
||||
use log::{Level, Metadata};
|
||||
use lru::LruCache;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::cell::RefCell;
|
||||
use std::hash::Hasher;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// The interest cache configuration.
|
||||
#[derive(Debug)]
|
||||
pub struct InterestCacheConfig {
|
||||
min_verbosity: Level,
|
||||
lru_cache_size: usize,
|
||||
}
|
||||
|
||||
impl Default for InterestCacheConfig {
|
||||
fn default() -> Self {
|
||||
InterestCacheConfig {
|
||||
min_verbosity: Level::Debug,
|
||||
lru_cache_size: 1024,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InterestCacheConfig {
|
||||
fn disabled() -> Self {
|
||||
Self {
|
||||
lru_cache_size: 0,
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InterestCacheConfig {
|
||||
/// Sets the minimum logging verbosity for which the cache will apply.
|
||||
///
|
||||
/// The interest for logs with a lower verbosity than specified here
|
||||
/// will not be cached.
|
||||
///
|
||||
/// It should be set to the lowest verbosity level for which the majority
|
||||
/// of the logs in your application are usually *disabled*.
|
||||
///
|
||||
/// In normal circumstances with typical logger usage patterns
|
||||
/// you shouldn't ever have to change this.
|
||||
///
|
||||
/// By default this is set to `Debug`.
|
||||
pub fn with_min_verbosity(mut self, level: Level) -> Self {
|
||||
self.min_verbosity = level;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the number of entries in the LRU cache used to cache interests
|
||||
/// for `log` records.
|
||||
///
|
||||
/// The bigger the cache, the more unlikely it will be for the interest
|
||||
/// in a given callsite to be recalculated, at the expense of extra
|
||||
/// memory usage per every thread which tries to log events.
|
||||
///
|
||||
/// Every unique [level] + [target] pair consumes a single slot
|
||||
/// in the cache. Entries will be added to the cache until its size
|
||||
/// reaches the value configured here, and from then on it will evict
|
||||
/// the least recently seen level + target pair when adding a new entry.
|
||||
///
|
||||
/// The ideal value to set here widely depends on how much exactly
|
||||
/// you're logging, and how diverse the targets are to which you are logging.
|
||||
///
|
||||
/// If your application spends a significant amount of time filtering logs
|
||||
/// which are *not* getting printed out then increasing this value will most
|
||||
/// likely help.
|
||||
///
|
||||
/// Setting this to zero will disable the cache.
|
||||
///
|
||||
/// By default this is set to 1024.
|
||||
///
|
||||
/// [level]: log::Metadata::level
|
||||
/// [target]: log::Metadata::target
|
||||
pub fn with_lru_cache_size(mut self, size: usize) -> Self {
|
||||
self.lru_cache_size = size;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct Key {
|
||||
target_address: usize,
|
||||
level_and_length: usize,
|
||||
}
|
||||
|
||||
struct State {
|
||||
min_verbosity: Level,
|
||||
epoch: usize,
|
||||
cache: LruCache<Key, u64, ahash::RandomState>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn new(epoch: usize, config: &InterestCacheConfig) -> Self {
|
||||
State {
|
||||
epoch,
|
||||
min_verbosity: config.min_verbosity,
|
||||
cache: LruCache::new(config.lru_cache_size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When the logger's filters are reconfigured the interest cache in core is cleared,
|
||||
// and we also want to get notified when that happens so that we can clear our cache too.
|
||||
//
|
||||
// So what we do here is to register a dummy callsite with the core, just so that we can be
|
||||
// notified when that happens. It doesn't really matter how exactly our dummy callsite looks
|
||||
// like and whether subscribers will actually be interested in it, since nothing will actually
|
||||
// be logged from it.
|
||||
|
||||
static INTEREST_CACHE_EPOCH: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
fn interest_cache_epoch() -> usize {
|
||||
INTEREST_CACHE_EPOCH.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
struct SentinelCallsite;
|
||||
|
||||
impl tracing_core::Callsite for SentinelCallsite {
|
||||
fn set_interest(&self, _: tracing_core::subscriber::Interest) {
|
||||
INTEREST_CACHE_EPOCH.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
fn metadata(&self) -> &tracing_core::Metadata<'_> {
|
||||
&SENTINEL_METADATA
|
||||
}
|
||||
}
|
||||
|
||||
static SENTINEL_CALLSITE: SentinelCallsite = SentinelCallsite;
|
||||
static SENTINEL_METADATA: tracing_core::Metadata<'static> = tracing_core::Metadata::new(
|
||||
"log interest cache",
|
||||
"log",
|
||||
tracing_core::Level::ERROR,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
tracing_core::field::FieldSet::new(&[], tracing_core::identify_callsite!(&SENTINEL_CALLSITE)),
|
||||
tracing_core::metadata::Kind::EVENT,
|
||||
);
|
||||
|
||||
static CONFIG: Lazy<Mutex<InterestCacheConfig>> = Lazy::new(|| {
|
||||
tracing_core::callsite::register(&SENTINEL_CALLSITE);
|
||||
Mutex::new(InterestCacheConfig::disabled())
|
||||
});
|
||||
|
||||
thread_local! {
|
||||
static STATE: RefCell<State> = {
|
||||
let config = CONFIG.lock().unwrap();
|
||||
RefCell::new(State::new(interest_cache_epoch(), &config))
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn configure(new_config: Option<InterestCacheConfig>) {
|
||||
*CONFIG.lock().unwrap() = new_config.unwrap_or_else(InterestCacheConfig::disabled);
|
||||
INTEREST_CACHE_EPOCH.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
pub(crate) fn try_cache(metadata: &Metadata<'_>, callback: impl FnOnce() -> bool) -> bool {
|
||||
STATE.with(|state| {
|
||||
let mut state = state.borrow_mut();
|
||||
|
||||
// If the interest cache in core was rebuilt we need to reset the cache here too.
|
||||
let epoch = interest_cache_epoch();
|
||||
if epoch != state.epoch {
|
||||
*state = State::new(epoch, &CONFIG.lock().unwrap());
|
||||
}
|
||||
|
||||
let level = metadata.level();
|
||||
if state.cache.cap() == 0 || level < state.min_verbosity {
|
||||
return callback();
|
||||
}
|
||||
|
||||
let target = metadata.target();
|
||||
|
||||
let mut hasher = AHasher::default();
|
||||
hasher.write(target.as_bytes());
|
||||
|
||||
const HASH_MASK: u64 = !1;
|
||||
const INTEREST_MASK: u64 = 1;
|
||||
|
||||
// We mask out the least significant bit of the hash since we'll use
|
||||
// that space to save the interest.
|
||||
//
|
||||
// Since we use a good hashing function the loss of only a single bit
|
||||
// won't really affect us negatively.
|
||||
let target_hash = hasher.finish() & HASH_MASK;
|
||||
|
||||
// Since log targets are usually static strings we just use the address of the pointer
|
||||
// as the key for our cache.
|
||||
//
|
||||
// We want each level to be cached separately so we also use the level as key, and since
|
||||
// some linkers at certain optimization levels deduplicate strings if their prefix matches
|
||||
// (e.g. "ham" and "hamster" might actually have the same address in memory) we also use the length.
|
||||
let key = Key {
|
||||
target_address: target.as_ptr() as usize,
|
||||
// For extra efficiency we pack both the level and the length into a single field.
|
||||
// The `level` can be between 1 and 5, so it can take at most 3 bits of space.
|
||||
level_and_length: level as usize | target.len().wrapping_shl(3),
|
||||
};
|
||||
|
||||
if let Some(&cached) = state.cache.get(&key) {
|
||||
// And here we make sure that the target actually matches.
|
||||
//
|
||||
// This is just a hash of the target string, so theoretically we're not guaranteed
|
||||
// that it won't collide, however in practice it shouldn't matter as it is quite
|
||||
// unlikely that the target string's address and its length and the level and
|
||||
// the hash will *all* be equal at the same time.
|
||||
//
|
||||
// We could of course actually store the whole target string in our cache,
|
||||
// but we really want to avoid doing that as the necessary memory allocations
|
||||
// would completely tank our performance, especially in cases where the cache's
|
||||
// size is too small so it needs to regularly replace entries.
|
||||
if cached & HASH_MASK == target_hash {
|
||||
return (cached & INTEREST_MASK) != 0;
|
||||
}
|
||||
|
||||
// Realistically we should never land here, unless someone is using a non-static
|
||||
// target string with the same length and level, or is very lucky and found a hash
|
||||
// collision for the cache's key.
|
||||
}
|
||||
|
||||
let interest = callback();
|
||||
state.cache.put(key, target_hash | interest as u64);
|
||||
|
||||
interest
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn lock_for_test() -> impl Drop {
|
||||
// We need to make sure only one test runs at a time.
|
||||
static LOCK: Lazy<Mutex<()>> = Lazy::new(Mutex::new);
|
||||
|
||||
match LOCK.lock() {
|
||||
Ok(guard) => guard,
|
||||
Err(poison) => poison.into_inner(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_when_disabled_the_callback_is_always_called() {
|
||||
let _lock = lock_for_test();
|
||||
|
||||
*CONFIG.lock().unwrap() = InterestCacheConfig::disabled();
|
||||
|
||||
std::thread::spawn(|| {
|
||||
let metadata = log::MetadataBuilder::new()
|
||||
.level(Level::Trace)
|
||||
.target("dummy")
|
||||
.build();
|
||||
let mut count = 0;
|
||||
try_cache(&metadata, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count, 1);
|
||||
try_cache(&metadata, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count, 2);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_when_enabled_the_callback_is_called_only_once_for_a_high_enough_verbosity() {
|
||||
let _lock = lock_for_test();
|
||||
|
||||
*CONFIG.lock().unwrap() = InterestCacheConfig::default().with_min_verbosity(Level::Debug);
|
||||
|
||||
std::thread::spawn(|| {
|
||||
let metadata = log::MetadataBuilder::new()
|
||||
.level(Level::Debug)
|
||||
.target("dummy")
|
||||
.build();
|
||||
let mut count = 0;
|
||||
try_cache(&metadata, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count, 1);
|
||||
try_cache(&metadata, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count, 1);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_when_core_interest_cache_is_rebuilt_this_cache_is_also_flushed() {
|
||||
let _lock = lock_for_test();
|
||||
|
||||
*CONFIG.lock().unwrap() = InterestCacheConfig::default().with_min_verbosity(Level::Debug);
|
||||
|
||||
std::thread::spawn(|| {
|
||||
let metadata = log::MetadataBuilder::new()
|
||||
.level(Level::Debug)
|
||||
.target("dummy")
|
||||
.build();
|
||||
{
|
||||
let mut count = 0;
|
||||
try_cache(&metadata, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
try_cache(&metadata, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count, 1);
|
||||
}
|
||||
tracing_core::callsite::rebuild_interest_cache();
|
||||
{
|
||||
let mut count = 0;
|
||||
try_cache(&metadata, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
try_cache(&metadata, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count, 1);
|
||||
}
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_when_enabled_the_callback_is_always_called_for_a_low_enough_verbosity() {
|
||||
let _lock = lock_for_test();
|
||||
|
||||
*CONFIG.lock().unwrap() = InterestCacheConfig::default().with_min_verbosity(Level::Debug);
|
||||
|
||||
std::thread::spawn(|| {
|
||||
let metadata = log::MetadataBuilder::new()
|
||||
.level(Level::Info)
|
||||
.target("dummy")
|
||||
.build();
|
||||
let mut count = 0;
|
||||
try_cache(&metadata, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count, 1);
|
||||
try_cache(&metadata, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count, 2);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_different_log_levels_are_cached_separately() {
|
||||
let _lock = lock_for_test();
|
||||
|
||||
*CONFIG.lock().unwrap() = InterestCacheConfig::default().with_min_verbosity(Level::Debug);
|
||||
|
||||
std::thread::spawn(|| {
|
||||
let metadata_debug = log::MetadataBuilder::new()
|
||||
.level(Level::Debug)
|
||||
.target("dummy")
|
||||
.build();
|
||||
let metadata_trace = log::MetadataBuilder::new()
|
||||
.level(Level::Trace)
|
||||
.target("dummy")
|
||||
.build();
|
||||
let mut count_debug = 0;
|
||||
let mut count_trace = 0;
|
||||
try_cache(&metadata_debug, || {
|
||||
count_debug += 1;
|
||||
true
|
||||
});
|
||||
try_cache(&metadata_trace, || {
|
||||
count_trace += 1;
|
||||
true
|
||||
});
|
||||
try_cache(&metadata_debug, || {
|
||||
count_debug += 1;
|
||||
true
|
||||
});
|
||||
try_cache(&metadata_trace, || {
|
||||
count_trace += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count_debug, 1);
|
||||
assert_eq!(count_trace, 1);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_different_log_targets_are_cached_separately() {
|
||||
let _lock = lock_for_test();
|
||||
|
||||
*CONFIG.lock().unwrap() = InterestCacheConfig::default().with_min_verbosity(Level::Debug);
|
||||
|
||||
std::thread::spawn(|| {
|
||||
let metadata_1 = log::MetadataBuilder::new()
|
||||
.level(Level::Trace)
|
||||
.target("dummy_1")
|
||||
.build();
|
||||
let metadata_2 = log::MetadataBuilder::new()
|
||||
.level(Level::Trace)
|
||||
.target("dummy_2")
|
||||
.build();
|
||||
let mut count_1 = 0;
|
||||
let mut count_2 = 0;
|
||||
try_cache(&metadata_1, || {
|
||||
count_1 += 1;
|
||||
true
|
||||
});
|
||||
try_cache(&metadata_2, || {
|
||||
count_2 += 1;
|
||||
true
|
||||
});
|
||||
try_cache(&metadata_1, || {
|
||||
count_1 += 1;
|
||||
true
|
||||
});
|
||||
try_cache(&metadata_2, || {
|
||||
count_2 += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count_1, 1);
|
||||
assert_eq!(count_2, 1);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_when_cache_runs_out_of_space_the_callback_is_called_again() {
|
||||
let _lock = lock_for_test();
|
||||
|
||||
*CONFIG.lock().unwrap() = InterestCacheConfig::default()
|
||||
.with_min_verbosity(Level::Debug)
|
||||
.with_lru_cache_size(1);
|
||||
|
||||
std::thread::spawn(|| {
|
||||
let metadata_1 = log::MetadataBuilder::new()
|
||||
.level(Level::Trace)
|
||||
.target("dummy_1")
|
||||
.build();
|
||||
let metadata_2 = log::MetadataBuilder::new()
|
||||
.level(Level::Trace)
|
||||
.target("dummy_2")
|
||||
.build();
|
||||
let mut count = 0;
|
||||
try_cache(&metadata_1, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
try_cache(&metadata_1, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count, 1);
|
||||
try_cache(&metadata_2, || true);
|
||||
try_cache(&metadata_1, || {
|
||||
count += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(count, 2);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cache_returns_previously_computed_value() {
|
||||
let _lock = lock_for_test();
|
||||
|
||||
*CONFIG.lock().unwrap() = InterestCacheConfig::default().with_min_verbosity(Level::Debug);
|
||||
|
||||
std::thread::spawn(|| {
|
||||
let metadata_1 = log::MetadataBuilder::new()
|
||||
.level(Level::Trace)
|
||||
.target("dummy_1")
|
||||
.build();
|
||||
let metadata_2 = log::MetadataBuilder::new()
|
||||
.level(Level::Trace)
|
||||
.target("dummy_2")
|
||||
.build();
|
||||
try_cache(&metadata_1, || true);
|
||||
assert_eq!(try_cache(&metadata_1, || { unreachable!() }), true);
|
||||
try_cache(&metadata_2, || false);
|
||||
assert_eq!(try_cache(&metadata_2, || { unreachable!() }), false);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cache_handles_non_static_target_string() {
|
||||
let _lock = lock_for_test();
|
||||
|
||||
*CONFIG.lock().unwrap() = InterestCacheConfig::default().with_min_verbosity(Level::Debug);
|
||||
|
||||
std::thread::spawn(|| {
|
||||
let mut target = *b"dummy_1";
|
||||
let metadata_1 = log::MetadataBuilder::new()
|
||||
.level(Level::Trace)
|
||||
.target(std::str::from_utf8(&target).unwrap())
|
||||
.build();
|
||||
|
||||
try_cache(&metadata_1, || true);
|
||||
assert_eq!(try_cache(&metadata_1, || { unreachable!() }), true);
|
||||
|
||||
*target.last_mut().unwrap() = b'2';
|
||||
let metadata_2 = log::MetadataBuilder::new()
|
||||
.level(Level::Trace)
|
||||
.target(std::str::from_utf8(&target).unwrap())
|
||||
.build();
|
||||
|
||||
try_cache(&metadata_2, || false);
|
||||
assert_eq!(try_cache(&metadata_2, || { unreachable!() }), false);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
600
third-party/vendor/tracing-log/src/lib.rs
vendored
Normal file
600
third-party/vendor/tracing-log/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,600 @@
|
|||
//! Adapters for connecting unstructured log records from the `log` crate into
|
||||
//! the `tracing` ecosystem.
|
||||
//!
|
||||
//! # Overview
|
||||
//!
|
||||
//! [`tracing`] is a framework for instrumenting Rust programs with context-aware,
|
||||
//! structured, event-based diagnostic information. This crate provides
|
||||
//! compatibility layers for using `tracing` alongside the logging facade provided
|
||||
//! by the [`log`] crate.
|
||||
//!
|
||||
//! This crate provides:
|
||||
//!
|
||||
//! - [`AsTrace`] and [`AsLog`] traits for converting between `tracing` and `log` types.
|
||||
//! - [`LogTracer`], a [`log::Log`] implementation that consumes [`log::Record`]s
|
||||
//! and outputs them as [`tracing::Event`].
|
||||
//!
|
||||
//! *Compiler support: [requires `rustc` 1.56+][msrv]*
|
||||
//!
|
||||
//! [msrv]: #supported-rust-versions
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! ## Convert log records to tracing `Event`s
|
||||
//!
|
||||
//! To convert [`log::Record`]s as [`tracing::Event`]s, set `LogTracer` as the default
|
||||
//! logger by calling its [`init`] or [`init_with_filter`] methods.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use std::error::Error;
|
||||
//! use tracing_log::LogTracer;
|
||||
//! use log;
|
||||
//!
|
||||
//! # fn main() -> Result<(), Box<Error>> {
|
||||
//! LogTracer::init()?;
|
||||
//!
|
||||
//! // will be available for Subscribers as a tracing Event
|
||||
//! log::trace!("an example trace log");
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! This conversion does not convert unstructured data in log records (such as
|
||||
//! values passed as format arguments to the `log!` macro) to structured
|
||||
//! `tracing` fields. However, it *does* attach these new events to to the
|
||||
//! span that was currently executing when the record was logged. This is the
|
||||
//! primary use-case for this library: making it possible to locate the log
|
||||
//! records emitted by dependencies which use `log` within the context of a
|
||||
//! trace.
|
||||
//!
|
||||
//! ## Convert tracing `Event`s to logs
|
||||
//!
|
||||
//! Enabling the ["log" and "log-always" feature flags][flags] on the `tracing`
|
||||
//! crate will cause all `tracing` spans and events to emit `log::Record`s as
|
||||
//! they occur.
|
||||
//!
|
||||
//! ## Caution: Mixing both conversions
|
||||
//!
|
||||
//! Note that `log::Logger` implementations that convert log records to trace events
|
||||
//! should not be used with `Subscriber`s that convert trace events _back_ into
|
||||
//! `log` records, as doing so will result in the event recursing between the subscriber
|
||||
//! and the logger forever (or, in real life, probably overflowing the call stack).
|
||||
//!
|
||||
//! If the logging of trace events generated from log records produced by the
|
||||
//! `log` crate is desired, either the `log` crate should not be used to
|
||||
//! implement this logging, or an additional layer of filtering will be
|
||||
//! required to avoid infinitely converting between `Event` and `log::Record`.
|
||||
//!
|
||||
//! ## Feature Flags
|
||||
//!
|
||||
//! * `std`: enables features that require the Rust standard library (on by default)
|
||||
//! * `log-tracer`: enables the `LogTracer` type (on by default)
|
||||
//! * `interest-cache`: makes it possible to configure an interest cache for
|
||||
//! logs emitted through the `log` crate (see [`Builder::with_interest_cache`]); requires `std`
|
||||
//!
|
||||
//! ## Supported Rust Versions
|
||||
//!
|
||||
//! Tracing is built against the latest stable release. The minimum supported
|
||||
//! version is 1.56. The current Tracing version is not guaranteed to build on
|
||||
//! Rust versions earlier than the minimum supported version.
|
||||
//!
|
||||
//! Tracing follows the same compiler support policies as the rest of the Tokio
|
||||
//! project. The current stable Rust compiler and the three most recent minor
|
||||
//! versions before it will always be supported. For example, if the current
|
||||
//! stable compiler version is 1.69, the minimum supported version will not be
|
||||
//! increased past 1.66, three minor versions prior. Increasing the minimum
|
||||
//! supported compiler version is not considered a semver breaking change as
|
||||
//! long as doing so complies with this policy.
|
||||
//!
|
||||
//! [`init`]: LogTracer::init
|
||||
//! [`init_with_filter`]: LogTracer::init_with_filter
|
||||
//! [`tracing`]: https://crates.io/crates/tracing
|
||||
//! [`tracing::Subscriber`]: https://docs.rs/tracing/latest/tracing/trait.Subscriber.html
|
||||
//! [`Subscriber`]: https://docs.rs/tracing/latest/tracing/trait.Subscriber.html
|
||||
//! [`tracing::Event`]: https://docs.rs/tracing/latest/tracing/struct.Event.html
|
||||
//! [flags]: https://docs.rs/tracing/latest/tracing/#crate-feature-flags
|
||||
//! [`Builder::with_interest_cache`]: log_tracer::Builder::with_interest_cache
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
|
||||
issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
|
||||
#![warn(
|
||||
missing_debug_implementations,
|
||||
missing_docs,
|
||||
rust_2018_idioms,
|
||||
unreachable_pub,
|
||||
bad_style,
|
||||
dead_code,
|
||||
improper_ctypes,
|
||||
non_shorthand_field_patterns,
|
||||
no_mangle_generic_items,
|
||||
overflowing_literals,
|
||||
path_statements,
|
||||
patterns_in_fns_without_body,
|
||||
private_in_public,
|
||||
unconditional_recursion,
|
||||
unused,
|
||||
unused_allocation,
|
||||
unused_comparisons,
|
||||
unused_parens,
|
||||
while_true
|
||||
)]
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use std::{fmt, io};
|
||||
|
||||
use tracing_core::{
|
||||
callsite::{self, Callsite},
|
||||
dispatcher,
|
||||
field::{self, Field, Visit},
|
||||
identify_callsite,
|
||||
metadata::{Kind, Level},
|
||||
subscriber, Event, Metadata,
|
||||
};
|
||||
|
||||
#[cfg(feature = "log-tracer")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "log-tracer")))]
|
||||
pub mod log_tracer;
|
||||
|
||||
#[cfg(feature = "log-tracer")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "log-tracer")))]
|
||||
#[doc(inline)]
|
||||
pub use self::log_tracer::LogTracer;
|
||||
|
||||
pub use log;
|
||||
|
||||
#[cfg(all(feature = "interest-cache", feature = "log-tracer", feature = "std"))]
|
||||
mod interest_cache;
|
||||
|
||||
#[cfg(all(feature = "interest-cache", feature = "log-tracer", feature = "std"))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(all(feature = "interest-cache", feature = "log-tracer", feature = "std")))
|
||||
)]
|
||||
pub use crate::interest_cache::InterestCacheConfig;
|
||||
|
||||
/// Format a log record as a trace event in the current span.
|
||||
pub fn format_trace(record: &log::Record<'_>) -> io::Result<()> {
|
||||
dispatch_record(record);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// XXX(eliza): this is factored out so that we don't have to deal with the pub
|
||||
// function `format_trace`'s `Result` return type...maybe we should get rid of
|
||||
// that in 0.2...
|
||||
pub(crate) fn dispatch_record(record: &log::Record<'_>) {
|
||||
dispatcher::get_default(|dispatch| {
|
||||
let filter_meta = record.as_trace();
|
||||
if !dispatch.enabled(&filter_meta) {
|
||||
return;
|
||||
}
|
||||
|
||||
let (_, keys, meta) = loglevel_to_cs(record.level());
|
||||
|
||||
let log_module = record.module_path();
|
||||
let log_file = record.file();
|
||||
let log_line = record.line();
|
||||
|
||||
let module = log_module.as_ref().map(|s| s as &dyn field::Value);
|
||||
let file = log_file.as_ref().map(|s| s as &dyn field::Value);
|
||||
let line = log_line.as_ref().map(|s| s as &dyn field::Value);
|
||||
|
||||
dispatch.event(&Event::new(
|
||||
meta,
|
||||
&meta.fields().value_set(&[
|
||||
(&keys.message, Some(record.args() as &dyn field::Value)),
|
||||
(&keys.target, Some(&record.target())),
|
||||
(&keys.module, module),
|
||||
(&keys.file, file),
|
||||
(&keys.line, line),
|
||||
]),
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/// Trait implemented for `tracing` types that can be converted to a `log`
|
||||
/// equivalent.
|
||||
pub trait AsLog: crate::sealed::Sealed {
|
||||
/// The `log` type that this type can be converted into.
|
||||
type Log;
|
||||
/// Returns the `log` equivalent of `self`.
|
||||
fn as_log(&self) -> Self::Log;
|
||||
}
|
||||
|
||||
/// Trait implemented for `log` types that can be converted to a `tracing`
|
||||
/// equivalent.
|
||||
pub trait AsTrace: crate::sealed::Sealed {
|
||||
/// The `tracing` type that this type can be converted into.
|
||||
type Trace;
|
||||
/// Returns the `tracing` equivalent of `self`.
|
||||
fn as_trace(&self) -> Self::Trace;
|
||||
}
|
||||
|
||||
impl<'a> crate::sealed::Sealed for Metadata<'a> {}
|
||||
|
||||
impl<'a> AsLog for Metadata<'a> {
|
||||
type Log = log::Metadata<'a>;
|
||||
fn as_log(&self) -> Self::Log {
|
||||
log::Metadata::builder()
|
||||
.level(self.level().as_log())
|
||||
.target(self.target())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
impl<'a> crate::sealed::Sealed for log::Metadata<'a> {}
|
||||
|
||||
impl<'a> AsTrace for log::Metadata<'a> {
|
||||
type Trace = Metadata<'a>;
|
||||
fn as_trace(&self) -> Self::Trace {
|
||||
let cs_id = identify_callsite!(loglevel_to_cs(self.level()).0);
|
||||
Metadata::new(
|
||||
"log record",
|
||||
self.target(),
|
||||
self.level().as_trace(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
field::FieldSet::new(FIELD_NAMES, cs_id),
|
||||
Kind::EVENT,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct Fields {
|
||||
message: field::Field,
|
||||
target: field::Field,
|
||||
module: field::Field,
|
||||
file: field::Field,
|
||||
line: field::Field,
|
||||
}
|
||||
|
||||
static FIELD_NAMES: &[&str] = &[
|
||||
"message",
|
||||
"log.target",
|
||||
"log.module_path",
|
||||
"log.file",
|
||||
"log.line",
|
||||
];
|
||||
|
||||
impl Fields {
|
||||
fn new(cs: &'static dyn Callsite) -> Self {
|
||||
let fieldset = cs.metadata().fields();
|
||||
let message = fieldset.field("message").unwrap();
|
||||
let target = fieldset.field("log.target").unwrap();
|
||||
let module = fieldset.field("log.module_path").unwrap();
|
||||
let file = fieldset.field("log.file").unwrap();
|
||||
let line = fieldset.field("log.line").unwrap();
|
||||
Fields {
|
||||
message,
|
||||
target,
|
||||
module,
|
||||
file,
|
||||
line,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! log_cs {
|
||||
($level:expr, $cs:ident, $meta:ident, $ty:ident) => {
|
||||
struct $ty;
|
||||
static $cs: $ty = $ty;
|
||||
static $meta: Metadata<'static> = Metadata::new(
|
||||
"log event",
|
||||
"log",
|
||||
$level,
|
||||
::core::option::Option::None,
|
||||
::core::option::Option::None,
|
||||
::core::option::Option::None,
|
||||
field::FieldSet::new(FIELD_NAMES, identify_callsite!(&$cs)),
|
||||
Kind::EVENT,
|
||||
);
|
||||
|
||||
impl callsite::Callsite for $ty {
|
||||
fn set_interest(&self, _: subscriber::Interest) {}
|
||||
fn metadata(&self) -> &'static Metadata<'static> {
|
||||
&$meta
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
log_cs!(
|
||||
tracing_core::Level::TRACE,
|
||||
TRACE_CS,
|
||||
TRACE_META,
|
||||
TraceCallsite
|
||||
);
|
||||
log_cs!(
|
||||
tracing_core::Level::DEBUG,
|
||||
DEBUG_CS,
|
||||
DEBUG_META,
|
||||
DebugCallsite
|
||||
);
|
||||
log_cs!(tracing_core::Level::INFO, INFO_CS, INFO_META, InfoCallsite);
|
||||
log_cs!(tracing_core::Level::WARN, WARN_CS, WARN_META, WarnCallsite);
|
||||
log_cs!(
|
||||
tracing_core::Level::ERROR,
|
||||
ERROR_CS,
|
||||
ERROR_META,
|
||||
ErrorCallsite
|
||||
);
|
||||
|
||||
static TRACE_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&TRACE_CS));
|
||||
static DEBUG_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&DEBUG_CS));
|
||||
static INFO_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&INFO_CS));
|
||||
static WARN_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&WARN_CS));
|
||||
static ERROR_FIELDS: Lazy<Fields> = Lazy::new(|| Fields::new(&ERROR_CS));
|
||||
|
||||
fn level_to_cs(level: Level) -> (&'static dyn Callsite, &'static Fields) {
|
||||
match level {
|
||||
Level::TRACE => (&TRACE_CS, &*TRACE_FIELDS),
|
||||
Level::DEBUG => (&DEBUG_CS, &*DEBUG_FIELDS),
|
||||
Level::INFO => (&INFO_CS, &*INFO_FIELDS),
|
||||
Level::WARN => (&WARN_CS, &*WARN_FIELDS),
|
||||
Level::ERROR => (&ERROR_CS, &*ERROR_FIELDS),
|
||||
}
|
||||
}
|
||||
|
||||
fn loglevel_to_cs(
|
||||
level: log::Level,
|
||||
) -> (
|
||||
&'static dyn Callsite,
|
||||
&'static Fields,
|
||||
&'static Metadata<'static>,
|
||||
) {
|
||||
match level {
|
||||
log::Level::Trace => (&TRACE_CS, &*TRACE_FIELDS, &TRACE_META),
|
||||
log::Level::Debug => (&DEBUG_CS, &*DEBUG_FIELDS, &DEBUG_META),
|
||||
log::Level::Info => (&INFO_CS, &*INFO_FIELDS, &INFO_META),
|
||||
log::Level::Warn => (&WARN_CS, &*WARN_FIELDS, &WARN_META),
|
||||
log::Level::Error => (&ERROR_CS, &*ERROR_FIELDS, &ERROR_META),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::sealed::Sealed for log::Record<'a> {}
|
||||
|
||||
impl<'a> AsTrace for log::Record<'a> {
|
||||
type Trace = Metadata<'a>;
|
||||
fn as_trace(&self) -> Self::Trace {
|
||||
let cs_id = identify_callsite!(loglevel_to_cs(self.level()).0);
|
||||
Metadata::new(
|
||||
"log record",
|
||||
self.target(),
|
||||
self.level().as_trace(),
|
||||
self.file(),
|
||||
self.line(),
|
||||
self.module_path(),
|
||||
field::FieldSet::new(FIELD_NAMES, cs_id),
|
||||
Kind::EVENT,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::sealed::Sealed for tracing_core::Level {}
|
||||
|
||||
impl AsLog for tracing_core::Level {
|
||||
type Log = log::Level;
|
||||
fn as_log(&self) -> log::Level {
|
||||
match *self {
|
||||
tracing_core::Level::ERROR => log::Level::Error,
|
||||
tracing_core::Level::WARN => log::Level::Warn,
|
||||
tracing_core::Level::INFO => log::Level::Info,
|
||||
tracing_core::Level::DEBUG => log::Level::Debug,
|
||||
tracing_core::Level::TRACE => log::Level::Trace,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::sealed::Sealed for log::Level {}
|
||||
|
||||
impl AsTrace for log::Level {
|
||||
type Trace = tracing_core::Level;
|
||||
#[inline]
|
||||
fn as_trace(&self) -> tracing_core::Level {
|
||||
match self {
|
||||
log::Level::Error => tracing_core::Level::ERROR,
|
||||
log::Level::Warn => tracing_core::Level::WARN,
|
||||
log::Level::Info => tracing_core::Level::INFO,
|
||||
log::Level::Debug => tracing_core::Level::DEBUG,
|
||||
log::Level::Trace => tracing_core::Level::TRACE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::sealed::Sealed for log::LevelFilter {}
|
||||
|
||||
impl AsTrace for log::LevelFilter {
|
||||
type Trace = tracing_core::LevelFilter;
|
||||
#[inline]
|
||||
fn as_trace(&self) -> tracing_core::LevelFilter {
|
||||
match self {
|
||||
log::LevelFilter::Off => tracing_core::LevelFilter::OFF,
|
||||
log::LevelFilter::Error => tracing_core::LevelFilter::ERROR,
|
||||
log::LevelFilter::Warn => tracing_core::LevelFilter::WARN,
|
||||
log::LevelFilter::Info => tracing_core::LevelFilter::INFO,
|
||||
log::LevelFilter::Debug => tracing_core::LevelFilter::DEBUG,
|
||||
log::LevelFilter::Trace => tracing_core::LevelFilter::TRACE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::sealed::Sealed for tracing_core::LevelFilter {}
|
||||
|
||||
impl AsLog for tracing_core::LevelFilter {
|
||||
type Log = log::LevelFilter;
|
||||
#[inline]
|
||||
fn as_log(&self) -> Self::Log {
|
||||
match *self {
|
||||
tracing_core::LevelFilter::OFF => log::LevelFilter::Off,
|
||||
tracing_core::LevelFilter::ERROR => log::LevelFilter::Error,
|
||||
tracing_core::LevelFilter::WARN => log::LevelFilter::Warn,
|
||||
tracing_core::LevelFilter::INFO => log::LevelFilter::Info,
|
||||
tracing_core::LevelFilter::DEBUG => log::LevelFilter::Debug,
|
||||
tracing_core::LevelFilter::TRACE => log::LevelFilter::Trace,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Extends log `Event`s to provide complete `Metadata`.
|
||||
///
|
||||
/// In `tracing-log`, an `Event` produced by a log (through [`AsTrace`]) has an hard coded
|
||||
/// "log" target and no `file`, `line`, or `module_path` attributes. This happens because `Event`
|
||||
/// requires its `Metadata` to be `'static`, while [`log::Record`]s provide them with a generic
|
||||
/// lifetime.
|
||||
///
|
||||
/// However, these values are stored in the `Event`'s fields and
|
||||
/// the [`normalized_metadata`] method allows to build a new `Metadata`
|
||||
/// that only lives as long as its source `Event`, but provides complete
|
||||
/// data.
|
||||
///
|
||||
/// It can typically be used by `Subscriber`s when processing an `Event`,
|
||||
/// to allow accessing its complete metadata in a consistent way,
|
||||
/// regardless of the source of its source.
|
||||
///
|
||||
/// [`normalized_metadata`]: NormalizeEvent#normalized_metadata
|
||||
pub trait NormalizeEvent<'a>: crate::sealed::Sealed {
|
||||
/// If this `Event` comes from a `log`, this method provides a new
|
||||
/// normalized `Metadata` which has all available attributes
|
||||
/// from the original log, including `file`, `line`, `module_path`
|
||||
/// and `target`.
|
||||
/// Returns `None` is the `Event` is not issued from a `log`.
|
||||
fn normalized_metadata(&'a self) -> Option<Metadata<'a>>;
|
||||
/// Returns whether this `Event` represents a log (from the `log` crate)
|
||||
fn is_log(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<'a> crate::sealed::Sealed for Event<'a> {}
|
||||
|
||||
impl<'a> NormalizeEvent<'a> for Event<'a> {
|
||||
fn normalized_metadata(&'a self) -> Option<Metadata<'a>> {
|
||||
let original = self.metadata();
|
||||
if self.is_log() {
|
||||
let mut fields = LogVisitor::new_for(self, level_to_cs(*original.level()).1);
|
||||
self.record(&mut fields);
|
||||
|
||||
Some(Metadata::new(
|
||||
"log event",
|
||||
fields.target.unwrap_or("log"),
|
||||
*original.level(),
|
||||
fields.file,
|
||||
fields.line.map(|l| l as u32),
|
||||
fields.module_path,
|
||||
field::FieldSet::new(&["message"], original.callsite()),
|
||||
Kind::EVENT,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn is_log(&self) -> bool {
|
||||
self.metadata().callsite() == identify_callsite!(level_to_cs(*self.metadata().level()).0)
|
||||
}
|
||||
}
|
||||
|
||||
struct LogVisitor<'a> {
|
||||
target: Option<&'a str>,
|
||||
module_path: Option<&'a str>,
|
||||
file: Option<&'a str>,
|
||||
line: Option<u64>,
|
||||
fields: &'static Fields,
|
||||
}
|
||||
|
||||
impl<'a> LogVisitor<'a> {
|
||||
// We don't actually _use_ the provided event argument; it is simply to
|
||||
// ensure that the `LogVisitor` does not outlive the event whose fields it
|
||||
// is visiting, so that the reference casts in `record_str` are safe.
|
||||
fn new_for(_event: &'a Event<'a>, fields: &'static Fields) -> Self {
|
||||
Self {
|
||||
target: None,
|
||||
module_path: None,
|
||||
file: None,
|
||||
line: None,
|
||||
fields,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit for LogVisitor<'a> {
|
||||
fn record_debug(&mut self, _field: &Field, _value: &dyn fmt::Debug) {}
|
||||
|
||||
fn record_u64(&mut self, field: &Field, value: u64) {
|
||||
if field == &self.fields.line {
|
||||
self.line = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
fn record_str(&mut self, field: &Field, value: &str) {
|
||||
unsafe {
|
||||
// The `Visit` API erases the string slice's lifetime. However, we
|
||||
// know it is part of the `Event` struct with a lifetime of `'a`. If
|
||||
// (and only if!) this `LogVisitor` was constructed with the same
|
||||
// lifetime parameter `'a` as the event in question, it's safe to
|
||||
// cast these string slices to the `'a` lifetime.
|
||||
if field == &self.fields.file {
|
||||
self.file = Some(&*(value as *const _));
|
||||
} else if field == &self.fields.target {
|
||||
self.target = Some(&*(value as *const _));
|
||||
} else if field == &self.fields.module {
|
||||
self.module_path = Some(&*(value as *const _));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
fn test_callsite(level: log::Level) {
|
||||
let record = log::Record::builder()
|
||||
.args(format_args!("Error!"))
|
||||
.level(level)
|
||||
.target("myApp")
|
||||
.file(Some("server.rs"))
|
||||
.line(Some(144))
|
||||
.module_path(Some("server"))
|
||||
.build();
|
||||
|
||||
let meta = record.as_trace();
|
||||
let (cs, _keys, _) = loglevel_to_cs(record.level());
|
||||
let cs_meta = cs.metadata();
|
||||
assert_eq!(
|
||||
meta.callsite(),
|
||||
cs_meta.callsite(),
|
||||
"actual: {:#?}\nexpected: {:#?}",
|
||||
meta,
|
||||
cs_meta
|
||||
);
|
||||
assert_eq!(meta.level(), &level.as_trace());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_callsite_is_correct() {
|
||||
test_callsite(log::Level::Error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn warn_callsite_is_correct() {
|
||||
test_callsite(log::Level::Warn);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn info_callsite_is_correct() {
|
||||
test_callsite(log::Level::Info);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debug_callsite_is_correct() {
|
||||
test_callsite(log::Level::Debug);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_callsite_is_correct() {
|
||||
test_callsite(log::Level::Trace);
|
||||
}
|
||||
}
|
||||
307
third-party/vendor/tracing-log/src/log_tracer.rs
vendored
Normal file
307
third-party/vendor/tracing-log/src/log_tracer.rs
vendored
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
//! An adapter for converting [`log`] records into `tracing` `Event`s.
|
||||
//!
|
||||
//! This module provides the [`LogTracer`] type which implements `log`'s [logger
|
||||
//! interface] by recording log records as `tracing` `Event`s. This is intended for
|
||||
//! use in conjunction with a `tracing` `Subscriber` to consume events from
|
||||
//! dependencies that emit [`log`] records within a trace context.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! To create and initialize a `LogTracer` with the default configurations, use:
|
||||
//!
|
||||
//! * [`init`] if you want to convert all logs, regardless of log level,
|
||||
//! allowing the tracing `Subscriber` to perform any filtering
|
||||
//! * [`init_with_filter`] to convert all logs up to a specified log level
|
||||
//!
|
||||
//! In addition, a [builder] is available for cases where more advanced
|
||||
//! configuration is required. In particular, the builder can be used to [ignore
|
||||
//! log records][ignore] emitted by particular crates. This is useful in cases
|
||||
//! such as when a crate emits both `tracing` diagnostics _and_ log records by
|
||||
//! default.
|
||||
//!
|
||||
//! [logger interface]: log::Log
|
||||
//! [`init`]: LogTracer.html#method.init
|
||||
//! [`init_with_filter`]: LogTracer.html#method.init_with_filter
|
||||
//! [builder]: LogTracer::builder()
|
||||
//! [ignore]: Builder::ignore_crate()
|
||||
use crate::AsTrace;
|
||||
pub use log::SetLoggerError;
|
||||
use tracing_core::dispatcher;
|
||||
|
||||
/// A simple "logger" that converts all log records into `tracing` `Event`s.
|
||||
#[derive(Debug)]
|
||||
pub struct LogTracer {
|
||||
ignore_crates: Box<[String]>,
|
||||
}
|
||||
|
||||
/// Configures a new `LogTracer`.
|
||||
#[derive(Debug)]
|
||||
pub struct Builder {
|
||||
ignore_crates: Vec<String>,
|
||||
filter: log::LevelFilter,
|
||||
#[cfg(all(feature = "interest-cache", feature = "std"))]
|
||||
interest_cache_config: Option<crate::InterestCacheConfig>,
|
||||
}
|
||||
|
||||
// ===== impl LogTracer =====
|
||||
|
||||
impl LogTracer {
|
||||
/// Returns a builder that allows customizing a `LogTracer` and setting it
|
||||
/// the default logger.
|
||||
///
|
||||
/// For example:
|
||||
/// ```rust
|
||||
/// # use std::error::Error;
|
||||
/// use tracing_log::LogTracer;
|
||||
/// use log;
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<Error>> {
|
||||
/// LogTracer::builder()
|
||||
/// .ignore_crate("foo") // suppose the `foo` crate is using `tracing`'s log feature
|
||||
/// .with_max_level(log::LevelFilter::Info)
|
||||
/// .init()?;
|
||||
///
|
||||
/// // will be available for Subscribers as a tracing Event
|
||||
/// log::info!("an example info log");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn builder() -> Builder {
|
||||
Builder::default()
|
||||
}
|
||||
|
||||
/// Creates a new `LogTracer` that can then be used as a logger for the `log` crate.
|
||||
///
|
||||
/// It is generally simpler to use the [`init`] or [`init_with_filter`] methods
|
||||
/// which will create the `LogTracer` and set it as the global logger.
|
||||
///
|
||||
/// Logger setup without the initialization methods can be done with:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use std::error::Error;
|
||||
/// use tracing_log::LogTracer;
|
||||
/// use log;
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<Error>> {
|
||||
/// let logger = LogTracer::new();
|
||||
/// log::set_boxed_logger(Box::new(logger))?;
|
||||
/// log::set_max_level(log::LevelFilter::Trace);
|
||||
///
|
||||
/// // will be available for Subscribers as a tracing Event
|
||||
/// log::trace!("an example trace log");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`init`]: LogTracer::init()
|
||||
/// [`init_with_filter`]: .#method.init_with_filter
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
ignore_crates: Vec::new().into_boxed_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up `LogTracer` as global logger for the `log` crate,
|
||||
/// with the given level as max level filter.
|
||||
///
|
||||
/// Setting a global logger can only be done once.
|
||||
///
|
||||
/// The [`builder`] function can be used to customize the `LogTracer` before
|
||||
/// initializing it.
|
||||
///
|
||||
/// [`builder`]: LogTracer::builder()
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
pub fn init_with_filter(level: log::LevelFilter) -> Result<(), SetLoggerError> {
|
||||
Self::builder().with_max_level(level).init()
|
||||
}
|
||||
|
||||
/// Sets a `LogTracer` as the global logger for the `log` crate.
|
||||
///
|
||||
/// Setting a global logger can only be done once.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use std::error::Error;
|
||||
/// use tracing_log::LogTracer;
|
||||
/// use log;
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<Error>> {
|
||||
/// LogTracer::init()?;
|
||||
///
|
||||
/// // will be available for Subscribers as a tracing Event
|
||||
/// log::trace!("an example trace log");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// This will forward all logs to `tracing` and lets the current `Subscriber`
|
||||
/// determine if they are enabled.
|
||||
///
|
||||
/// The [`builder`] function can be used to customize the `LogTracer` before
|
||||
/// initializing it.
|
||||
///
|
||||
/// If you know in advance you want to filter some log levels,
|
||||
/// use [`builder`] or [`init_with_filter`] instead.
|
||||
///
|
||||
/// [`init_with_filter`]: LogTracer::init_with_filter()
|
||||
/// [`builder`]: LogTracer::builder()
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
pub fn init() -> Result<(), SetLoggerError> {
|
||||
Self::builder().init()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LogTracer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "interest-cache", feature = "std"))]
|
||||
use crate::interest_cache::try_cache as try_cache_interest;
|
||||
|
||||
#[cfg(not(all(feature = "interest-cache", feature = "std")))]
|
||||
fn try_cache_interest(_: &log::Metadata<'_>, callback: impl FnOnce() -> bool) -> bool {
|
||||
callback()
|
||||
}
|
||||
|
||||
impl log::Log for LogTracer {
|
||||
fn enabled(&self, metadata: &log::Metadata<'_>) -> bool {
|
||||
// First, check the log record against the current max level enabled by
|
||||
// the current `tracing` subscriber.
|
||||
if metadata.level().as_trace() > tracing_core::LevelFilter::current() {
|
||||
// If the log record's level is above that, disable it.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Okay, it wasn't disabled by the max level — do we have any specific
|
||||
// modules to ignore?
|
||||
if !self.ignore_crates.is_empty() {
|
||||
// If we are ignoring certain module paths, ensure that the metadata
|
||||
// does not start with one of those paths.
|
||||
let target = metadata.target();
|
||||
for ignored in &self.ignore_crates[..] {
|
||||
if target.starts_with(ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try_cache_interest(metadata, || {
|
||||
// Finally, check if the current `tracing` dispatcher cares about this.
|
||||
dispatcher::get_default(|dispatch| dispatch.enabled(&metadata.as_trace()))
|
||||
})
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record<'_>) {
|
||||
if self.enabled(record.metadata()) {
|
||||
crate::dispatch_record(record);
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
// ===== impl Builder =====
|
||||
|
||||
impl Builder {
|
||||
/// Returns a new `Builder` to construct a [`LogTracer`].
|
||||
///
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Sets a global maximum level for `log` records.
|
||||
///
|
||||
/// Log records whose level is more verbose than the provided level will be
|
||||
/// disabled.
|
||||
///
|
||||
/// By default, all `log` records will be enabled.
|
||||
pub fn with_max_level(self, filter: impl Into<log::LevelFilter>) -> Self {
|
||||
let filter = filter.into();
|
||||
Self { filter, ..self }
|
||||
}
|
||||
|
||||
/// Configures the `LogTracer` to ignore all log records whose target
|
||||
/// starts with the given string.
|
||||
///
|
||||
/// This should be used when a crate enables the `tracing/log` feature to
|
||||
/// emit log records for tracing events. Otherwise, those events will be
|
||||
/// recorded twice.
|
||||
pub fn ignore_crate(mut self, name: impl Into<String>) -> Self {
|
||||
self.ignore_crates.push(name.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures the `LogTracer` to ignore all log records whose target
|
||||
/// starts with any of the given the given strings.
|
||||
///
|
||||
/// This should be used when a crate enables the `tracing/log` feature to
|
||||
/// emit log records for tracing events. Otherwise, those events will be
|
||||
/// recorded twice.
|
||||
pub fn ignore_all<I>(self, crates: impl IntoIterator<Item = I>) -> Self
|
||||
where
|
||||
I: Into<String>,
|
||||
{
|
||||
crates.into_iter().fold(self, Self::ignore_crate)
|
||||
}
|
||||
|
||||
/// Configures the `LogTracer` to either disable or enable the interest cache.
|
||||
///
|
||||
/// When enabled, a per-thread LRU cache will be used to cache whenever the logger
|
||||
/// is interested in a given [level] + [target] pair for records generated through
|
||||
/// the `log` crate.
|
||||
///
|
||||
/// When no `trace!` logs are enabled the logger is able to cheaply filter
|
||||
/// them out just by comparing their log level to the globally specified
|
||||
/// maximum, and immediately reject them. When *any* other `trace!` log is
|
||||
/// enabled (even one which doesn't actually exist!) the logger has to run
|
||||
/// its full filtering machinery on each and every `trace!` log, which can
|
||||
/// potentially be very expensive.
|
||||
///
|
||||
/// Enabling this cache is useful in such situations to improve performance.
|
||||
///
|
||||
/// You most likely do not want to enabled this if you have registered any dynamic
|
||||
/// filters on your logger and you want them to be run every time.
|
||||
///
|
||||
/// This is disabled by default.
|
||||
///
|
||||
/// [level]: log::Metadata::level
|
||||
/// [target]: log::Metadata::target
|
||||
#[cfg(all(feature = "interest-cache", feature = "std"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "interest-cache", feature = "std"))))]
|
||||
pub fn with_interest_cache(mut self, config: crate::InterestCacheConfig) -> Self {
|
||||
self.interest_cache_config = Some(config);
|
||||
self
|
||||
}
|
||||
|
||||
/// Constructs a new `LogTracer` with the provided configuration and sets it
|
||||
/// as the default logger.
|
||||
///
|
||||
/// Setting a global logger can only be done once.
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
#[allow(unused_mut)]
|
||||
pub fn init(mut self) -> Result<(), SetLoggerError> {
|
||||
#[cfg(all(feature = "interest-cache", feature = "std"))]
|
||||
crate::interest_cache::configure(self.interest_cache_config.take());
|
||||
|
||||
let ignore_crates = self.ignore_crates.into_boxed_slice();
|
||||
let logger = Box::new(LogTracer { ignore_crates });
|
||||
log::set_boxed_logger(logger)?;
|
||||
log::set_max_level(self.filter);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Builder {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
ignore_crates: Vec::new(),
|
||||
filter: log::LevelFilter::max(),
|
||||
#[cfg(all(feature = "interest-cache", feature = "std"))]
|
||||
interest_cache_config: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
123
third-party/vendor/tracing-log/tests/log_tracer.rs
vendored
Normal file
123
third-party/vendor/tracing-log/tests/log_tracer.rs
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use tracing::subscriber::with_default;
|
||||
use tracing_core::span::{Attributes, Record};
|
||||
use tracing_core::{span, Event, Level, LevelFilter, Metadata, Subscriber};
|
||||
use tracing_log::{LogTracer, NormalizeEvent};
|
||||
|
||||
struct State {
|
||||
last_normalized_metadata: Mutex<(bool, Option<OwnedMetadata>)>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct OwnedMetadata {
|
||||
name: String,
|
||||
target: String,
|
||||
level: Level,
|
||||
module_path: Option<String>,
|
||||
file: Option<String>,
|
||||
line: Option<u32>,
|
||||
}
|
||||
|
||||
struct TestSubscriber(Arc<State>);
|
||||
|
||||
impl Subscriber for TestSubscriber {
|
||||
fn enabled(&self, meta: &Metadata<'_>) -> bool {
|
||||
dbg!(meta);
|
||||
true
|
||||
}
|
||||
|
||||
fn max_level_hint(&self) -> Option<LevelFilter> {
|
||||
Some(LevelFilter::from_level(Level::INFO))
|
||||
}
|
||||
|
||||
fn new_span(&self, _span: &Attributes<'_>) -> span::Id {
|
||||
span::Id::from_u64(42)
|
||||
}
|
||||
|
||||
fn record(&self, _span: &span::Id, _values: &Record<'_>) {}
|
||||
|
||||
fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
|
||||
|
||||
fn event(&self, event: &Event<'_>) {
|
||||
dbg!(event);
|
||||
*self.0.last_normalized_metadata.lock().unwrap() = (
|
||||
event.is_log(),
|
||||
event.normalized_metadata().map(|normalized| OwnedMetadata {
|
||||
name: normalized.name().to_string(),
|
||||
target: normalized.target().to_string(),
|
||||
level: *normalized.level(),
|
||||
module_path: normalized.module_path().map(String::from),
|
||||
file: normalized.file().map(String::from),
|
||||
line: normalized.line(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn enter(&self, _span: &span::Id) {}
|
||||
|
||||
fn exit(&self, _span: &span::Id) {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalized_metadata() {
|
||||
LogTracer::init().unwrap();
|
||||
let me = Arc::new(State {
|
||||
last_normalized_metadata: Mutex::new((false, None)),
|
||||
});
|
||||
let state = me.clone();
|
||||
|
||||
with_default(TestSubscriber(me), || {
|
||||
log::info!("expected info log");
|
||||
log::debug!("unexpected debug log");
|
||||
let log = log::Record::builder()
|
||||
.args(format_args!("Error!"))
|
||||
.level(log::Level::Info)
|
||||
.build();
|
||||
log::logger().log(&log);
|
||||
last(
|
||||
&state,
|
||||
true,
|
||||
Some(OwnedMetadata {
|
||||
name: "log event".to_string(),
|
||||
target: "".to_string(),
|
||||
level: Level::INFO,
|
||||
module_path: None,
|
||||
file: None,
|
||||
line: None,
|
||||
}),
|
||||
);
|
||||
|
||||
let log = log::Record::builder()
|
||||
.args(format_args!("Error!"))
|
||||
.level(log::Level::Info)
|
||||
.target("log_tracer_target")
|
||||
.file(Some("server.rs"))
|
||||
.line(Some(144))
|
||||
.module_path(Some("log_tracer"))
|
||||
.build();
|
||||
log::logger().log(&log);
|
||||
last(
|
||||
&state,
|
||||
true,
|
||||
Some(OwnedMetadata {
|
||||
name: "log event".to_string(),
|
||||
target: "log_tracer_target".to_string(),
|
||||
level: Level::INFO,
|
||||
module_path: Some("log_tracer".to_string()),
|
||||
file: Some("server.rs".to_string()),
|
||||
line: Some(144),
|
||||
}),
|
||||
);
|
||||
|
||||
tracing::info!("test with a tracing info");
|
||||
last(&state, false, None);
|
||||
})
|
||||
}
|
||||
|
||||
fn last(state: &State, should_be_log: bool, expected: Option<OwnedMetadata>) {
|
||||
let lock = state.last_normalized_metadata.lock().unwrap();
|
||||
let (is_log, metadata) = &*lock;
|
||||
dbg!(&metadata);
|
||||
assert_eq!(dbg!(*is_log), should_be_log);
|
||||
assert_eq!(metadata.as_ref(), expected.as_ref());
|
||||
}
|
||||
10
third-party/vendor/tracing-log/tests/reexport_log_crate.rs
vendored
Normal file
10
third-party/vendor/tracing-log/tests/reexport_log_crate.rs
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
use tracing_log::{log::LevelFilter, LogTracer};
|
||||
|
||||
/// This test makes sure we can access `log::LevelFilter` through the `tracing_log` crate and don't
|
||||
/// have to depend on `log` separately.
|
||||
///
|
||||
/// See https://github.com/tokio-rs/tracing/issues/552.
|
||||
#[test]
|
||||
fn can_initialize_log_tracer_with_level() {
|
||||
LogTracer::init_with_filter(LevelFilter::Error).unwrap();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue