Skip to main content

iota_common/
logging.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use once_cell::sync::Lazy;
6
7use crate::in_test_configuration;
8
9#[macro_export]
10macro_rules! fatal {
11    ($($arg:tt)*) => {{
12        tracing::error!(fatal = true, $($arg)*);
13        panic!($($arg)*);
14    }};
15}
16
17#[inline(always)]
18pub fn crash_on_debug() -> bool {
19    static CRASH_ON_DEBUG: Lazy<bool> = Lazy::new(|| {
20        in_test_configuration() || std::env::var("IOTA_ENABLE_DEBUG_ASSERTIONS").is_ok()
21    });
22
23    *CRASH_ON_DEBUG
24}
25
26#[cfg(not(target_arch = "wasm32"))]
27#[macro_export]
28macro_rules! debug_fatal {
29    ($($arg:tt)*) => {{
30        if $crate::logging::crash_on_debug() {
31            $crate::fatal!($($arg)*);
32        } else {
33            let stacktrace = std::backtrace::Backtrace::capture();
34            tracing::error!(debug_fatal = true, stacktrace = ?stacktrace, $($arg)*);
35            let location = concat!(file!(), ':', line!());
36            if let Some(metrics) = iota_metrics::get_metrics() {
37                metrics.system_invariant_violations.with_label_values(&[location]).inc();
38            }
39        }
40    }};
41}
42
43// `iota-metrics` isn't available on wasm32; same macro without the metrics
44// callout.
45#[cfg(target_arch = "wasm32")]
46#[macro_export]
47macro_rules! debug_fatal {
48    ($($arg:tt)*) => {{
49        if $crate::logging::crash_on_debug() {
50            $crate::fatal!($($arg)*);
51        } else {
52            tracing::error!(debug_fatal = true, $($arg)*);
53        }
54    }};
55}
56
57mod tests {
58    #[test]
59    #[should_panic]
60    fn test_fatal() {
61        fatal!("This is a fatal error");
62    }
63
64    #[test]
65    #[should_panic]
66    fn test_debug_fatal() {
67        if cfg!(debug_assertions) {
68            debug_fatal!("This is a debug fatal error");
69        } else {
70            // pass in release mode as well
71            fatal!("This is a fatal error");
72        }
73    }
74
75    #[cfg(not(debug_assertions))]
76    #[test]
77    fn test_debug_fatal_release_mode() {
78        debug_fatal!("This is a debug fatal error");
79    }
80}