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