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
use log;
use config::Config;

use crate::protocol::{Message, SystemMsg};
use crate::actor::{ActorRef, SysTell, BoxActorProd};

#[derive(Clone)]
pub struct Logger<Msg: Message> {
    level: log::Level,
    actor: ActorRef<Msg>,
}

impl<Msg> Logger<Msg>
    where Msg: Message
{
    pub fn init(level: log::Level,
                actor: ActorRef<Msg>) -> Self {
        let logger = Logger {
            level,
            actor
        };

        let _ = log::set_boxed_logger(Box::new(logger.clone())); // result is Err for some reason (.unwrap() panics)
        log::set_max_level(level.to_level_filter());

        logger
    }
}

impl<Msg> log::Log for Logger<Msg>
    where Msg: Message
{
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &log::Record) {
        self.actor.sys_tell(SystemMsg::Log(LogEntry::from(record)), None);
    }

    fn flush(&self) {
    }
}

pub trait LoggerProps {
    type Msg: Message;

    fn props(config: &Config) -> BoxActorProd<Self::Msg>;
}

#[derive(Clone, Debug)]
pub struct LogEntry {
    pub level: log::Level,
    pub module: Option<String>,
    pub body: String,
}

impl<'a> From<&'a log::Record<'a>> for LogEntry {
    fn from(record: &log::Record) -> Self {
        LogEntry {
            level: record.level(),
            module: record.module_path().map(|m| m.to_string()),
            body: format!("{}", record.args())
        }
    }
}

pub trait DeadLetterProps {
    type Msg: Message;

    fn props(dl: ActorRef<Self::Msg>) -> BoxActorProd<Self::Msg>;
}