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
use crate::{Error, Receiver}; use log::LevelFilter; use std::io::{stderr, stdout, BufWriter, Stderr, Stdout, Write}; use std::{fmt, fs::File}; pub trait Consumer: Send + Sync + 'static { fn boxed(self) -> Result<Box<dyn Consumer>, Error>; fn consume(&mut self, channel: Receiver); } impl Consumer for BaseConsumer { fn boxed(self) -> Result<Box<dyn Consumer>, Error> { Ok(Box::new(self) as _) } fn consume(&mut self, channel: Receiver) { for message in channel { if let Some(message) = message { for (level, ref mut w) in self.outputers.iter_mut() { if *level >= message.level { if let Err(e) = w.write_all(message.content.as_bytes()) { panic!("failed write log to {}: {}", (&*w).desc(), e); } } } } else { break; } } } } #[derive(Default)] pub struct BaseConsumer { outputers: Vec<(LevelFilter, Box<dyn Outputer>)>, } impl fmt::Debug for BaseConsumer { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("BaseConsumer") .field( "outputers", &self.outputers.iter().map(|(l, o)| (l, o.desc())).collect::<Vec<_>>(), ) .finish() } } impl BaseConsumer { pub fn new() -> Self { Self::default() } pub fn chain<O: Outputer>(mut self, level: LevelFilter, outputer: O) -> Result<Self, Error> { self.outputers.push((level, outputer.boxed()?)); Ok(self) } pub fn stdout(level: LevelFilter) -> Self { Self::new().chain(level, stdout()).unwrap() } pub fn stderr(level: LevelFilter) -> Self { Self::new().chain(level, stderr()).unwrap() } pub fn file(level: LevelFilter, file: File) -> Self { Self::new().chain(level, file).unwrap() } pub fn bufwriter<W>(level: LevelFilter, bufwriter: BufWriter<W>) -> Self where W: Write + Send + Sync + 'static, { Self::new().chain(level, bufwriter).unwrap() } } pub trait Outputer: Write + Send + Sync + 'static { fn boxed(self) -> Result<Box<dyn Outputer>, Error>; fn desc(&self) -> &str; } impl Outputer for Stdout { fn boxed(self) -> Result<Box<dyn Outputer>, Error> { Ok(Box::new(self) as _) } fn desc(&self) -> &str { "stdout" } } impl Outputer for Stderr { fn boxed(self) -> Result<Box<dyn Outputer>, Error> { Ok(Box::new(self) as _) } fn desc(&self) -> &str { "stderr" } } impl Outputer for File { fn boxed(self) -> Result<Box<dyn Outputer>, Error> { Ok(Box::new(self) as _) } fn desc(&self) -> &str { "file" } } impl<W> Outputer for BufWriter<W> where W: Write + Send + Sync + 'static, { fn boxed(self) -> Result<Box<dyn Outputer>, Error> { Ok(Box::new(self) as _) } fn desc(&self) -> &str { "bufwriter" } }