lb_rs/service/
logging.rs

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            // stdout target for non-android platforms
39            #[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            // logcat target for android
56            #[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}