config_items/
lg.rs

1use serde::{Serialize, Deserialize};
2use std::error::Error;
3use log::LevelFilter;
4use log4rs::append::console::ConsoleAppender;
5use log4rs::append::file::FileAppender;
6use log4rs::encode::pattern::PatternEncoder;
7use log4rs::config::Config as LogConfig;
8use log4rs::config::{Appender, Logger, Root};
9// use log::*;
10use std::env;
11
12use crate::data::get_log_filename;
13use crate::res::ERes;
14
15fn default_level() -> String {
16    "info".into()
17}
18
19/// Logging configuration
20#[derive(Serialize, Deserialize, Debug, Clone)]
21pub struct Logging {
22    pub file_name: String,
23    #[serde(default="default_level")]
24    pub level: String,
25    pub file_logging_disabled: Option<bool>,
26}
27impl Logging {
28    /// Initialize using current configuration
29    pub fn init(&self) -> ERes<()> {
30        create_log_config_and_init(self)?;
31        Ok(())
32    }
33}
34impl Default for Logging {
35    fn default() -> Self {
36        Logging {
37            file_name: get_log_filename().into(),
38            level: default_level(),
39            file_logging_disabled: None,
40        }
41    }
42}
43
44fn level_filter_from_string(es:&str) -> Result<LevelFilter, Box<dyn Error>> {
45    let ll = match es {
46        "debug" => LevelFilter::Debug,
47        "info" => LevelFilter::Info,
48        "warn" => LevelFilter::Warn,
49        "error" => LevelFilter::Error,
50        "trace" => LevelFilter::Trace,
51        _ => return Err(Box::from(format!("Invalid log level '{}'", es)))
52    };
53    Ok(ll)
54}
55
56/// Create a logging configuration
57pub fn create_log_config(lg:&Logging)  -> ERes<LogConfig>  {
58    const PATTERN:&str = "[{d(%Y-%m-%d %H:%M:%S)} {l}] {m}{n}";
59
60    let no_file_logging = if let Some(fld) = &lg.file_logging_disabled {
61        *fld
62    } else {
63        false
64    };
65
66    let enable_file_logging = ! no_file_logging;
67
68    let level_filter = match env::var("RUST_LOG") {
69        Ok(rl) => level_filter_from_string(&rl)?,
70        Err(_) => level_filter_from_string(lg.level.as_str())?
71    };
72
73    let config = if enable_file_logging {
74        let stdout = ConsoleAppender::builder()
75            .encoder(Box::new(PatternEncoder::new(PATTERN)))
76            .build();
77
78        let requests = FileAppender::builder()
79                .encoder(Box::new(PatternEncoder::new(PATTERN)))
80            .build(&lg.file_name)?;
81
82        let cfg = LogConfig::builder()
83            .appender(Appender::builder()
84                .build("stdout", Box::new(stdout)))
85            .appender(Appender::builder()
86                .build("requests", Box::new(requests)))
87            .logger(Logger::builder()
88                .build("app::backend::db", level_filter))
89            .logger(Logger::builder()
90                    .appender("requests")
91                    .additive(false)
92                .build("app::requests", level_filter))
93            .build(Root::builder()
94                    .appender("stdout")
95                    .appender("requests")
96                .build(level_filter))?;
97        cfg
98    } else {
99        let stdout = ConsoleAppender::builder()
100            .encoder(Box::new(PatternEncoder::new(PATTERN)))
101            .build();
102        let cfg = LogConfig::builder()
103            .appender(Appender::builder()
104                .build("stdout", Box::new(stdout)))
105            .logger(Logger::builder()
106                .build("app::backend::db", level_filter))
107            .build(Root::builder()
108                    .appender("stdout")
109                .build(level_filter))?;
110        cfg
111    };
112
113    Ok(config)
114}
115
116/// Create a logging configuration and initialize logger
117fn create_log_config_and_init(lg:&Logging)  -> ERes<()>  {
118    let lcfg = create_log_config(lg)?;
119    match log4rs::init_config(lcfg) {
120        Ok(_)=> Ok(()),
121        Err(e) => Err(Box::new(e)),
122    }        
123}