1#![forbid(unsafe_code, future_incompatible, rust_2018_idioms)]
2#![deny(missing_debug_implementations, nonstandard_style)]
3#![warn(missing_docs, missing_doc_code_examples, unreachable_pub)]
4#![allow(dead_code)]
5
6use log::kv::{Error, Key, Value, Visitor};
22use log::{Log, Metadata, Record, SetLoggerError};
23use std::io::Write;
24use std::net::UdpSocket;
25
26pub use log::Level;
28
29pub use log::LevelFilter;
31
32pub const STATIC_MAX_LEVEL: LevelFilter = log::STATIC_MAX_LEVEL;
34
35#[inline]
37pub fn max_level() -> LevelFilter {
38 log::max_level()
39}
40
41#[macro_export(local_inner_macros)]
78macro_rules! log {
79 (target: $target:expr, kvs: $kvs:expr, $lvl:expr, $($arg:tt)+) => ({
80 let lvl = $lvl;
81 if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
82 $crate::__private_api_log(
83 __log_format_args!($($arg)+),
84 lvl,
85 &($target, __log_module_path!(), __log_file!(), __log_line!()),
86 Some($kvs),
87 );
88 }
89 });
90 (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
91 let lvl = $lvl;
92 if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
93 $crate::__private_api_log(
94 __log_format_args!($($arg)+),
95 lvl,
96 &($target, __log_module_path!(), __log_file!(), __log_line!()),
97 None,
98 );
99 }
100 });
101 (kvs: $kvs:expr, $lvl:expr, $($arg:tt)+) => ({
102 (log!(target: __log_module_path!(), kvs: $kvs, $lvl, $($arg)+)) });
103
104 ($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+))
105}
106
107#[macro_export(local_inner_macros)]
108#[doc(hidden)]
109macro_rules! log_impl {
110 (target: $target:expr, kvs: $kvs:expr, $lvl:expr, ($($arg:expr),*)) => {{
112 let lvl = $lvl;
113 if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
114 $crate::__private_api_log(
115 __log_format_args!($($arg),*),
116 lvl,
117 &($target, __log_module_path!(), __log_file!(), __log_line!()),
118 $kvs,
119 );
120 }
121 }};
122}
123
124#[macro_export(local_inner_macros)]
126macro_rules! trace {
127 (target: $target:expr, kvs: $kvs:expr, $($arg:tt)+) => (
128 log!(target: $target, kvs: $kvs, $crate::Level::Trace, $($arg)+);
129 );
130 (target: $target:expr, $($arg:tt)+) => (
131 log!(target: $target, $crate::Level::Trace, $($arg)+);
132 );
133 (kvs: $kvs:expr, $($arg:tt)+) => (
134 log!(kvs: $kvs, $crate::Level::Trace, $($arg)+);
135 );
136 ($($arg:tt)+) => (
137 log!($crate::Level::Trace, $($arg)+);
138 )
139}
140
141#[macro_export(local_inner_macros)]
143macro_rules! debug {
144 (target: $target:expr, kvs: $kvs:expr, $($arg:tt)+) => (
145 log!(target: $target, kvs: $kvs, $crate::Level::Debug, $($arg)+);
146 );
147 (target: $target:expr, $($arg:tt)+) => (
148 log!(target: $target, $crate::Level::Debug, $($arg)+);
149 );
150 (kvs: $kvs:expr, $($arg:tt)+) => (
151 log!(kvs: $kvs, $crate::Level::Debug, $($arg)+);
152 );
153 ($($arg:tt)+) => (
154 log!($crate::Level::Debug, $($arg)+);
155 )
156}
157
158#[macro_export(local_inner_macros)]
160macro_rules! info {
161 (target: $target:expr, kvs: $kvs:expr, $($arg:tt)+) => (
162 log!(target: $target, kvs: $kvs, $crate::Level::Info, $($arg)+);
163 );
164 (target: $target:expr, $($arg:tt)+) => (
165 log!(target: $target, $crate::Level::Info, $($arg)+);
166 );
167 (kvs: $kvs:expr, $($arg:tt)+) => (
168 log!(kvs: $kvs, $crate::Level::Info, $($arg)+);
169 );
170 ($($arg:tt)+) => (
171 log!($crate::Level::Info, $($arg)+);
172 )
173}
174
175#[macro_export(local_inner_macros)]
177macro_rules! warn {
178 (target: $target:expr, kvs: $kvs:expr, $($arg:tt)+) => (
179 log!(target: $target, kvs: $kvs, $crate::Level::Warn, $($arg)+);
180 );
181 (target: $target:expr, $($arg:tt)+) => (
182 log!(target: $target, $crate::Level::Warn, $($arg)+);
183 );
184 (kvs: $kvs:expr, $($arg:tt)+) => (
185 log!(kvs: $kvs, $crate::Level::Warn, $($arg)+);
186 );
187 ($($arg:tt)+) => (
188 log!($crate::Level::Warn, $($arg)+);
189 )
190}
191
192#[macro_export(local_inner_macros)]
194macro_rules! error {
195 (target: $target:expr, kvs: $kvs:expr, $($arg:tt)+) => (
196 log!(target: $target, kvs: $kvs, $crate::Level::Error, $($arg)+);
197 );
198 (target: $target:expr, $($arg:tt)+) => (
199 log!(target: $target, $crate::Level::Error, $($arg)+);
200 );
201 (kvs: $kvs:expr, $($arg:tt)+) => (
202 log!(kvs: $kvs, $crate::Level::Error, $($arg)+);
203 );
204 ($($arg:tt)+) => (
205 log!($crate::Level::Error, $($arg)+);
206 )
207}
208
209#[macro_export(local_inner_macros)]
212macro_rules! log_enabled {
213 (target: $target:expr, $lvl:expr) => {{
214 let lvl = $lvl;
215 lvl <= $crate::STATIC_MAX_LEVEL
216 && lvl <= $crate::max_level()
217 && $crate::__private_api_enabled(lvl, $target)
218 }};
219 ($lvl:expr) => {
220 log_enabled!(target: __log_module_path!(), $lvl)
221 };
222}
223
224#[doc(hidden)]
225#[macro_export]
226macro_rules! __log_format_args {
227 ($($args:tt)*) => {
228 format_args!($($args)*)
229 };
230}
231
232#[doc(hidden)]
233#[macro_export]
234macro_rules! __log_module_path {
235 () => {
236 module_path!()
237 };
238}
239
240#[doc(hidden)]
241#[macro_export]
242macro_rules! __log_file {
243 () => {
244 file!()
245 };
246}
247
248#[doc(hidden)]
249#[macro_export]
250macro_rules! __log_line {
251 () => {
252 line!()
253 };
254}
255
256#[doc(hidden)]
258pub fn __private_api_log(
259 args: std::fmt::Arguments<'_>,
260 level: log::Level,
261 &(target, module_path, file, line): &(&str, &'static str, &'static str, u32),
262 kvs: Option<&dyn log::kv::Source>,
263) {
264 log::logger().log(
265 &log::Record::builder()
266 .args(args)
267 .level(level)
268 .target(target)
269 .module_path_static(Some(module_path))
270 .file_static(Some(file))
271 .line(Some(line))
272 .key_values(&kvs)
273 .build(),
274 );
275}
276
277#[derive(Debug)]
302pub enum WireFmt {
303 Uncompressed,
305 ByteBuffer,
307}
308
309#[derive(Debug)]
311pub struct UdpLogger {
312 default_level: LevelFilter,
313 module_levels: Vec<(String, LevelFilter)>,
314 default_source: UdpSocket,
315 sources: Vec<(LevelFilter, UdpSocket)>,
316 default_destination: String,
317 destinations: Vec<(LevelFilter, String)>,
318 wire_fmt: WireFmt,
319}
320
321impl UdpLogger {
322 #[must_use = "You must call init() to begin logging"]
335 pub fn new() -> Self {
336 let socket = UdpSocket::bind("127.0.0.1:4000").expect("unable to bind to socket");
337 socket
338 .set_nonblocking(true)
339 .expect("unable to set socket non-blocking");
340
341 Self {
342 default_level: LevelFilter::Trace,
343 module_levels: Vec::new(),
344 default_source: socket,
345 sources: Vec::new(),
346 default_destination: "127.0.0.1:4010".to_string(),
347 destinations: Vec::new(),
348 wire_fmt: WireFmt::Uncompressed,
349 }
350 }
351
352 #[must_use = "You must call init() to begin logging"]
359 pub fn env(mut self) -> Self {
360 if let Ok(level) = std::env::var("RUST_LOG") {
361 match level.to_lowercase().as_str() {
362 "trace" => self.default_level = log::LevelFilter::Trace,
363 "debug" => self.default_level = log::LevelFilter::Debug,
364 "info" => self.default_level = log::LevelFilter::Info,
365 "warn" => self.default_level = log::LevelFilter::Warn,
366 "error" => self.default_level = log::LevelFilter::Error,
367 _ => (),
368 }
369 };
370 self
371 }
372
373 #[must_use = "You must call init() to begin logging"]
379 pub fn with_level(mut self, level: LevelFilter) -> Self {
380 self.default_level = level;
381 self
382 }
383
384 #[must_use = "You must call init() to begin logging"]
415 pub fn with_module_level(mut self, target: &str, level: LevelFilter) -> Self {
416 self.module_levels.push((target.to_string(), level));
417
418 #[cfg(test)]
420 self.module_levels
421 .sort_by_key(|(name, _level)| name.len().wrapping_neg());
422
423 self
424 }
425
426 #[must_use = "You must call init() to begin logging"]
443 pub fn with_source(mut self, source: &str) -> Self {
444 let socket = UdpSocket::bind(source).expect("unable to bind to socket");
445 socket
446 .set_nonblocking(true)
447 .expect("unable to set socket non-blocking");
448 self.default_source = socket;
449
450 self
451 }
452
453 #[must_use = "You must call init() to begin logging"]
473 pub fn with_source_level(mut self, source: &str, level: LevelFilter) -> Self {
474 let socket = UdpSocket::bind(source).expect("unable to bind to socket");
475 socket
476 .set_nonblocking(true)
477 .expect("unable to set socket non-blocking");
478 self.sources.push((level, socket));
479
480 self
481 }
482
483 #[must_use = "You must call init() to begin logging"]
500 pub fn with_destination(mut self, destination: &str) -> Self {
501 self.default_destination = destination.to_string();
502
503 self
504 }
505
506 #[must_use = "You must call init() to begin logging"]
525 pub fn with_destination_level(mut self, destination: &str, level: LevelFilter) -> Self {
526 self.destinations.push((level, destination.to_string()));
527
528 self
529 }
530
531 #[must_use = "You must call init() to begin logging"]
533 pub fn with_wire_fmt(mut self, wire_fmt: WireFmt) -> Self {
534 self.wire_fmt = wire_fmt;
535
536 self
537 }
538
539 #[doc(hidden)]
540 pub fn partial_init(mut self) -> Self {
542 self.module_levels
546 .sort_by_key(|(name, _level)| name.len().wrapping_neg());
547 let max_level = self
548 .module_levels
549 .iter()
550 .map(|(_name, level)| level)
551 .copied()
552 .max();
553 let max_level = max_level
554 .map(|lvl| lvl.max(self.default_level))
555 .unwrap_or(self.default_level);
556
557 self.sources.sort_by_key(|(level, _socket)| *level);
558 self.destinations.sort_by_key(|(level, _socket)| *level);
559 log::set_max_level(max_level);
560
561 self
562 }
563 pub fn init(self) -> Result<(), SetLoggerError> {
566 let logger = self.partial_init();
567 log::set_boxed_logger(Box::new(logger))?;
568 Ok(())
569 }
570}
571
572impl Default for UdpLogger {
573 fn default() -> Self {
575 UdpLogger::new()
576 }
577}
578
579#[derive(Default)]
580struct KVAccumulator(String);
581
582impl<'kvs> Visitor<'kvs> for KVAccumulator {
583 fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {
584 self.0.push_str(&format!(" {}={}", key, value));
585 Ok(())
586 }
587}
588
589impl Log for UdpLogger {
590 fn enabled(&self, metadata: &Metadata<'_>) -> bool {
591 &metadata.level().to_level_filter()
592 <= self
593 .module_levels
594 .iter()
595 .find(|(name, _level)| metadata.target().starts_with(name))
599 .map(|(_name, level)| level)
600 .unwrap_or(&self.default_level)
601 }
602
603 fn log(&self, record: &Record<'_>) {
604 if self.enabled(record.metadata()) {
605 let socket = self
606 .sources
607 .iter()
608 .find(|(level, _socket)| level >= &record.level())
609 .map(|(_level, socket)| socket)
610 .unwrap_or_else(|| &self.default_source);
611
612 let remote_addr = self
613 .destinations
614 .iter()
615 .find(|(level, _socket)| level >= &record.level())
616 .map(|(_level, socket)| socket)
617 .unwrap_or_else(|| &self.default_destination);
618
619 let target = if !record.target().is_empty() {
620 record.target()
621 } else {
622 record.module_path().unwrap_or_default()
623 };
624 let source = record.key_values();
625 let mut visitor = KVAccumulator::default();
626 let _result = source.visit(&mut visitor);
627
628 let result = match self.wire_fmt {
629 WireFmt::Uncompressed => {
630 let payload = format!(
631 "{} {:<5} [{}] {}{}",
632 chrono::Utc::now().format("%Y-%m-%d %H:%M:%S%.3f"),
633 record.level().to_string(),
634 target,
635 record.args(),
636 visitor.0
637 );
638 socket.send_to(payload.as_bytes(), remote_addr)
639 }
640 WireFmt::ByteBuffer => {
641 let mut encoder = bytebuffer::ByteBuffer::new();
642 let level: [u8; 1] = match record.level() {
643 Level::Error => [1],
644 Level::Warn => [2],
645 Level::Info => [3],
646 Level::Debug => [4],
647 Level::Trace => [5],
648 };
649 let now = chrono::Utc::now().timestamp_millis().to_be_bytes();
650 let text = format!("[{}] {}{}", target, record.args(), visitor.0);
651 encoder
652 .write(&level)
653 .and_then(|_count| encoder.write(&now))
654 .and_then(|_count| {
655 encoder.write_string(&text);
656 socket.send_to(&encoder.to_bytes(), remote_addr)
657 })
658 }
659 };
660 match result {
661 Ok(_) => (),
662 Err(err) => {
663 println!("error sending payload, err={}", err)
664 }
665 };
666 }
667 }
668
669 fn flush(&self) {}
670}