1use std::io::{self, Write};
2use std::path::Path;
3
4use chrono::Utc;
5use colored::Colorize;
6use env_logger::fmt::{style, Formatter};
7use log::{
8 kv::{Error, Key, Value, VisitSource},
9 Level, Record,
10};
11
12pub use log::{debug, error, info, trace, warn as warning};
13
14#[derive(
16 Clone,
17 Copy,
18 Debug,
19 Default,
20 strum_macros::Display,
21 strum_macros::EnumString,
22 strum_macros::FromRepr,
23)]
24pub enum SDKLogLevel {
25 Error = 1,
26 Warning,
27 #[default]
28 Info,
29 Debug,
30 Trace,
31}
32static LOG_ENV_VAR: &str = "CELP_LOG";
33
34impl SDKLogLevel {
36 pub const MAX: Self = SDKLogLevel::Trace;
38
39 pub const MIN: Self = SDKLogLevel::Error;
41}
42
43pub fn init_logger(module_name: &str, log_level: Option<SDKLogLevel>) {
60 let log_level = match log_level.unwrap_or_default() {
61 SDKLogLevel::Error => Level::Error,
62 SDKLogLevel::Warning => Level::Warn,
63 SDKLogLevel::Info => Level::Info,
64 SDKLogLevel::Debug => Level::Debug,
65 SDKLogLevel::Trace => Level::Trace,
66 }
67 .to_level_filter();
68
69 env_logger::Builder::from_env(LOG_ENV_VAR)
70 .filter_level(log_level)
73 .filter_module(module_name, log_level)
74 .target(env_logger::Target::Stdout)
75 .format(format_log_str)
76 .init();
77}
78
79fn format_log_str(buf: &mut Formatter, record: &Record) -> Result<(), io::Error> {
83 let now = Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Micros, true);
84
85 let filename = record.file().unwrap_or("Unknown file path");
86 let path = Path::new(filename);
87 let file = path
88 .file_name()
89 .and_then(|s| s.to_str())
90 .unwrap_or("<unknown>");
91
92 let line = record.line().unwrap_or(0);
93
94 let sdk_log_level = record.level();
95 let level = match sdk_log_level {
97 Level::Error => String::from("E").red(),
98 Level::Warn => String::from("W").yellow(),
99 Level::Info => String::from("I").green(),
100 Level::Debug => String::from("D").blue(),
101 Level::Trace => String::from("T").white(),
102 };
103
104 let args = record.args();
105
106 write!(buf, "[{now}] [{file}:{line}] [---{level}---] {args:?}")?;
109
110 record
111 .key_values()
112 .visit(&mut KvSourceVisitor(buf))
113 .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
114
115 writeln!(buf)?;
116
117 Ok(())
118}
119
120struct KvSourceVisitor<'a>(&'a mut Formatter);
121
122impl<'kvs> VisitSource<'kvs> for KvSourceVisitor<'_> {
123 fn visit_pair(&mut self, key: Key<'_>, value: Value<'kvs>) -> Result<(), Error> {
124 let style = style::Style::new().italic();
125
126 write!(self.0, "{style}")?;
127 write!(self.0, " {}={}", key, value)?;
128 write!(self.0, "{style:#}")?;
129 Ok(())
130 }
131}