lb_rs/service/
logging.rs

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