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            #[cfg(target_os = "android")]
59            if let Some(writer) =
60                tracing_logcat::LogcatMakeWriter::new(tracing_logcat::LogcatTag::Target).ok()
61            {
62                layers.push(
63                    fmt::Layer::new()
64                        .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
65                        .with_ansi(false)
66                        .with_writer(writer)
67                        .with_filter(lockbook_log_level)
68                        .with_filter(filter::filter_fn(|metadata| {
69                            metadata.target().starts_with("lb_rs")
70                                || metadata.target().starts_with("workspace")
71                                || metadata.target().starts_with("lb_java")
72                        }))
73                        .boxed(),
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 |error_header| {
89        let bt = Backtrace::force_capture();
90        tracing::error!("panic detected: {error_header} {}", bt);
91        eprintln!("panic detected and logged: {error_header} {bt}");
92        let file_name = generate_panic_filename(&path);
93        let content = generate_panic_content(&error_header.to_string(), &bt.to_string());
94
95        let mut file = OpenOptions::new()
96            .create(true)
97            .append(true)
98            .open(&file_name)
99            .unwrap();
100
101        file.write_all(content.as_bytes()).unwrap();
102    }));
103}