1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
//! Provides macros used for logging messages on-chain, with
//! the ability to provide "trace level" logging messages.
//!
//! In addition to this, the trace level logging messages utilizes
//! stack based formatting if the message size is less than 512 bytes
//! for maximal compute units consumption efficiency
/// msg_panic! is a wrapper around the `msg!` and `panic!`
/// macros used to log an error message, and panic in bpf environments
/// which do not actually show a message emitted by a panic macro
#[macro_export]
macro_rules! msg_panic {
($($args:tt)+) => {{
// the actual error message
solana_program::msg!("RUNTIME ERROR: {}", format_args!($($args)*));
// panic to indicate the line the error came from
// but panicking doesn't log anything in bpf target for solana programs
panic!("RUNTIME ERROR: {}", format_args!($($args)*));
}};
}
#[macro_export]
macro_rules! sum {
// this delcares an exrpession i think :shrug:
// todo(): explain this more
($($args:expr),*) => {{
let mut result = 0;
$(
// combine the size of each value
result = result + $args.len();
)*
// return the size of all arguments
result
}}
}
/// msg_trace! is a wrapper around the `msg!` macro, that faciliates logging trace
/// level logs, which include the file and line number from where the message was emitted.
///
/// if the total msg size is less than or equal to 512 bytes, then `arrform!` is used for
/// the optimize (heap-less) message formatting. messages larger than 512 bytes use the traditional `format!`.
#[macro_export]
macro_rules! msg_trace {
($($args:tt)+) => {
// get the filename that produce the log, it's less info than the fille path
// but it saves pace, an when paired with the line number is more than enough debug
let file_name = std::path::Path::new(file!()).file_name().unwrap().to_string_lossy();
let input_sizes = sum!($($args)*);
solana_program::msg!("input sizes {}", input_sizes);
if input_sizes > 512 {
// slow path
solana_program::msg!("{}", format!("'{}', '{}:{}", format!($($args)*), file_name, line!()).as_str());
} else {
use tulip_arrform::{arrform, ArrForm};
let file_info = arrform!(256, "{}:{}", file_name, line!());
let msg_part = arrform!(512, $($args)*);
solana_program::msg!("'{}', {}", msg_part.as_str(), file_info.as_str());
}
};
}
#[cfg(test)]
mod test {
use super::*;
use solana_program::msg;
#[test]
fn test_trace() {
{
msg_trace!("hello world this is {}", "very big message");
}
{
let mut msg_str = String::new();
for _ in 0..550 {
msg_str.push('a');
}
msg_trace!("{}", msg_str);
}
}
#[test]
#[should_panic(expected = "RUNTIME ERROR: too many keks")]
fn test_msg_panic() {
msg_panic!("too many keks");
}
}