captains_log/
console_impl.rs1use crate::{
2 config::{LogFormat, SinkConfigBuild, SinkConfigTrait},
3 env::EnvVarDefault,
4 log_impl::{LogSink, LogSinkTrait},
5 time::Timer,
6};
7use log::{Level, Record};
8use std::hash::{Hash, Hasher};
9use std::path::Path;
10use std::str::FromStr;
11
12#[derive(Hash)]
27pub struct LogConsole {
28 pub target: ConsoleTarget,
29
30 pub level: Level,
32
33 pub format: LogFormat,
34}
35
36impl LogConsole {
37 pub fn new(target: ConsoleTarget, level: Level, format: LogFormat) -> Self {
38 Self { target, level, format }
39 }
40}
41
42#[derive(Copy, Clone, Debug, Hash, PartialEq)]
43#[repr(u8)]
44pub enum ConsoleTarget {
45 Stdout = 1,
46 Stderr = 2,
47}
48
49impl FromStr for ConsoleTarget {
50 type Err = ();
51
52 fn from_str(s: &str) -> Result<Self, ()> {
54 let v = s.to_lowercase();
55 match v.as_str() {
56 "stdout" => Ok(ConsoleTarget::Stdout),
57 "stderr" => Ok(ConsoleTarget::Stderr),
58 "out" => Ok(ConsoleTarget::Stdout),
59 "err" => Ok(ConsoleTarget::Stderr),
60 "1" => Ok(ConsoleTarget::Stdout),
61 "2" => Ok(ConsoleTarget::Stderr),
62 _ => Err(()),
63 }
64 }
65}
66
67crate::impl_from_env!(ConsoleTarget);
70
71impl SinkConfigBuild for LogConsole {
72 fn build(&self) -> LogSink {
73 LogSink::Console(LogSinkConsole::new(self))
74 }
75}
76
77impl SinkConfigTrait for LogConsole {
78 fn get_level(&self) -> Level {
79 self.level
80 }
81
82 fn get_file_path(&self) -> Option<Box<Path>> {
83 None
84 }
85
86 fn write_hash(&self, hasher: &mut Box<dyn Hasher>) {
87 self.hash(hasher);
88 hasher.write(b"LogConsole");
89 }
90}
91
92pub(crate) struct LogSinkConsole {
93 target_fd: libc::c_int,
94 max_level: Level,
95 formatter: LogFormat,
96}
97
98impl LogSinkConsole {
99 fn new(config: &LogConsole) -> Self {
100 Self {
101 target_fd: config.target as i32,
102 max_level: config.level,
103 formatter: config.format.clone(),
104 }
105 }
106}
107
108impl LogSinkTrait for LogSinkConsole {
109 fn open(&self) -> std::io::Result<()> {
110 Ok(())
111 }
112
113 fn reopen(&self) -> std::io::Result<()> {
114 Ok(())
115 }
116
117 #[inline(always)]
118 fn log(&self, now: &Timer, r: &Record) {
119 if r.level() <= self.max_level {
120 let buf = self.formatter.process(now, r);
121 unsafe {
122 let _ = libc::write(self.target_fd, buf.as_ptr() as *const libc::c_void, buf.len());
123 }
124 }
125 }
126
127 #[inline(always)]
128 fn flush(&self) {}
129}