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