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