1use crate::error::{LogError, LogResult};
6use crate::logger::{CustomFilter, LogData, LogPlus};
7use crate::utils::{AsyncLogType, debug_check_init, parse_level, parse_size};
8use crate::quickwit::{QuickwitConfig, QuickwitClient};
9use std::io::LineWriter;
10use std::path::Path;
11use std::sync::{mpsc, OnceLock};
12
13static LOGGER_PLUS: OnceLock<LogPlus> = OnceLock::new();
15
16#[inline]
18pub fn init_log_simple(
19 level: &str,
20 log_file: String,
21 log_file_max: &str,
22 use_console: bool,
23 use_async: bool,
24) -> LogResult<()> {
25 init_log_inner(
26 parse_level(level)?,
27 log_file,
28 parse_size(log_file_max)?,
29 use_console,
30 use_async,
31 None,
32 None,
33 )
34}
35
36#[inline]
38pub fn init_log(
39 level: log::LevelFilter,
40 log_file: String,
41 log_file_max: u32,
42 use_console: bool,
43 use_async: bool,
44) -> LogResult<()> {
45 init_log_inner(level, log_file, log_file_max, use_console, use_async, None, None)
46}
47
48#[inline]
50pub fn init_log_with_plugin<P>(
51 level: log::LevelFilter,
52 log_file: String,
53 log_file_max: u32,
54 use_console: bool,
55 use_async: bool,
56 plugin: P,
57) -> LogResult<()>
58where
59 P: std::io::Write + Send + Sync + 'static,
60{
61 init_log_inner(
62 level,
63 log_file,
64 log_file_max,
65 use_console,
66 use_async,
67 Some(Box::new(plugin)),
68 None,
69 )
70}
71
72#[inline]
74pub fn init_log_with_filter(
75 level: log::LevelFilter,
76 log_file: String,
77 log_file_max: u32,
78 use_console: bool,
79 use_async: bool,
80 filter: impl CustomFilter,
81) -> LogResult<()> {
82 init_log_inner(
83 level,
84 log_file,
85 log_file_max,
86 use_console,
87 use_async,
88 None,
89 Some(Box::new(filter)),
90 )
91}
92
93pub fn init_log_with_all<P>(
95 level: log::LevelFilter,
96 log_file: String,
97 log_file_max: u32,
98 use_console: bool,
99 use_async: bool,
100 plugin: P,
101 filter: impl CustomFilter,
102) -> LogResult<()>
103where
104 P: std::io::Write + Send + Sync + 'static,
105{
106 init_log_inner(
107 level,
108 log_file,
109 log_file_max,
110 use_console,
111 use_async,
112 Some(Box::new(plugin)),
113 Some(Box::new(filter)),
114 )
115}
116
117pub fn set_level(target: String, level: log::LevelFilter) {
119 if let Ok(mut f) = get_logger_plus().level_filter.write() {
120 f.insert(target, level);
121 }
122}
123
124fn init_log_inner(
126 level: log::LevelFilter,
127 log_file: String,
128 log_file_max: u32,
129 use_console: bool,
130 use_async: bool,
131 plugin: Option<Box<dyn std::io::Write + Send + Sync + 'static>>,
132 filter: Option<Box<dyn CustomFilter>>,
133) -> LogResult<()> {
134 init_log_inner_with_config(
135 level,
136 log_file,
137 log_file_max,
138 use_console,
139 use_async,
140 plugin,
141 filter,
142 true,
143 true,
144 true,
145 Vec::new(),
146 None,
147 )
148}
149
150pub fn init_log_inner_with_config(
152 level: log::LevelFilter,
153 log_file: String,
154 log_file_max: u32,
155 use_console: bool,
156 use_async: bool,
157 plugin: Option<Box<dyn std::io::Write + Send + Sync + 'static>>,
158 filter: Option<Box<dyn CustomFilter>>,
159 show_process_id: bool,
160 show_thread_info: bool,
161 show_module_path: bool,
162 highlight_keywords: Vec<String>,
163 quickwit_config: Option<QuickwitConfig>,
164) -> LogResult<()> {
165 if log_file_max == 0 {
167 return Err(LogError::config("Max file size cannot be zero"));
168 }
169
170 if !log_file.is_empty() {
171 if let Some(parent) = Path::new(&log_file).parent() {
172 if !parent.exists() {
173 return Err(LogError::file_operation(
174 log_file.clone(),
175 "Parent directory does not exist",
176 ));
177 }
178 }
179 }
180
181 debug_check_init();
182
183 log::set_max_level(level);
184
185 let console = if use_console {
187 Some(LineWriter::new(std::io::stdout()))
188 } else {
189 None
190 };
191
192 let (fileout, log_size) = if !log_file.is_empty() {
194 match crate::utils::open_log_file_sync(&log_file) {
195 Ok((writer, size)) => (Some(writer), size),
196 Err(e) => {
197 eprintln!("Failed to open log file {}: {}", log_file, e);
198 (None, 0)
199 }
200 }
201 } else {
202 (None, 0)
203 };
204
205 let sender = if use_async {
207 let (sender, receiver) = mpsc::channel::<AsyncLogType>();
208
209 let quickwit_config_clone = quickwit_config.clone();
211
212 std::thread::spawn(move || {
213 let quickwit_client = if let Some(config) = quickwit_config_clone {
215 match crate::quickwit::QuickwitClient::new(config) {
216 Ok(client) => {
217 if std::env::var("QUICKWIT_DEBUG").is_ok() {
218 eprintln!("✓ 异步线程中 Quickwit 客户端创建成功");
219 }
220 Some(client)
221 },
222 Err(e) => {
223 eprintln!("✗ 异步线程中 Quickwit 客户端创建失败: {}", e);
224 None
225 }
226 }
227 } else {
228 None
229 };
230
231 loop {
232 match receiver.recv() {
233 Ok(data) => match data {
234 AsyncLogType::Message(msg) => {
235 get_logger_plus().write(&msg);
236 crate::utils::put_msg_to_cache(msg);
237 }
238 AsyncLogType::Flush => get_logger_plus().flush_inner(),
239 AsyncLogType::QuickwitLog(log_entry) => {
240 if let Some(ref client) = quickwit_client {
241 match client.send_log(&log_entry) {
242 Ok(()) => {
243 if std::env::var("QUICKWIT_DEBUG").is_ok() {
244 eprintln!("✓ 异步模式:日志已发送到 Quickwit: {}", log_entry.message);
245 }
246 },
247 Err(e) => {
248 eprintln!("✗ 异步模式:发送日志到 Quickwit 失败: {}", e);
249 eprintln!(" 日志内容: {}", log_entry.message);
250 eprintln!(" 错误详情: {:?}", e);
251 }
252 }
253 }
254 }
255 },
256 Err(e) => eprintln!("logger channel recv error: {}", e),
257 }
258 }
259 });
260 Some(sender)
261 } else {
262 None
263 };
264
265 let logger_data = LogData {
266 log_size,
267 console,
268 fileout,
269 sender,
270 plugin,
271 };
272
273 let quickwit_client = match quickwit_config {
275 Some(config) => {
276 if std::env::var("QUICKWIT_DEBUG").is_ok() {
277 eprintln!("正在创建 Quickwit 客户端,配置: {:?}", config);
278 }
279 match QuickwitClient::new(config) {
280 Ok(client) => {
281 if std::env::var("QUICKWIT_DEBUG").is_ok() {
282 eprintln!("✓ Quickwit 客户端创建成功");
283 }
284 Some(client)
285 },
286 Err(e) => {
287 eprintln!("✗ Quickwit 客户端创建失败: {}", e);
288 return Err(e);
289 }
290 }
291 },
292 None => {
293 if std::env::var("QUICKWIT_DEBUG").is_ok() {
294 eprintln!("未配置 Quickwit,跳过客户端创建");
295 }
296 None
297 },
298 };
299
300 let logger = LogPlus::new(
301 level,
302 log_file,
303 log_file_max,
304 filter,
305 logger_data,
306 show_process_id,
307 show_thread_info,
308 show_module_path,
309 highlight_keywords,
310 quickwit_client,
311 );
312
313 LOGGER_PLUS
314 .set(logger)
315 .map_err(|_| LogError::initialization_error("Logger already initialized"))?;
316
317 log::set_logger(get_logger_plus())
318 .map_err(|e| LogError::initialization_error(format!("Failed to set logger: {}", e)))?;
319
320 Ok(())
321}
322
323pub fn get_logger_plus() -> &'static LogPlus {
325 LOGGER_PLUS.get().expect("Logger not initialized")
326}
327
328pub fn is_initialized() -> bool {
330 LOGGER_PLUS.get().is_some()
331}
332
333pub fn current_log_level() -> Option<log::LevelFilter> {
335 LOGGER_PLUS.get().map(|logger| logger.level)
336}