1use std::sync::Mutex;
2
3pub use ::slog;
4use format::LogFormat;
5use once_cell::sync::Lazy;
6use slog::{o, Drain, FnValue, Logger, PushFnValue, Record};
7
8pub static LOGGER: Lazy<slog::Logger> = Lazy::new(new_logger);
9
10pub fn new_logger() -> Logger {
11 match LogFormat::from_env() {
12 LogFormat::PlainText => {
13 let decorator = slog_term::PlainDecorator::new(std::io::stdout());
14 let drain = slog_term::FullFormat::new(decorator).build().fuse();
15 let drain = slog_async::Async::new(drain).chan_size(1000).build().fuse();
16 let drain = slog_envlogger::new(drain).fuse();
17 let drain = Mutex::new(drain).map(slog::Fuse);
18 slog::Logger::root(drain, o!())
19 }
20 LogFormat::Json => {
21 let drain = slog_json::Json::new(std::io::stdout()).build().fuse();
22 let drain = slog_async::Async::new(drain).chan_size(1000).build().fuse();
23 let drain = slog_envlogger::new(drain).fuse();
24 let drain = Mutex::new(drain).map(slog::Fuse);
25 slog::Logger::root(
26 drain,
27 o!(
28 "ts" => PushFnValue(move |_: &Record, ser| {
29 ser.emit(chrono::Local::now().to_rfc3339())
30 }),
31 "lvl" => FnValue(move |rec: &Record| {
32 rec.level().as_short_str()
33 }),
34 "msg" => PushFnValue(move |rec: &Record, ser| {
35 ser.emit(rec.msg())
36 }),
37 ),
38 )
39 }
40 }
41}
42
43#[macro_export]
44macro_rules! trace(
45 (#$tag:expr, $($args:tt)+) => {
46 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Trace, $tag, $($args)+)
47 };
48 ($($args:tt)+) => {
49 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Trace, "", $($args)+)
50 };
51);
52
53#[macro_export]
54macro_rules! debug(
55 (#$tag:expr, $($args:tt)+) => {
56 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Debug, $tag, $($args)+)
57 };
58 ($($args:tt)+) => {
59 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Debug, "", $($args)+)
60 };
61);
62
63#[macro_export]
64macro_rules! info(
65 (#$tag:expr, $($args:tt)+) => {
66 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Info, $tag, $($args)+)
67 };
68 ($($args:tt)+) => {
69 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Info, "", $($args)+)
70 };
71);
72
73#[macro_export]
74macro_rules! warn(
75 (#$tag:expr, $($args:tt)+) => {
76 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Warning, $tag, $($args)+)
77 };
78 ($($args:tt)+) => {
79 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Warning, "", $($args)+)
80 };
81);
82
83#[macro_export]
84macro_rules! error(
85 (#$tag:expr, $($args:tt)+) => {
86 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Error, $tag, $($args)+)
87 };
88 ($($args:tt)+) => {
89 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Error, "", $($args)+)
90 };
91);
92
93#[macro_export]
94macro_rules! crit(
95 (#$tag:expr, $($args:tt)+) => {
96 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Critical, $tag, $($args)+)
97 };
98 ($($args:tt)+) => {
99 $crate::slog::log!($crate::LOGGER, $crate::slog::Level::Critical, "", $($args)+)
100 };
101);
102
103mod format {
104 use std::env;
105
106 #[derive(Copy, Clone)]
107 pub(crate) enum LogFormat {
108 PlainText,
109 Json,
110 }
111
112 impl Default for LogFormat {
113 fn default() -> Self {
114 Self::Json
115 }
116 }
117
118 impl<S: AsRef<str>> From<S> for LogFormat {
119 fn from(s: S) -> Self {
120 match s.as_ref() {
121 "plain" => Self::PlainText,
122 "json" => Self::Json,
123 "" => Default::default(),
124 _ => panic!("Unrecognized {} value: '{}'", Self::ENV_NAME, s.as_ref()),
125 }
126 }
127 }
128
129 impl LogFormat {
130 const ENV_NAME: &'static str = "RUST_LOG_FORMAT";
131
132 pub(crate) fn from_env() -> Self {
133 Self::from(env::var(Self::ENV_NAME).ok().unwrap_or_default())
134 }
135 }
136}
137
138#[test]
139fn test_simple_info() {
140 info!("test"; "q" => 2);
141 info!("test");
142}