nonblock_logger/
consumer.rs

1use crate::{Error, Receiver};
2use log::LevelFilter;
3use std::io::{stderr, stdout, BufWriter, Stderr, Stdout, Write};
4use std::{fmt, fs::File};
5
6pub trait Consumer: Send + Sync + 'static {
7    fn boxed(self) -> Result<Box<dyn Consumer>, Error>;
8    fn consume(&mut self, channel: Receiver);
9}
10
11impl Consumer for BaseConsumer {
12    fn boxed(self) -> Result<Box<dyn Consumer>, Error> {
13        Ok(Box::new(self) as _)
14    }
15
16    fn consume(&mut self, channel: Receiver) {
17        for message in channel {
18            if let Some(message) = message {
19                for (level, ref mut w) in self.outputers.iter_mut() {
20                    if *level >= message.level {
21                        if let Err(e) = w.write_all(message.content.as_bytes()) {
22                            panic!("failed write log to {}: {}", (&*w).desc(), e);
23                        }
24                    }
25                }
26            } else {
27                break;
28            }
29        }
30    }
31}
32
33#[derive(Default)]
34pub struct BaseConsumer {
35    outputers: Vec<(LevelFilter, Box<dyn Outputer>)>,
36}
37
38impl fmt::Debug for BaseConsumer {
39    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
40        fmt.debug_struct("BaseConsumer")
41            .field(
42                "outputers",
43                &self.outputers.iter().map(|(l, o)| (l, o.desc())).collect::<Vec<_>>(),
44            )
45            .finish()
46    }
47}
48
49impl BaseConsumer {
50    pub fn new() -> Self {
51        Self::default()
52    }
53
54    pub fn chain<O: Outputer>(mut self, level: LevelFilter, outputer: O) -> Result<Self, Error> {
55        self.outputers.push((level, outputer.boxed()?));
56        Ok(self)
57    }
58
59    pub fn stdout(level: LevelFilter) -> Self {
60        Self::new().chain(level, stdout()).unwrap()
61    }
62
63    pub fn stderr(level: LevelFilter) -> Self {
64        Self::new().chain(level, stderr()).unwrap()
65    }
66
67    pub fn file(level: LevelFilter, file: File) -> Self {
68        Self::new().chain(level, file).unwrap()
69    }
70
71    pub fn bufwriter<W>(level: LevelFilter, bufwriter: BufWriter<W>) -> Self
72    where
73        W: Write + Send + Sync + 'static,
74    {
75        Self::new().chain(level, bufwriter).unwrap()
76    }
77}
78
79pub trait Outputer: Write + Send + Sync + 'static {
80    fn boxed(self) -> Result<Box<dyn Outputer>, Error>;
81    fn desc(&self) -> &str;
82}
83
84impl Outputer for Stdout {
85    fn boxed(self) -> Result<Box<dyn Outputer>, Error> {
86        Ok(Box::new(self) as _)
87    }
88
89    fn desc(&self) -> &str {
90        "stdout"
91    }
92}
93
94impl Outputer for Stderr {
95    fn boxed(self) -> Result<Box<dyn Outputer>, Error> {
96        Ok(Box::new(self) as _)
97    }
98
99    fn desc(&self) -> &str {
100        "stderr"
101    }
102}
103
104impl Outputer for File {
105    fn boxed(self) -> Result<Box<dyn Outputer>, Error> {
106        Ok(Box::new(self) as _)
107    }
108
109    fn desc(&self) -> &str {
110        "file"
111    }
112}
113
114impl<W> Outputer for BufWriter<W>
115where
116    W: Write + Send + Sync + 'static,
117{
118    fn boxed(self) -> Result<Box<dyn Outputer>, Error> {
119        Ok(Box::new(self) as _)
120    }
121
122    fn desc(&self) -> &str {
123        "bufwriter"
124    }
125}