1use crate::Config;
2use crate::model::errors::{LbResult, core_err_unexpected};
3use crate::service::debug::{generate_panic_content, generate_panic_filename};
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 #[cfg(not(target_arch = "wasm32"))]
25 layers.push(
26 fmt::Layer::new()
27 .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
28 .with_ansi(config.colored_logs)
29 .with_target(true)
30 .with_writer(tracing_appender::rolling::never(&config.writeable_path, LOG_FILE))
31 .with_filter(lockbook_log_level)
32 .with_filter(filter::filter_fn(|metadata| {
33 metadata.target().starts_with("lb_rs")
34 || metadata.target().starts_with("dbrs")
35 || metadata.target().starts_with("workspace")
36 || metadata.target().starts_with("lb_fs")
37 }))
38 .boxed(),
39 );
40
41 if config.stdout_logs {
42 #[cfg(not(target_os = "android"))]
44 layers.push(
45 fmt::Layer::new()
46 .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
47 .with_ansi(config.colored_logs)
48 .with_target(true)
49 .with_filter(lockbook_log_level)
50 .with_filter(filter::filter_fn(|metadata| {
51 metadata.target().starts_with("lb_rs")
52 || metadata.target().starts_with("dbrs")
53 || metadata.target().starts_with("workspace")
54 || metadata.target().starts_with("lb_fs")
55 }))
56 .boxed(),
57 );
58
59 #[cfg(target_os = "android")]
61 if let Some(writer) =
62 tracing_logcat::LogcatMakeWriter::new(tracing_logcat::LogcatTag::Target).ok()
63 {
64 layers.push(
65 fmt::Layer::new()
66 .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
67 .with_ansi(false)
68 .with_writer(writer)
69 .with_filter(lockbook_log_level)
70 .with_filter(filter::filter_fn(|metadata| {
71 metadata.target().starts_with("lb_rs")
72 || metadata.target().starts_with("workspace")
73 || metadata.target().starts_with("lb_java")
74 }))
75 .boxed(),
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 |error_header| {
91 let bt = Backtrace::force_capture();
92 tracing::error!("panic detected: {error_header} {}", bt);
93 eprintln!("panic detected and logged: {error_header} {bt}");
94 let file_name = generate_panic_filename(&path);
95 let content = generate_panic_content(&error_header.to_string(), &bt.to_string());
96
97 let mut file = OpenOptions::new()
98 .create(true)
99 .append(true)
100 .open(&file_name)
101 .unwrap();
102
103 file.write_all(content.as_bytes()).unwrap();
104 }));
105}