1use crate::{Config, LevelPadding, ThreadLogMode, ThreadPadding};
2use log::{LevelFilter, Record};
3use std::io::{Error, Write};
4use std::thread;
5
6#[inline(always)]
7pub fn try_log<W>(config: &Config, record: &Record<'_>, write: &mut W) -> Result<(), Error>
8where
9 W: Write + Sized,
10{
11 if should_skip(config, record) {
12 return Ok(());
13 }
14
15 if config.time <= record.level() && config.time != LevelFilter::Off {
16 write_time(write, config)?;
17 }
18
19 if config.level <= record.level() && config.level != LevelFilter::Off {
20 write_level(record, write, config)?;
21 }
22
23 if config.thread <= record.level() && config.thread != LevelFilter::Off {
24 match config.thread_log_mode {
25 ThreadLogMode::IDs => {
26 write_thread_id(write, config)?;
27 }
28 ThreadLogMode::Names | ThreadLogMode::Both => {
29 write_thread_name(write, config)?;
30 }
31 }
32 }
33
34 if config.target <= record.level() && config.target != LevelFilter::Off {
35 write_target(record, write)?;
36 }
37
38 if config.location <= record.level() && config.location != LevelFilter::Off {
39 write_location(record, write)?;
40 }
41
42 write_args(record, write)
43}
44
45#[inline(always)]
46pub fn write_time<W>(write: &mut W, config: &Config) -> Result<(), Error>
47where
48 W: Write + Sized,
49{
50 let cur_time = if config.time_local {
51 (chrono::Local::now() + config.time_offset).format(&*config.time_format)
52 } else {
53 (chrono::Utc::now() + config.time_offset).format(&*config.time_format)
54 };
55
56 write!(write, "{} ", cur_time)?;
57 Ok(())
58}
59
60#[inline(always)]
61pub fn write_level<W>(record: &Record<'_>, write: &mut W, config: &Config) -> Result<(), Error>
62where
63 W: Write + Sized,
64{
65 match config.level_padding {
66 LevelPadding::Left => write!(write, "[{: >5}] ", record.level())?,
67 LevelPadding::Right => write!(write, "[{: <5}] ", record.level())?,
68 LevelPadding::Off => write!(write, "[{}] ", record.level())?,
69 };
70 Ok(())
71}
72
73#[inline(always)]
74pub fn write_target<W>(record: &Record<'_>, write: &mut W) -> Result<(), Error>
75where
76 W: Write + Sized,
77{
78 write!(write, "{}: ", record.target())?;
79 Ok(())
80}
81
82#[inline(always)]
83pub fn write_location<W>(record: &Record<'_>, write: &mut W) -> Result<(), Error>
84where
85 W: Write + Sized,
86{
87 let file = record.file().unwrap_or("<unknown>");
88 if let Some(line) = record.line() {
89 write!(write, "[{}:{}] ", file, line)?;
90 } else {
91 write!(write, "[{}:<unknown>] ", file)?;
92 }
93 Ok(())
94}
95
96pub fn write_thread_name<W>(write: &mut W, config: &Config) -> Result<(), Error>
97where
98 W: Write + Sized,
99{
100 if let Some(name) = thread::current().name() {
101 match config.thread_padding {
102 ThreadPadding::Left { 0: qty } => {
103 write!(write, "({name:>0$}) ", qty, name = name)?;
104 }
105 ThreadPadding::Right { 0: qty } => {
106 write!(write, "({name:<0$}) ", qty, name = name)?;
107 }
108 ThreadPadding::Off => {
109 write!(write, "({}) ", name)?;
110 }
111 }
112 } else if config.thread_log_mode == ThreadLogMode::Both {
113 write_thread_id(write, config)?;
114 }
115
116 Ok(())
117}
118
119pub fn write_thread_id<W>(write: &mut W, config: &Config) -> Result<(), Error>
120where
121 W: Write + Sized,
122{
123 let id = format!("{:?}", thread::current().id());
124 let id = id.replace("ThreadId(", "");
125 let id = id.replace(")", "");
126 match config.thread_padding {
127 ThreadPadding::Left { 0: qty } => {
128 write!(write, "({id:>0$}) ", qty, id = id)?;
129 }
130 ThreadPadding::Right { 0: qty } => {
131 write!(write, "({id:<0$}) ", qty, id = id)?;
132 }
133 ThreadPadding::Off => {
134 write!(write, "({}) ", id)?;
135 }
136 }
137 Ok(())
138}
139
140#[inline(always)]
141pub fn write_args<W>(record: &Record<'_>, write: &mut W) -> Result<(), Error>
142where
143 W: Write + Sized,
144{
145 writeln!(write, "{}", record.args())?;
146 Ok(())
147}
148
149#[inline(always)]
150pub fn should_skip(config: &Config, record: &Record<'_>) -> bool {
151 match (record.target(), &*config.filter_allow) {
153 (path, allowed) if !allowed.is_empty() => {
154 if !allowed.iter().any(|v| path.starts_with(&**v)) {
156 return true;
158 }
159 }
160 _ => {}
161 }
162
163 match (record.target(), &*config.filter_ignore) {
165 (path, ignore) if !ignore.is_empty() => {
166 if ignore.iter().any(|v| path.starts_with(&**v)) {
168 return true;
170 }
171 }
172 _ => {}
173 }
174
175 false
176}