1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! A generic log proxy implementation.
//!
//! This module defines the [`LogProxy`] struct and implements the [`Log`]
//! trait for it.
//!
//! # Use
//!
//! # Example
//!
//! [`LogProxy`]: ./struct.LogProxy.html
//! [`Log`]: ../trait.Log.html

use crate::common::log::{Log, LogRecord, Loglevel, LoglevelFilter, Sender};

/// A [`LogProxy`] is a logger implementation (`Log`) which sends log records
/// using its Sender side of a Channel.
///
/// [`LogProxy`]: ./struct.LogProxy.html
#[derive(Debug)]
pub struct LogProxy<T: Sender> {
    name: String,
    level: LoglevelFilter,
    sender: T,
}

impl<T: Sender<Item = LogRecord>> LogProxy<T> {
    fn new(name: impl Into<String>, level: LoglevelFilter, sender: T) -> LogProxy<T> {
        LogProxy {
            name: name.into(),
            level,
            sender,
        }
    }

    /// Return a new boxed LogProxy for the provided sender and level.
    pub fn boxed(name: impl Into<String>, level: LoglevelFilter, sender: T) -> Box<LogProxy<T>> {
        Box::new(LogProxy::new(name, level, sender))
    }
}

impl<T: Sender<Item = LogRecord>> Log for LogProxy<T> {
    fn name(&self) -> &str {
        self.name.as_ref()
    }
    fn enabled(&self, level: Loglevel) -> bool {
        LoglevelFilter::from(level) <= self.level
    }
    fn log(&self, record: &LogRecord) {
        self.sender
            .send(record.clone())
            .expect("LogProxy failed to send record");
    }
}

#[cfg(test)]
mod tests {
    use crate::common::log::{proxy::LogProxy, thread::LogThread, Log, Loglevel, LoglevelFilter};

    #[allow(clippy::cognitive_complexity)]
    #[test]
    fn proxy_level() {
        let log_thread = LogThread::spawn(
            "main_thread",
            LoglevelFilter::Off,
            LoglevelFilter::Trace,
            None,
            vec![],
        )
        .unwrap();

        let log_endpoint = log_thread.get_sender();

        let log_proxy = LogProxy::boxed("fatal", LoglevelFilter::Fatal, log_endpoint.clone());
        assert!(log_proxy.enabled(Loglevel::Fatal));
        assert!(!log_proxy.enabled(Loglevel::Error));

        let log_proxy = LogProxy::boxed("error", LoglevelFilter::Error, log_endpoint.clone());
        assert!(log_proxy.enabled(Loglevel::Fatal));
        assert!(log_proxy.enabled(Loglevel::Error));
        assert!(!log_proxy.enabled(Loglevel::Warn));

        let log_proxy = LogProxy::boxed("warn", LoglevelFilter::Warn, log_endpoint.clone());
        assert!(log_proxy.enabled(Loglevel::Fatal));
        assert!(log_proxy.enabled(Loglevel::Error));
        assert!(log_proxy.enabled(Loglevel::Warn));
        assert!(!log_proxy.enabled(Loglevel::Note));
        assert!(!log_proxy.enabled(Loglevel::Info));
        assert!(!log_proxy.enabled(Loglevel::Debug));
        assert!(!log_proxy.enabled(Loglevel::Trace));

        let log_proxy = LogProxy::boxed("note", LoglevelFilter::Note, log_endpoint.clone());
        assert!(log_proxy.enabled(Loglevel::Fatal));
        assert!(log_proxy.enabled(Loglevel::Error));
        assert!(log_proxy.enabled(Loglevel::Warn));
        assert!(log_proxy.enabled(Loglevel::Note));
        assert!(!log_proxy.enabled(Loglevel::Info));
        assert!(!log_proxy.enabled(Loglevel::Debug));
        assert!(!log_proxy.enabled(Loglevel::Trace));

        let log_proxy = LogProxy::boxed("info", LoglevelFilter::Info, log_endpoint.clone());
        assert!(log_proxy.enabled(Loglevel::Fatal));
        assert!(log_proxy.enabled(Loglevel::Error));
        assert!(log_proxy.enabled(Loglevel::Warn));
        assert!(log_proxy.enabled(Loglevel::Note));
        assert!(log_proxy.enabled(Loglevel::Info));
        assert!(!log_proxy.enabled(Loglevel::Debug));
        assert!(!log_proxy.enabled(Loglevel::Trace));

        let log_proxy = LogProxy::boxed("debug", LoglevelFilter::Debug, log_endpoint.clone());
        assert!(log_proxy.enabled(Loglevel::Fatal));
        assert!(log_proxy.enabled(Loglevel::Error));
        assert!(log_proxy.enabled(Loglevel::Warn));
        assert!(log_proxy.enabled(Loglevel::Note));
        assert!(log_proxy.enabled(Loglevel::Info));
        assert!(log_proxy.enabled(Loglevel::Debug));
        assert!(!log_proxy.enabled(Loglevel::Trace));

        let log_proxy = LogProxy::boxed("trace", LoglevelFilter::Trace, log_endpoint.clone());
        assert!(log_proxy.enabled(Loglevel::Fatal));
        assert!(log_proxy.enabled(Loglevel::Error));
        assert!(log_proxy.enabled(Loglevel::Warn));
        assert!(log_proxy.enabled(Loglevel::Note));
        assert!(log_proxy.enabled(Loglevel::Info));
        assert!(log_proxy.enabled(Loglevel::Debug));
        assert!(log_proxy.enabled(Loglevel::Trace));

        let log_proxy = LogProxy::boxed("off", LoglevelFilter::Off, log_endpoint.clone());
        assert!(!log_proxy.enabled(Loglevel::Fatal));
        assert!(!log_proxy.enabled(Loglevel::Error));
        assert!(!log_proxy.enabled(Loglevel::Warn));
        assert!(!log_proxy.enabled(Loglevel::Note));
        assert!(!log_proxy.enabled(Loglevel::Info));
        assert!(!log_proxy.enabled(Loglevel::Debug));
        assert!(!log_proxy.enabled(Loglevel::Trace));
    }
}