pidcat/sink/
terminal.rs

1use crate::log::Log;
2use crate::sink::Sink;
3use async_trait::async_trait;
4use colored::*;
5use lazy_static::lazy_static;
6
7struct Color(u8, u8, u8);
8
9lazy_static! {
10    static ref ERROR: Color = Color(255, 38, 0);
11    static ref VERBOSE: Color = Color(255, 255, 255);
12    static ref INFO: Color = Color(5, 215, 2);
13    static ref WARNING: Color = Color(215, 95, 2);
14    static ref DEBUG: Color = Color(95, 175, 255);
15}
16
17macro_rules! error {
18    ($s:expr) => {
19        println!("{}", $s.truecolor(ERROR.0, ERROR.1, ERROR.2))
20    };
21}
22
23macro_rules! warn {
24    ($s:expr) => {
25        println!("{}", $s.truecolor(WARNING.0, WARNING.1, WARNING.2))
26    };
27}
28
29macro_rules! info {
30    ($s:expr) => {
31        println!("{}", $s.truecolor(INFO.0, INFO.1, INFO.2))
32    };
33}
34
35macro_rules! debug {
36    ($s:expr) => {
37        println!("{}", $s.truecolor(DEBUG.0, DEBUG.1, DEBUG.2))
38    };
39}
40
41macro_rules! verbose {
42    ($s:expr) => {
43        println!("{}", $s.truecolor(VERBOSE.0, VERBOSE.1, VERBOSE.2))
44    };
45}
46
47pub(crate) struct TerminalSink {
48    color: bool,
49    tag_width: usize,
50}
51
52impl TerminalSink {
53    #[allow(dead_code)]
54    pub(crate) fn new(color: String, tag_width: usize) -> Self {
55        Self {
56            color: color == "always" || color == "auto",
57            tag_width,
58        }
59    }
60
61    fn terminal_print(&self, level: &str, s: String) {
62        if self.color {
63            match level {
64                "V" => verbose!(s),
65                "D" => debug!(s),
66                "I" => info!(s),
67                "W" => warn!(s),
68                "E" => error!(s),
69                "F" => error!(s),
70                _ => verbose!(s),
71            };
72        }
73    }
74}
75
76#[async_trait]
77impl Sink for TerminalSink {
78    async fn write(&self, log: Log) {
79        let mut tag = log.tag;
80        if tag.len() > self.tag_width {
81            tag.truncate(self.tag_width);
82        }
83        let message = &log.message.split('\n').collect::<Vec<&str>>();
84        for (i, s) in message.iter().enumerate() {
85            let s = if i == 0 {
86                format!(
87                    "{:11} {:>5} {:<5} {:width$} {:^3} {}",
88                    log.time,
89                    log.pid,
90                    log.tid,
91                    tag,
92                    log.level.on_truecolor(88, 88, 88),
93                    s,
94                    width = self.tag_width
95                )
96            } else {
97                format!(
98                    "{:12} {:>5} {:<5} {:width$} {:^3} {}",
99                    "",
100                    "",
101                    "",
102                    " ",
103                    log.level.on_truecolor(88, 88, 88),
104                    s,
105                    width = self.tag_width
106                )
107            };
108            if self.color {
109                self.terminal_print(log.level.as_str(), s);
110            } else {
111                println!("{}", s);
112            }
113        }
114    }
115}