1use crate::model::errors::{core_err_unexpected, LbResult};
2use crate::Config;
3use chrono::Local;
4use std::backtrace::Backtrace;
5use std::{env, fs, panic};
6use tracing::metadata::LevelFilter;
7use tracing_subscriber::fmt::format::FmtSpan;
8use tracing_subscriber::{filter, fmt, prelude::*, Layer};
9
10pub static LOG_FILE: &str = "lockbook.log";
11
12pub fn init(config: &Config) -> LbResult<()> {
13 if config.logs {
14 let lockbook_log_level = env::var("LOG_LEVEL")
15 .ok()
16 .and_then(|s| s.as_str().parse().ok())
17 .unwrap_or(LevelFilter::DEBUG);
18
19 let mut layers = Vec::with_capacity(2);
20
21 layers.push(
22 fmt::Layer::new()
23 .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
24 .with_ansi(config.colored_logs)
25 .with_target(true)
26 .with_writer(tracing_appender::rolling::never(&config.writeable_path, LOG_FILE))
27 .with_filter(lockbook_log_level)
28 .with_filter(filter::filter_fn(|metadata| {
29 metadata.target().starts_with("lb_rs")
30 || metadata.target().starts_with("dbrs")
31 || metadata.target().starts_with("workspace")
32 || metadata.target().starts_with("lb_fs")
33 }))
34 .boxed(),
35 );
36
37 if config.stdout_logs {
38 #[cfg(not(target_os = "android"))]
40 layers.push(
41 fmt::Layer::new()
42 .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
43 .with_ansi(config.colored_logs)
44 .with_target(true)
45 .with_filter(lockbook_log_level)
46 .with_filter(filter::filter_fn(|metadata| {
47 metadata.target().starts_with("lb_rs")
48 || metadata.target().starts_with("dbrs")
49 || metadata.target().starts_with("workspace")
50 || metadata.target().starts_with("lb_fs")
51 }))
52 .boxed(),
53 );
54
55 #[cfg(target_os = "android")]
57 if let Some(writer) =
58 tracing_logcat::LogcatMakeWriter::new(tracing_logcat::LogcatTag::Target).ok()
59 {
60 layers.push(
61 fmt::Layer::new()
62 .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
63 .with_ansi(false)
64 .with_writer(writer)
65 .with_filter(lockbook_log_level)
66 .with_filter(filter::filter_fn(|metadata| {
67 metadata.target().starts_with("lb_rs")
68 || metadata.target().starts_with("workspace")
69 || metadata.target().starts_with("lb_java")
70 }))
71 .boxed(),
72 );
73 }
74 }
75
76 tracing::subscriber::set_global_default(
77 tracing_subscriber::Registry::default().with(layers),
78 )
79 .map_err(core_err_unexpected)?;
80 panic_capture(config);
81 }
82 Ok(())
83}
84
85fn panic_capture(config: &Config) {
86 let path = config.writeable_path.clone();
87 panic::set_hook(Box::new(move |panic_info| {
88 let bt = Backtrace::force_capture();
89 tracing::error!("panic detected: {panic_info} {}", bt);
90 eprintln!("panic detected and logged: {panic_info} {}", bt);
91 let timestamp = Local::now().format("%Y-%m-%d---%H-%M-%S");
92 let file_name = format!("{}/panic---{}.log", path, timestamp);
93 let file = format!("INFO: {}\nBT: {}", panic_info, bt);
94 fs::write(file_name, file).unwrap();
95 }));
96}