Make a String round-trippable Targets implementation
This commit is contained in:
commit
7c26d8db4d
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
/Cargo.lock
|
16
Cargo.toml
Normal file
16
Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "tracing-subscriber-fmttargets"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
alloc = ["tracing-subscriber/alloc"]
|
||||
default = ["registry", "std"]
|
||||
registry = ["tracing-subscriber/registry"]
|
||||
std = ["tracing-subscriber/std", "tracing-core/std"]
|
||||
|
||||
[dependencies]
|
||||
tracing-core = { version = "0.1", default-features = false }
|
||||
tracing-subscriber = { version = "0.3", default-features = false }
|
237
src/lib.rs
Normal file
237
src/lib.rs
Normal file
|
@ -0,0 +1,237 @@
|
|||
#![cfg(any(feature = "std", feature = "alloc"))]
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct FmtTargets {
|
||||
pub inner: tracing_subscriber::filter::Targets,
|
||||
}
|
||||
|
||||
impl FmtTargets {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: tracing_subscriber::filter::Targets::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_target(
|
||||
self,
|
||||
target: impl Into<String>,
|
||||
level: impl Into<tracing_subscriber::filter::LevelFilter>,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: self.inner.with_target(target, level),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_targets<T, L>(self, targets: impl IntoIterator<Item = (T, L)>) -> Self
|
||||
where
|
||||
String: From<T>,
|
||||
tracing_subscriber::filter::LevelFilter: From<L>,
|
||||
{
|
||||
Self {
|
||||
inner: self.inner.with_targets(targets),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_default(self, level: impl Into<tracing_subscriber::filter::LevelFilter>) -> Self {
|
||||
Self {
|
||||
inner: self.inner.with_default(level),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> tracing_subscriber::filter::targets::Iter<'_> {
|
||||
self.inner.iter()
|
||||
}
|
||||
|
||||
pub fn would_enable(&self, target: &str, level: &tracing_core::metadata::Level) -> bool {
|
||||
self.inner.would_enable(target, level)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, L> Extend<(T, L)> for FmtTargets
|
||||
where
|
||||
T: Into<String>,
|
||||
L: Into<tracing_subscriber::filter::LevelFilter>,
|
||||
{
|
||||
fn extend<I: IntoIterator<Item = (T, L)>>(&mut self, iter: I) {
|
||||
self.inner.extend(iter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, L> FromIterator<(T, L)> for FmtTargets
|
||||
where
|
||||
T: Into<String>,
|
||||
L: Into<tracing_subscriber::filter::LevelFilter>,
|
||||
{
|
||||
fn from_iter<I: IntoIterator<Item = (T, L)>>(iter: I) -> Self {
|
||||
Self {
|
||||
inner: FromIterator::from_iter(iter),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for FmtTargets {
|
||||
type Item = <tracing_subscriber::filter::Targets as IntoIterator>::Item;
|
||||
type IntoIter = <tracing_subscriber::filter::Targets as IntoIterator>::IntoIter;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a FmtTargets {
|
||||
type Item = <&'a tracing_subscriber::filter::Targets as IntoIterator>::Item;
|
||||
type IntoIter = <&'a tracing_subscriber::filter::Targets as IntoIterator>::IntoIter;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
(&self.inner).into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> tracing_subscriber::Layer<S> for FmtTargets
|
||||
where
|
||||
S: tracing_core::Subscriber,
|
||||
{
|
||||
fn enabled(
|
||||
&self,
|
||||
metadata: &tracing_core::Metadata<'_>,
|
||||
ctx: tracing_subscriber::layer::Context<'_, S>,
|
||||
) -> bool {
|
||||
tracing_subscriber::Layer::<S>::enabled(&self.inner, metadata, ctx)
|
||||
}
|
||||
|
||||
fn register_callsite(
|
||||
&self,
|
||||
metadata: &'static tracing_core::Metadata<'static>,
|
||||
) -> tracing_core::subscriber::Interest {
|
||||
tracing_subscriber::Layer::<S>::register_callsite(&self.inner, metadata)
|
||||
}
|
||||
|
||||
fn max_level_hint(&self) -> Option<tracing_core::metadata::LevelFilter> {
|
||||
tracing_subscriber::Layer::<S>::max_level_hint(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "registry")]
|
||||
impl<S> tracing_subscriber::layer::Filter<S> for FmtTargets {
|
||||
fn enabled(
|
||||
&self,
|
||||
meta: &tracing_core::Metadata<'_>,
|
||||
cx: &tracing_subscriber::layer::Context<'_, S>,
|
||||
) -> bool {
|
||||
tracing_subscriber::layer::Filter::<S>::enabled(&self.inner, meta, cx)
|
||||
}
|
||||
|
||||
fn callsite_enabled(
|
||||
&self,
|
||||
meta: &'static tracing_core::Metadata<'static>,
|
||||
) -> tracing_core::subscriber::Interest {
|
||||
tracing_subscriber::layer::Filter::<S>::callsite_enabled(&self.inner, meta)
|
||||
}
|
||||
|
||||
fn max_level_hint(&self) -> Option<tracing_subscriber::filter::LevelFilter> {
|
||||
tracing_subscriber::layer::Filter::<S>::max_level_hint(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<tracing_subscriber::filter::Targets> for FmtTargets {
|
||||
fn as_ref(&self) -> &tracing_subscriber::filter::Targets {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<tracing_subscriber::filter::Targets> for FmtTargets {
|
||||
fn as_mut(&mut self) -> &mut tracing_subscriber::filter::Targets {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl From<tracing_subscriber::filter::Targets> for FmtTargets {
|
||||
fn from(inner: tracing_subscriber::filter::Targets) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FmtTargets> for tracing_subscriber::filter::Targets {
|
||||
fn from(this: FmtTargets) -> Self {
|
||||
this.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for FmtTargets {
|
||||
type Err = <tracing_subscriber::filter::Targets as std::str::FromStr>::Err;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self { inner: s.parse()? })
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for FmtTargets {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let targets = self
|
||||
.inner
|
||||
.iter()
|
||||
.map(|(path, level)| format!("{}={}", path, level))
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
|
||||
let max_level = [
|
||||
tracing_core::Level::TRACE,
|
||||
tracing_core::Level::DEBUG,
|
||||
tracing_core::Level::INFO,
|
||||
tracing_core::Level::WARN,
|
||||
tracing_core::Level::ERROR,
|
||||
]
|
||||
.iter()
|
||||
.fold(None, |found, level| {
|
||||
if found.is_none()
|
||||
&& self
|
||||
.inner
|
||||
.would_enable("not_a_real_target_so_nothing_can_conflict", level)
|
||||
{
|
||||
Some(level.to_string().to_lowercase())
|
||||
} else {
|
||||
found
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(level) = max_level {
|
||||
if !targets.is_empty() {
|
||||
write!(f, "{},{}", level, targets)
|
||||
} else {
|
||||
write!(f, "{}", level)
|
||||
}
|
||||
} else if !targets.is_empty() {
|
||||
write!(f, "{}", targets)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FmtTargets;
|
||||
|
||||
#[test]
|
||||
fn builds_info_targets() {
|
||||
let t: FmtTargets = "info".parse().unwrap();
|
||||
|
||||
println!("{:?}", t);
|
||||
|
||||
assert_eq!(t.to_string(), "info");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_specific_targets() {
|
||||
let t: FmtTargets = "pict_rs=info".parse().unwrap();
|
||||
|
||||
assert_eq!(t.to_string(), "pict_rs=info");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_warn_and_specific_targets() {
|
||||
let t: FmtTargets = "warn,pict_rs=info".parse().unwrap();
|
||||
|
||||
assert_eq!(t.to_string(), "warn,pict_rs=info");
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue