1use log::Level;
13use std::path::{Path, PathBuf};
14use std::str::FromStr;
15
16#[doc(hidden)]
17#[macro_export(local_inner_macros)]
18macro_rules! impl_from_env {
19 ($type: tt) => {
20 impl<'a> Into<$type> for EnvVarDefault<'a, $type> {
21 #[inline]
22 fn into(self) -> $type {
23 if let Ok(v) = std::env::var(&self.name) {
24 match $type::from_str(&v) {
25 Ok(r) => return r,
26 Err(_) => {
27 std::eprintln!(
28 "env {}={} is not valid, set to {:?}",
29 self.name,
30 v,
31 self.default
32 );
33 }
34 }
35 }
36 return self.default;
37 }
38 }
39 };
40}
41
42pub struct EnvVarDefault<'a, T> {
44 pub(crate) name: &'a str,
45 pub(crate) default: T,
46}
47
48pub fn env_or<'a, T>(name: &'a str, default: T) -> EnvVarDefault<'a, T> {
63 EnvVarDefault { name, default }
64}
65
66impl<'a> Into<String> for EnvVarDefault<'a, &'a str> {
67 fn into(self) -> String {
68 if let Ok(v) = std::env::var(&self.name) {
69 return v;
70 }
71 return self.default.to_string();
72 }
73}
74
75impl<'a, P: AsRef<Path>> Into<PathBuf> for EnvVarDefault<'a, P> {
76 fn into(self) -> PathBuf {
77 if let Some(v) = std::env::var_os(&self.name) {
78 if v.len() > 0 {
79 return PathBuf::from(v);
80 }
81 }
82 return self.default.as_ref().to_path_buf();
83 }
84}
85
86crate::impl_from_env!(Level);
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::recipe;
92 use crate::*;
93
94 #[test]
95 fn test_env_config() {
96 unsafe { std::env::set_var("LEVEL", "warn") };
98 let level: Level = env_or("LEVEL", Level::Debug).into();
99 assert_eq!(level, Level::Warn);
100 unsafe { std::env::set_var("LEVEL", "WARN") };
101 let level: Level = env_or("LEVEL", Level::Debug).into();
102 assert_eq!(level, Level::Warn);
103
104 assert_eq!(ConsoleTarget::from_str("Stdout").unwrap(), ConsoleTarget::Stdout);
105 assert_eq!(ConsoleTarget::from_str("StdERR").unwrap(), ConsoleTarget::Stderr);
106 assert_eq!(ConsoleTarget::from_str("1").unwrap(), ConsoleTarget::Stdout);
107 assert_eq!(ConsoleTarget::from_str("2").unwrap(), ConsoleTarget::Stderr);
108 assert_eq!(ConsoleTarget::from_str("0").unwrap_err(), ());
109
110 unsafe { std::env::set_var("CONSOLE", "stderr") };
112 let target: ConsoleTarget = env_or("CONSOLE", ConsoleTarget::Stdout).into();
113 assert_eq!(target, ConsoleTarget::Stderr);
114 unsafe { std::env::set_var("CONSOLE", "") };
115 let target: ConsoleTarget = env_or("CONSOLE", ConsoleTarget::Stdout).into();
116 assert_eq!(target, ConsoleTarget::Stdout);
117
118 unsafe { std::env::set_var("LOG_PATH", "/tmp/test.log") };
120 let path: PathBuf = env_or("LOG_PATH", "/tmp/other.log").into();
121 assert_eq!(path, Path::new("/tmp/test.log").to_path_buf());
122
123 unsafe { std::env::set_var("LOG_PATH", "") };
124 let path: PathBuf = env_or("LOG_PATH", "/tmp/other.log").into();
125 assert_eq!(path, Path::new("/tmp/other.log").to_path_buf());
126
127 let _builder = recipe::raw_file_logger(env_or("LOG_PATH", "/tmp/other.log"), Level::Info);
128 let _builder =
129 recipe::raw_file_logger(env_or("LOG_PATH", "/tmp/other.log".to_string()), Level::Info);
130 }
131}