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::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        layers.push(
25            fmt::Layer::new()
26                .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
27                .with_ansi(config.colored_logs)
28                .with_target(true)
29                .with_writer(tracing_appender::rolling::never(&config.writeable_path, LOG_FILE))
30                .with_filter(lockbook_log_level)
31                .with_filter(filter::filter_fn(|metadata| {
32                    metadata.target().starts_with("lb_rs")
33                        || metadata.target().starts_with("dbrs")
34                        || metadata.target().starts_with("workspace")
35                        || metadata.target().starts_with("lb_fs")
36                }))
37                .boxed(),
38        );
39
40        if config.stdout_logs {
41            // stdout target for non-android platforms
42            #[cfg(not(target_os = "android"))]
43            layers.push(
44                fmt::Layer::new()
45                    .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
46                    .with_ansi(config.colored_logs)
47                    .with_target(true)
48                    .with_filter(lockbook_log_level)
49                    .with_filter(filter::filter_fn(|metadata| {
50                        metadata.target().starts_with("lb_rs")
51                            || metadata.target().starts_with("dbrs")
52                            || metadata.target().starts_with("workspace")
53                            || metadata.target().starts_with("lb_fs")
54                    }))
55                    .boxed(),
56            );
57
58            // logcat target for android
59            #[cfg(target_os = "android")]
60            if let Some(writer) =
61                tracing_logcat::LogcatMakeWriter::new(tracing_logcat::LogcatTag::Target).ok()
62            {
63                layers.push(
64                    fmt::Layer::new()
65                        .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
66                        .with_ansi(false)
67                        .with_writer(writer)
68                        .with_filter(lockbook_log_level)
69                        .with_filter(filter::filter_fn(|metadata| {
70                            metadata.target().starts_with("lb_rs")
71                                || metadata.target().starts_with("workspace")
72                                || metadata.target().starts_with("lb_java")
73                        }))
74                        .boxed(),
75                );
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 |panic_info| {
91        let bt = Backtrace::force_capture();
92        tracing::error!("panic detected: {panic_info} {}", bt);
93        eprintln!("panic detected and logged: {panic_info} {bt}");
94        let timestamp = Local::now().format("%Y-%m-%d---%H-%M-%S");
95        let file_name = format!("{path}/panic---{timestamp}.log");
96        let content = format!("INFO: {panic_info}\nBT: {bt}");
97
98        let mut file = OpenOptions::new()
99            .create(true)
100            .append(true)
101            .open(&file_name)
102            .unwrap();
103
104        file.write_all(content.as_bytes()).unwrap();
105    }));
106}