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