acta 0.1.1

Make Tracing Great Again.
Documentation
use tracing_subscriber::EnvFilter;
use tracing_subscriber::layer::Layered;

use crate::Result;
use crate::config::StyleConfig;
use crate::config::{Filter, Level};

pub type FmtLayer = Box<dyn tracing_subscriber::Layer<tracing_subscriber::Registry> + Send + Sync>;
pub type InnerSubscriber = Layered<FmtLayer, tracing_subscriber::Registry>;
type RawReloadHandle = tracing_subscriber::reload::Handle<EnvFilter, InnerSubscriber>;

#[must_use = "dropping ReloadHandle loses the ability to change log filters at runtime"]
#[allow(clippy::module_name_repetitions)]
pub struct ReloadHandle {
    raw: RawReloadHandle,
    filter: Filter,
    style: StyleConfig,
}

impl std::fmt::Debug for ReloadHandle {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ReloadHandle").finish_non_exhaustive()
    }
}

impl ReloadHandle {
    pub fn with_style(&mut self, f: impl FnOnce(&mut StyleConfig)) {
        f(&mut self.style);
    }

    pub fn reload(&mut self, directive: &str) -> Result<()> {
        self.apply_directive(directive)?;
        self.filter = Filter::new(Level::Custom(directive.to_owned()));
        Ok(())
    }

    pub fn set_filter(&mut self, filter: Filter) -> Result<()> {
        let directive = filter.as_directive();
        self.apply_directive(&directive)?;
        self.filter = filter;
        Ok(())
    }

    pub fn set_level(&mut self, level: Level) -> Result<()> {
        self.filter.level = level;
        self.apply_current_filter()
    }

    pub fn set_target_level(&mut self, target: impl Into<String>, level: Level) -> Result<()> {
        let target = target.into();
        self.filter.set_target(target, level);
        self.apply_current_filter()
    }

    pub fn remove_target_level(&mut self, target: &str) -> Result<()> {
        self.filter.remove_target(target);
        self.apply_current_filter()
    }

    fn apply_current_filter(&self) -> Result<()> {
        let directive = self.filter.as_directive();
        let env_filter = EnvFilter::try_new(&directive)?;
        self.raw.modify(|f| *f = env_filter)?;
        Ok(())
    }

    fn apply_directive(&self, directive: &str) -> Result<()> {
        let filter = EnvFilter::try_new(directive)?;
        self.raw.modify(|f| *f = filter)?;
        Ok(())
    }
}

pub fn build_reload_filter(
    level: Level,
    style: StyleConfig,
) -> (
    tracing_subscriber::reload::Layer<EnvFilter, InnerSubscriber>,
    ReloadHandle,
) {
    let filter = Filter::new(level);
    let (layer, raw) = tracing_subscriber::reload::Layer::new(
        EnvFilter::try_new(filter.as_directive()).unwrap_or_default(),
    );

    (layer, ReloadHandle { raw, filter, style })
}