Skip to main content

lb_rs/service/
logging.rs

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