Skip to main content

tuwunel_core/
debug.rs

1use std::{any::Any, env, panic, sync::LazyLock};
2
3use tracing::Level;
4// Export debug proc_macros
5pub use tuwunel_macros::recursion_depth;
6
7// Export all of the ancillary tools from here as well.
8pub use crate::{result::DebugInspect, utils::debug::*};
9
10/// Log event at given level in debug-mode (when debug-assertions are enabled).
11/// In release-mode it becomes DEBUG level, and possibly subject to elision.
12#[macro_export]
13#[collapse_debuginfo(yes)]
14macro_rules! debug_event {
15	( $level:expr_2021, $($x:tt)+ ) => {
16		if $crate::debug::logging() {
17			::tracing::event!( $level, _debug = true, $($x)+ )
18		} else {
19			::tracing::debug!( $($x)+ )
20		}
21	}
22}
23
24/// Log message at the ERROR level in debug-mode (when debug-assertions are
25/// enabled). In release-mode it becomes DEBUG level, and possibly subject to
26/// elision.
27#[macro_export]
28macro_rules! debug_error {
29	( $($x:tt)+ ) => {
30		$crate::debug_event!(::tracing::Level::ERROR, $($x)+ )
31	}
32}
33
34/// Log message at the WARN level in debug-mode (when debug-assertions are
35/// enabled). In release-mode it becomes DEBUG level, and possibly subject to
36/// elision.
37#[macro_export]
38macro_rules! debug_warn {
39	( $($x:tt)+ ) => {
40		$crate::debug_event!(::tracing::Level::WARN, $($x)+ )
41	}
42}
43
44/// Log message at the INFO level in debug-mode (when debug-assertions are
45/// enabled). In release-mode it becomes DEBUG level, and possibly subject to
46/// elision.
47#[macro_export]
48macro_rules! debug_info {
49	( $($x:tt)+ ) => {
50		$crate::debug_event!(::tracing::Level::INFO, $($x)+ )
51	}
52}
53
54pub const INFO_SPAN_LEVEL: Level = if logging() { Level::INFO } else { Level::DEBUG };
55
56pub static DEBUGGER: LazyLock<bool> =
57	LazyLock::new(|| env::var("_").unwrap_or_default().ends_with("gdb"));
58
59#[cfg_attr(debug_assertions, crate::ctor)]
60#[cfg_attr(not(debug_assertions), allow(dead_code))]
61fn set_panic_trap() {
62	if !*DEBUGGER {
63		return;
64	}
65
66	let next = panic::take_hook();
67	panic::set_hook(Box::new(move |info| {
68		panic_handler(info, &next);
69	}));
70}
71
72#[cold]
73#[inline(never)]
74pub fn panic_handler(info: &panic::PanicHookInfo<'_>, next: &dyn Fn(&panic::PanicHookInfo<'_>)) {
75	trap();
76	next(info);
77}
78
79#[inline(always)]
80pub fn trap() {
81	#[cfg(core_intrinsics)]
82	//SAFETY: embeds llvm intrinsic for hardware breakpoint
83	unsafe {
84		std::intrinsics::breakpoint();
85	}
86
87	#[cfg(all(not(core_intrinsics), target_arch = "x86_64"))]
88	//SAFETY: embeds instruction for hardware breakpoint
89	unsafe {
90		std::arch::asm!("int3");
91	}
92}
93
94#[must_use]
95pub fn panic_str(p: &Box<dyn Any + Send + 'static>) -> &'static str {
96	(**p)
97		.downcast_ref::<&str>()
98		.copied()
99		.unwrap_or_default()
100}
101
102#[inline(always)]
103#[must_use]
104pub fn rttype_name<T: ?Sized>(_: &T) -> &'static str { type_name::<T>() }
105
106#[inline(always)]
107#[must_use]
108pub fn type_name<T: ?Sized>() -> &'static str { std::any::type_name::<T>() }
109
110/// Returns true if debug logging is enabled. In this mode extra logging calls
111/// are made at all log levels, not just DEBUG and TRACE. These logs are demoted
112/// to DEBUG level when this function returns false; as a consequence they will
113/// be elided by `release_max_log_level` when featured.
114#[must_use]
115#[inline]
116pub const fn logging() -> bool {
117	cfg!(debug_assertions)
118		|| cfg!(tuwunel_debug_logging)
119		|| !cfg!(feature = "release_max_log_level")
120}