1#![forbid(unsafe_code)]
2
3use core::sync::atomic::{AtomicU8, Ordering};
4use std::env;
5use std::fs::{File, OpenOptions};
6use std::io::{self, BufWriter, Write};
7use std::path::Path;
8use std::sync::{Mutex, OnceLock};
9
10#[repr(u8)]
11#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
12pub enum Level {
13 Off = 0,
14 Error = 1,
15 Warn = 2,
16 Notice = 3,
17 Info = 4,
18 Debug = 5,
19 Trace = 6,
20}
21
22impl Level {
23 #[inline]
24 pub fn as_str(self) -> &'static str {
25 match self {
26 Level::Off => "OFF",
27 Level::Error => "ERROR",
28 Level::Warn => "WARN",
29 Level::Notice => "NOTICE",
30 Level::Info => "INFO",
31 Level::Debug => "DEBUG",
32 Level::Trace => "TRACE",
33 }
34 }
35
36 #[inline]
37 pub fn parse(s: &str) -> Option<Self> {
38 match s.trim().to_ascii_lowercase().as_str() {
39 "off" => Some(Level::Off),
40 "error" => Some(Level::Error),
41 "warn" | "warning" => Some(Level::Warn),
42 "notice" => Some(Level::Notice),
43 "info" => Some(Level::Info),
44 "debug" => Some(Level::Debug),
45 "trace" => Some(Level::Trace),
46 _ => None,
47 }
48 }
49}
50
51static RUNTIME_LEVEL: AtomicU8 = AtomicU8::new(Level::Info as u8);
52
53#[inline]
54pub fn set_level(level: Level) {
55 RUNTIME_LEVEL.store(level as u8, Ordering::Relaxed);
56}
57
58#[inline]
59#[must_use]
60pub fn level() -> Level {
61 match RUNTIME_LEVEL.load(Ordering::Relaxed) {
62 0 => Level::Off,
63 1 => Level::Error,
64 2 => Level::Warn,
65 3 => Level::Notice,
66 4 => Level::Info,
67 5 => Level::Debug,
68 _ => Level::Trace,
69 }
70}
71
72pub fn init_from_env(var_name: &str, default: Level) {
85 let level = env::var(var_name)
86 .ok()
87 .and_then(|s| Level::parse(&s))
88 .unwrap_or(default);
89 set_level(level);
90}
91
92pub fn init() {
107 init_from_env("RUST_LOG", Level::Info);
108}
109
110pub fn init_with_default(default: Level) {
112 init_from_env("RUST_LOG", default);
113}
114
115pub const COMPILED_MAX_LEVEL: Level = compiled_max_level();
116
117const fn compiled_max_level() -> Level {
118 #[cfg(feature = "max_trace")]
119 {
120 return Level::Trace;
121 }
122 #[cfg(all(not(feature = "max_trace"), feature = "max_debug"))]
123 {
124 return Level::Debug;
125 }
126 #[cfg(all(
127 not(feature = "max_trace"),
128 not(feature = "max_debug"),
129 feature = "max_info"
130 ))]
131 {
132 return Level::Info;
133 }
134
135 #[cfg(all(
136 not(feature = "max_trace"),
137 not(feature = "max_debug"),
138 not(feature = "max_info"),
139 feature = "max_notice"
140 ))]
141 {
142 return Level::Notice;
143 }
144
145 #[cfg(all(
146 not(feature = "max_trace"),
147 not(feature = "max_debug"),
148 not(feature = "max_info"),
149 not(feature = "max_notice"),
150 feature = "max_warn"
151 ))]
152 {
153 return Level::Warn;
154 }
155 #[cfg(all(
156 not(feature = "max_trace"),
157 not(feature = "max_debug"),
158 not(feature = "max_info"),
159 not(feature = "max_notice"),
160 not(feature = "max_warn"),
161 feature = "max_error"
162 ))]
163 {
164 return Level::Error;
165 }
166
167 #[allow(unreachable_code)]
168 Level::Off
169}
170
171#[inline(always)]
172pub fn enabled(_level: Level) -> bool {
173 #[cfg(feature = "disabled")]
174 {
175 return false;
176 }
177
178 #[cfg(not(feature = "disabled"))]
179 {
180 if (_level as u8) > (COMPILED_MAX_LEVEL as u8) {
181 return false;
182 }
183 RUNTIME_LEVEL.load(Ordering::Relaxed) >= _level as u8
184 }
185}
186
187pub fn init_from_args<I, S>(args: I)
188where
189 I: IntoIterator<Item = S>,
190 S: AsRef<str>,
191{
192 let mut it = args.into_iter();
193 while let Some(arg) = it.next() {
194 let a = arg.as_ref();
195
196 if let Some(v) = a
198 .strip_prefix("--log=")
199 .or_else(|| a.strip_prefix("--log-level="))
200 {
201 if let Some(lvl) = Level::parse(v) {
202 set_level(lvl);
203 }
204 continue;
205 }
206
207 if a == "--log" || a == "--log-level" {
209 if let Some(next) = it.next() {
210 if let Some(lvl) = Level::parse(next.as_ref()) {
211 set_level(lvl);
212 }
213 }
214 continue;
215 }
216 }
217}
218
219enum Sink {
220 Stderr,
221 File(FileSink),
222}
223
224struct FileSink {
225 writer: Mutex<BufWriter<File>>,
226}
227
228impl FileSink {
229 fn new(file: File) -> Self {
230 Self {
231 writer: Mutex::new(BufWriter::new(file)),
232 }
233 }
234
235 fn write(
236 &self,
237 timestamp: &str,
238 level: &str,
239 module: &str,
240 line: u32,
241 msg: core::fmt::Arguments<'_>,
242 ) {
243 let mut writer = match self.writer.lock() {
244 Ok(guard) => guard,
245 Err(poisoned) => poisoned.into_inner(),
246 };
247
248 let _ = writer.write_fmt(format_args!("{} {} {}:{} ", timestamp, level, module, line));
249 let _ = writer.write_fmt(msg);
250 let _ = writer.write_all(b"\n");
251 }
252
253 fn write_with_fields(
254 &self,
255 timestamp: &str,
256 level: &str,
257 module: &str,
258 line: u32,
259 msg: core::fmt::Arguments<'_>,
260 fields: core::fmt::Arguments<'_>,
261 ) {
262 let mut writer = match self.writer.lock() {
263 Ok(guard) => guard,
264 Err(poisoned) => poisoned.into_inner(),
265 };
266
267 let _ = writer.write_fmt(format_args!("{} {} {}:{} ", timestamp, level, module, line));
268 let _ = writer.write_fmt(msg);
269 let _ = writer.write_all(b" ");
270 let _ = writer.write_fmt(fields);
271 let _ = writer.write_all(b"\n");
272 }
273}
274
275static ACTIVE_SINK: OnceLock<Sink> = OnceLock::new();
276
277fn active_sink() -> &'static Sink {
278 ACTIVE_SINK.get_or_init(|| Sink::Stderr)
279}
280
281pub fn set_file_logging(path: impl AsRef<Path>) -> io::Result<()> {
282 configure_file_sink(path.as_ref(), false)
283}
284
285pub fn append_file_logging(path: impl AsRef<Path>) -> io::Result<()> {
286 configure_file_sink(path.as_ref(), true)
287}
288
289fn configure_file_sink(path: &Path, append: bool) -> io::Result<()> {
290 let file = OpenOptions::new()
291 .create(true)
292 .write(true)
293 .append(append)
294 .truncate(!append)
295 .open(path)?;
296
297 let sink = Sink::File(FileSink::new(file));
298 ACTIVE_SINK
299 .set(sink)
300 .map_err(|_| io::Error::new(io::ErrorKind::AlreadyExists, "log sink already initialized"))
301}
302
303struct LevelStyle {
304 ansi: &'static str,
305 display: &'static str,
306 plain: &'static str,
307}
308
309const ERROR_STYLE: LevelStyle = LevelStyle {
310 ansi: "\x1b[91m",
311 display: "ERROR",
312 plain: "ERROR",
313};
314
315const NOTICE_STYLE: LevelStyle = LevelStyle {
316 ansi: "\x1b[95m",
317 display: "NOTICE",
318 plain: "NOTICE",
319};
320
321const WARN_STYLE: LevelStyle = LevelStyle {
322 ansi: "\x1b[93m",
323 display: " WARN",
324 plain: "WARN",
325};
326
327const INFO_STYLE: LevelStyle = LevelStyle {
328 ansi: "\x1b[92m",
329 display: " INFO",
330 plain: "INFO",
331};
332
333const DEBUG_STYLE: LevelStyle = LevelStyle {
334 ansi: "\x1b[96m",
335 display: "DEBUG",
336 plain: "DEBUG",
337};
338
339const TRACE_STYLE: LevelStyle = LevelStyle {
340 ansi: "\x1b[94m",
341 display: "TRACE",
342 plain: "TRACE",
343};
344
345#[inline]
346fn emit_with_style(style: &LevelStyle, msg: core::fmt::Arguments<'_>, _line: u32, _module: &str) {
347 emit_with_style_and_fields(style, msg, None, _line, _module)
348}
349
350#[inline]
351fn emit_with_style_and_fields(
352 style: &LevelStyle,
353 msg: core::fmt::Arguments<'_>,
354 fields: Option<core::fmt::Arguments<'_>>,
355 _line: u32,
356 _module: &str,
357) {
358 #[cfg(not(feature = "disabled"))]
359 {
360 let timestamp = format_timestamp();
361 match active_sink() {
362 Sink::Stderr => {
363 if let Some(fields) = fields {
364 eprintln!(
365 "\x1b[90m{}\x1b[0m {}{}\x1b[0m \x1b[1;37m{}:{}\x1b[0m {} \x1b[36m{}\x1b[0m",
366 timestamp, style.ansi, style.display, _module, _line, msg, fields
367 );
368 } else {
369 eprintln!(
370 "\x1b[90m{}\x1b[0m {}{}\x1b[0m \x1b[1;37m{}:{}\x1b[0m {}",
371 timestamp, style.ansi, style.display, _module, _line, msg
372 );
373 }
374 }
375 Sink::File(file_sink) => {
376 if let Some(fields) = fields {
377 file_sink.write_with_fields(
378 ×tamp,
379 style.plain,
380 _module,
381 _line,
382 msg,
383 fields,
384 );
385 } else {
386 file_sink.write(×tamp, style.plain, _module, _line, msg);
387 }
388 }
389 }
390 }
391}
392
393#[inline]
394fn format_timestamp() -> String {
395 use std::time::{SystemTime, UNIX_EPOCH};
396
397 let duration = SystemTime::now()
398 .duration_since(UNIX_EPOCH)
399 .expect("Time went backwards");
400
401 let secs = duration.as_secs();
402 let micros = duration.subsec_micros();
403
404 let days_since_epoch = secs / 86400;
405 let secs_today = secs % 86400;
406
407 let hours = secs_today / 3600;
408 let minutes = (secs_today % 3600) / 60;
409 let seconds = secs_today % 60;
410
411 let mut year = 1970;
412 let mut days = days_since_epoch;
413
414 loop {
415 let days_in_year = if year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) {
416 366
417 } else {
418 365
419 };
420 if days < days_in_year {
421 break;
422 }
423 days -= days_in_year;
424 year += 1;
425 }
426
427 let is_leap = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
428 let days_in_months = if is_leap {
429 [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
430 } else {
431 [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
432 };
433
434 let mut month = 1;
435 for &days_in_month in &days_in_months {
436 if days < days_in_month {
437 break;
438 }
439 days -= days_in_month;
440 month += 1;
441 }
442 let day = days + 1;
443
444 format!(
445 "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:06}Z",
446 year, month, day, hours, minutes, seconds, micros
447 )
448}
449
450#[cold]
451#[inline(never)]
452#[doc(hidden)]
453pub fn emit_error(_msg: core::fmt::Arguments<'_>, _line: u32, _module: &str) {
454 emit_with_style(&ERROR_STYLE, _msg, _line, _module);
455}
456
457#[cold]
458#[inline(never)]
459#[doc(hidden)]
460pub fn emit_error_with_fields(
461 _msg: core::fmt::Arguments<'_>,
462 _fields: core::fmt::Arguments<'_>,
463 _line: u32,
464 _module: &str,
465) {
466 emit_with_style_and_fields(&ERROR_STYLE, _msg, Some(_fields), _line, _module);
467}
468
469#[cold]
470#[inline(never)]
471#[doc(hidden)]
472pub fn emit_warn(_msg: core::fmt::Arguments<'_>, _line: u32, _module: &str) {
473 emit_with_style(&WARN_STYLE, _msg, _line, _module);
474}
475
476#[cold]
477#[inline(never)]
478#[doc(hidden)]
479pub fn emit_warn_with_fields(
480 _msg: core::fmt::Arguments<'_>,
481 _fields: core::fmt::Arguments<'_>,
482 _line: u32,
483 _module: &str,
484) {
485 emit_with_style_and_fields(&WARN_STYLE, _msg, Some(_fields), _line, _module);
486}
487
488#[cold]
489#[inline(never)]
490#[doc(hidden)]
491pub fn emit_notice(_msg: core::fmt::Arguments<'_>, _line: u32, _module: &str) {
492 emit_with_style(&NOTICE_STYLE, _msg, _line, _module);
493}
494
495#[cold]
496#[inline(never)]
497#[doc(hidden)]
498pub fn emit_notice_with_fields(
499 _msg: core::fmt::Arguments<'_>,
500 _fields: core::fmt::Arguments<'_>,
501 _line: u32,
502 _module: &str,
503) {
504 emit_with_style_and_fields(&NOTICE_STYLE, _msg, Some(_fields), _line, _module);
505}
506
507#[cold]
508#[inline(never)]
509#[doc(hidden)]
510pub fn emit_info(_msg: core::fmt::Arguments<'_>, _line: u32, _module: &str) {
511 emit_with_style(&INFO_STYLE, _msg, _line, _module);
512}
513
514#[cold]
515#[inline(never)]
516#[doc(hidden)]
517pub fn emit_info_with_fields(
518 _msg: core::fmt::Arguments<'_>,
519 _fields: core::fmt::Arguments<'_>,
520 _line: u32,
521 _module: &str,
522) {
523 emit_with_style_and_fields(&INFO_STYLE, _msg, Some(_fields), _line, _module);
524}
525
526#[cold]
527#[inline(never)]
528#[doc(hidden)]
529pub fn emit_debug(_msg: core::fmt::Arguments<'_>, _line: u32, _module: &str) {
530 emit_with_style(&DEBUG_STYLE, _msg, _line, _module);
531}
532
533#[cold]
534#[inline(never)]
535#[doc(hidden)]
536pub fn emit_debug_with_fields(
537 _msg: core::fmt::Arguments<'_>,
538 _fields: core::fmt::Arguments<'_>,
539 _line: u32,
540 _module: &str,
541) {
542 emit_with_style_and_fields(&DEBUG_STYLE, _msg, Some(_fields), _line, _module);
543}
544
545#[cold]
546#[inline(never)]
547#[doc(hidden)]
548pub fn emit_trace(_msg: core::fmt::Arguments<'_>, _line: u32, _module: &str) {
549 emit_with_style(&TRACE_STYLE, _msg, _line, _module);
550}
551
552#[cold]
553#[inline(never)]
554#[doc(hidden)]
555pub fn emit_trace_with_fields(
556 _msg: core::fmt::Arguments<'_>,
557 _fields: core::fmt::Arguments<'_>,
558 _line: u32,
559 _module: &str,
560) {
561 emit_with_style_and_fields(&TRACE_STYLE, _msg, Some(_fields), _line, _module);
562}
563
564#[macro_export]
567#[doc(hidden)]
568macro_rules! __format_fields {
569 () => { "" };
570
571 (? $name:ident) => {
572 format_args!("{}={:?}", stringify!($name), $name)
573 };
574
575 (% $name:ident) => {
576 format_args!("{}={}", stringify!($name), $name)
577 };
578
579 ($key:ident = ? $value:expr) => {
580 format_args!("{}={:?}", stringify!($key), $value)
581 };
582
583 ($key:ident = $value:expr) => {
584 format_args!("{}={}", stringify!($key), $value)
585 };
586
587 (? $name:ident, $($rest:tt)*) => {
588 format_args!("{}={:?} {}", stringify!($name), $name, $crate::__format_fields!($($rest)*))
589 };
590
591 (% $name:ident, $($rest:tt)*) => {
592 format_args!("{}={} {}", stringify!($name), $name, $crate::__format_fields!($($rest)*))
593 };
594
595 ($key:ident = ? $value:expr, $($rest:tt)*) => {
596 format_args!("{}={:?} {}", stringify!($key), $value, $crate::__format_fields!($($rest)*))
597 };
598
599 ($key:ident = $value:expr, $($rest:tt)*) => {
600 format_args!("{}={} {}", stringify!($key), $value, $crate::__format_fields!($($rest)*))
601 };
602}
603
604#[macro_export]
605macro_rules! error {
606 ($msg:literal; $($field:tt)+) => {{
607 if $crate::enabled($crate::Level::Error) {
608 $crate::emit_error_with_fields(
609 format_args!($msg),
610 $crate::__format_fields!($($field)+),
611 line!(),
612 module_path!()
613 );
614 }
615 }};
616
617 ($msg:literal, $($arg:expr),+; $($field:tt)+) => {{
618 if $crate::enabled($crate::Level::Error) {
619 $crate::emit_error_with_fields(
620 format_args!($msg, $($arg),+),
621 $crate::__format_fields!($($field)+),
622 line!(),
623 module_path!()
624 );
625 }
626 }};
627
628 ($msg:literal, ? $($field:tt)+) => {{
629 if $crate::enabled($crate::Level::Error) {
630 $crate::emit_error_with_fields(
631 format_args!($msg),
632 $crate::__format_fields!(? $($field)+),
633 line!(),
634 module_path!()
635 );
636 }
637 }};
638
639 ($msg:literal, % $($field:tt)+) => {{
640 if $crate::enabled($crate::Level::Error) {
641 $crate::emit_error_with_fields(
642 format_args!($msg),
643 $crate::__format_fields!(% $($field)+),
644 line!(),
645 module_path!()
646 );
647 }
648 }};
649
650 ($($arg:tt)+) => {{
651 if $crate::enabled($crate::Level::Error) {
652 $crate::emit_error(format_args!($($arg)+), line!(), module_path!());
653 }
654 }};
655}
656
657#[macro_export]
658macro_rules! warn {
659 ($msg:literal; $($field:tt)+) => {{
660 if $crate::enabled($crate::Level::Warn) {
661 $crate::emit_warn_with_fields(
662 format_args!($msg),
663 $crate::__format_fields!($($field)+),
664 line!(),
665 module_path!()
666 );
667 }
668 }};
669
670 ($msg:literal, $($arg:expr),+; $($field:tt)+) => {{
671 if $crate::enabled($crate::Level::Warn) {
672 $crate::emit_warn_with_fields(
673 format_args!($msg, $($arg),+),
674 $crate::__format_fields!($($field)+),
675 line!(),
676 module_path!()
677 );
678 }
679 }};
680
681 ($msg:literal, ? $($field:tt)+) => {{
682 if $crate::enabled($crate::Level::Warn) {
683 $crate::emit_warn_with_fields(
684 format_args!($msg),
685 $crate::__format_fields!(? $($field)+),
686 line!(),
687 module_path!()
688 );
689 }
690 }};
691
692 ($msg:literal, % $($field:tt)+) => {{
693 if $crate::enabled($crate::Level::Warn) {
694 $crate::emit_warn_with_fields(
695 format_args!($msg),
696 $crate::__format_fields!(% $($field)+),
697 line!(),
698 module_path!()
699 );
700 }
701 }};
702
703 ($($arg:tt)+) => {{
704 if $crate::enabled($crate::Level::Warn) {
705 $crate::emit_warn(format_args!($($arg)+), line!(), module_path!());
706 }
707 }};
708}
709
710#[macro_export]
711macro_rules! notice {
712 ($msg:literal; $($field:tt)+) => {{
713 if $crate::enabled($crate::Level::Notice) {
714 $crate::emit_notice_with_fields(
715 format_args!($msg),
716 $crate::__format_fields!($($field)+),
717 line!(),
718 module_path!()
719 );
720 }
721 }};
722
723 ($msg:literal, $($arg:expr),+; $($field:tt)+) => {{
724 if $crate::enabled($crate::Level::Notice) {
725 $crate::emit_notice_with_fields(
726 format_args!($msg, $($arg),+),
727 $crate::__format_fields!($($field)+),
728 line!(),
729 module_path!()
730 );
731 }
732 }};
733
734 ($msg:literal, ? $($field:tt)+) => {{
735 if $crate::enabled($crate::Level::Notice) {
736 $crate::emit_notice_with_fields(
737 format_args!($msg),
738 $crate::__format_fields!(? $($field)+),
739 line!(),
740 module_path!()
741 );
742 }
743 }};
744
745 ($msg:literal, % $($field:tt)+) => {{
746 if $crate::enabled($crate::Level::Notice) {
747 $crate::emit_notice_with_fields(
748 format_args!($msg),
749 $crate::__format_fields!(% $($field)+),
750 line!(),
751 module_path!()
752 );
753 }
754 }};
755
756 ($($arg:tt)+) => {{
757 if $crate::enabled($crate::Level::Notice) {
758 $crate::emit_notice(format_args!($($arg)+), line!(), module_path!());
759 }
760 }};
761}
762
763#[macro_export]
764macro_rules! info {
765 ($msg:literal; $($field:tt)+) => {{
766 if $crate::enabled($crate::Level::Info) {
767 $crate::emit_info_with_fields(
768 format_args!($msg),
769 $crate::__format_fields!($($field)+),
770 line!(),
771 module_path!()
772 );
773 }
774 }};
775
776 ($msg:literal, $($arg:expr),+; $($field:tt)+) => {{
777 if $crate::enabled($crate::Level::Info) {
778 $crate::emit_info_with_fields(
779 format_args!($msg, $($arg),+),
780 $crate::__format_fields!($($field)+),
781 line!(),
782 module_path!()
783 );
784 }
785 }};
786
787 ($msg:literal, ? $($field:tt)+) => {{
788 if $crate::enabled($crate::Level::Info) {
789 $crate::emit_info_with_fields(
790 format_args!($msg),
791 $crate::__format_fields!(? $($field)+),
792 line!(),
793 module_path!()
794 );
795 }
796 }};
797
798 ($msg:literal, % $($field:tt)+) => {{
799 if $crate::enabled($crate::Level::Info) {
800 $crate::emit_info_with_fields(
801 format_args!($msg),
802 $crate::__format_fields!(% $($field)+),
803 line!(),
804 module_path!()
805 );
806 }
807 }};
808
809 ($($arg:tt)+) => {{
810 if $crate::enabled($crate::Level::Info) {
811 $crate::emit_info(format_args!($($arg)+), line!(), module_path!());
812 }
813 }};
814}
815
816#[macro_export]
817macro_rules! debug {
818 ($msg:literal; $($field:tt)+) => {{
819 if $crate::enabled($crate::Level::Debug) {
820 $crate::emit_debug_with_fields(
821 format_args!($msg),
822 $crate::__format_fields!($($field)+),
823 line!(),
824 module_path!()
825 );
826 }
827 }};
828
829 ($msg:literal, $($arg:expr),+; $($field:tt)+) => {{
830 if $crate::enabled($crate::Level::Debug) {
831 $crate::emit_debug_with_fields(
832 format_args!($msg, $($arg),+),
833 $crate::__format_fields!($($field)+),
834 line!(),
835 module_path!()
836 );
837 }
838 }};
839
840 ($msg:literal, ? $($field:tt)+) => {{
841 if $crate::enabled($crate::Level::Debug) {
842 $crate::emit_debug_with_fields(
843 format_args!($msg),
844 $crate::__format_fields!(? $($field)+),
845 line!(),
846 module_path!()
847 );
848 }
849 }};
850
851 ($msg:literal, % $($field:tt)+) => {{
852 if $crate::enabled($crate::Level::Debug) {
853 $crate::emit_debug_with_fields(
854 format_args!($msg),
855 $crate::__format_fields!(% $($field)+),
856 line!(),
857 module_path!()
858 );
859 }
860 }};
861
862 ($($arg:tt)+) => {{
863 if $crate::enabled($crate::Level::Debug) {
864 $crate::emit_debug(format_args!($($arg)+), line!(), module_path!());
865 }
866 }};
867}
868
869#[macro_export]
870macro_rules! trace {
871 ($msg:literal; $($field:tt)+) => {{
872 if $crate::enabled($crate::Level::Trace) {
873 $crate::emit_trace_with_fields(
874 format_args!($msg),
875 $crate::__format_fields!($($field)+),
876 line!(),
877 module_path!()
878 );
879 }
880 }};
881
882 ($msg:literal, $($arg:expr),+; $($field:tt)+) => {{
883 if $crate::enabled($crate::Level::Trace) {
884 $crate::emit_trace_with_fields(
885 format_args!($msg, $($arg),+),
886 $crate::__format_fields!($($field)+),
887 line!(),
888 module_path!()
889 );
890 }
891 }};
892
893 ($msg:literal, ? $($field:tt)+) => {{
894 if $crate::enabled($crate::Level::Trace) {
895 $crate::emit_trace_with_fields(
896 format_args!($msg),
897 $crate::__format_fields!(? $($field)+),
898 line!(),
899 module_path!()
900 );
901 }
902 }};
903
904 ($msg:literal, % $($field:tt)+) => {{
905 if $crate::enabled($crate::Level::Trace) {
906 $crate::emit_trace_with_fields(
907 format_args!($msg),
908 $crate::__format_fields!(% $($field)+),
909 line!(),
910 module_path!()
911 );
912 }
913 }};
914
915 ($($arg:tt)+) => {{
916 if $crate::enabled($crate::Level::Trace) {
917 $crate::emit_trace(format_args!($($arg)+), line!(), module_path!());
918 }
919 }};
920}