dango 0.1.1

Application skeleton
Documentation
//
// Copyright © 2022, Oleg Lelenkov
// License: BSD 3-Clause
// Authors: Oleg Lelenkov
//

use std::fmt::{self, Debug};
use std::marker::PhantomData;

use uninode::UniNode;

use tracing::subscriber::{Interest, Subscriber};
use tracing::{span, Event, Metadata};
use tracing_subscriber::filter::targets::Targets;
use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::layer::{Context, Filter, Layer};
use tracing_subscriber::registry::LookupSpan;

pub fn create_level_filter(level: &str) -> LevelFilter {
    match level {
        "trace" => LevelFilter::TRACE,
        "debug" => LevelFilter::DEBUG,
        "info" => LevelFilter::INFO,
        "warn" => LevelFilter::WARN,
        "error" => LevelFilter::ERROR,
        _ => LevelFilter::OFF,
    }
}

pub fn create_target_filter(cfg: &UniNode) -> Targets {
    let mut retval = Targets::new();
    for target in cfg.clone().to_array().unwrap() {
        let target = target.as_str().ok().and_then(|v| v.split_once('='));
        if let Some((target, level)) = target {
            let level = create_level_filter(level);
            retval = retval.with_target(target, level);
        }
    }
    retval
}

#[derive(Clone)]
pub struct Filtered<L, F, S> {
    filter: F,
    layer: L,
    _s: PhantomData<fn(S)>,
}

impl<L, F, S> Filtered<L, F, S>
where
    F: Filter<S> + 'static,
{
    pub fn new(layer: L, filter: F) -> Self {
        Self {
            layer,
            filter,
            _s: PhantomData,
        }
    }

    fn enabled(&self, meta: &Metadata<'_>, ctx: &Context<S>) -> bool {
        Filter::enabled(&self.filter, meta, ctx)
    }
}

impl<F, L, S> Debug for Filtered<F, L, S>
where
    F: Debug,
    L: Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("CombFiltered")
            .field("filter", &self.filter)
            .field("layer", &self.layer)
            .finish()
    }
}

impl<S, L, F> Layer<S> for Filtered<L, F, S>
where
    S: Subscriber + for<'span> LookupSpan<'span> + 'static + Debug,
    for<'a> <S as LookupSpan<'a>>::Data: Debug,
    F: Filter<S> + Layer<S> + 'static,
    L: Layer<S>,
{
    fn on_layer(&mut self, subscriber: &mut S) {
        self.filter.on_layer(subscriber);
        self.layer.on_layer(subscriber);
    }

    fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
        let interest = self.filter.callsite_enabled(metadata);
        if !interest.is_never() {
            self.layer.register_callsite(metadata);
        }
        Interest::always()
    }

    fn enabled(&self, meta: &Metadata, ctx: Context<S>) -> bool {
        let enabled = self.enabled(meta, &ctx);
        if enabled {
            self.layer.enabled(meta, ctx)
        } else {
            true
        }
    }

    fn on_new_span(&self, attrs: &span::Attributes, id: &span::Id, ctx: Context<S>) {
        self.layer.on_new_span(attrs, id, ctx.clone())
    }

    fn max_level_hint(&self) -> Option<LevelFilter> {
        Filter::max_level_hint(&self.filter)
    }

    fn on_record(&self, id: &span::Id, values: &span::Record, ctx: Context<S>) {
        if let Some(meta) = ctx.metadata(id) {
            if self.enabled(meta, &ctx) {
                self.layer.on_record(id, values, ctx)
            }
        }
    }

    fn on_follows_from(&self, id: &span::Id, follows: &span::Id, ctx: Context<'_, S>) {
        if let (Some(id_meta), Some(f_meta)) = (ctx.metadata(id), ctx.metadata(follows)) {
            if self.enabled(id_meta, &ctx) && self.enabled(f_meta, &ctx) {
                self.layer.on_follows_from(id, follows, ctx)
            }
        }
    }

    fn on_event(&self, event: &Event, ctx: Context<S>) {
        if self.enabled(event.metadata(), &ctx) {
            self.layer.on_event(event, ctx);
        }
    }

    fn on_enter(&self, id: &span::Id, ctx: Context<S>) {
        if let Some(meta) = ctx.metadata(id) {
            if self.enabled(meta, &ctx) {
                self.layer.on_enter(id, ctx)
            }
        }
    }

    fn on_exit(&self, id: &span::Id, ctx: Context<S>) {
        if let Some(meta) = ctx.metadata(id) {
            if self.enabled(meta, &ctx) {
                self.layer.on_exit(id, ctx)
            }
        }
    }

    fn on_close(&self, id: span::Id, ctx: Context<S>) {
        if let Some(meta) = ctx.metadata(&id) {
            if self.enabled(meta, &ctx) {
                self.layer.on_close(id, ctx)
            }
        }
    }

    fn on_id_change(&self, old: &span::Id, new: &span::Id, ctx: Context<S>) {
        if let Some(meta) = ctx.metadata(old) {
            if self.enabled(meta, &ctx) {
                self.layer.on_id_change(old, new, ctx)
            }
        }
    }
}