| 1 | //! Debugging helpers to handle `WAYLAND_DEBUG` env variable. |
| 2 | |
| 3 | use std::{ |
| 4 | fmt::Display, |
| 5 | os::unix::io::AsRawFd, |
| 6 | time::{SystemTime, UNIX_EPOCH}, |
| 7 | }; |
| 8 | |
| 9 | use crate::protocol::Argument; |
| 10 | |
| 11 | /// The `WAYLAND_DEBUG` env variable is set to debug client. |
| 12 | pub fn has_debug_client_env() -> bool { |
| 13 | matches!(std::env::var_os("WAYLAND_DEBUG" ), Some(str) if str == "1" || str == "client" ) |
| 14 | } |
| 15 | |
| 16 | /// Print the dispatched message to stderr in a following format: |
| 17 | /// |
| 18 | /// `[timestamp] <- interface@id.msg_name(args)` |
| 19 | #[cfg_attr (coverage, coverage(off))] |
| 20 | pub fn print_dispatched_message<Id: Display, Fd: AsRawFd>( |
| 21 | interface: &str, |
| 22 | id: u32, |
| 23 | msg_name: &str, |
| 24 | args: &[Argument<Id, Fd>], |
| 25 | ) { |
| 26 | // Add timestamp to output. |
| 27 | print_timestamp(); |
| 28 | |
| 29 | eprint!(" <- {}@ {}. {}, ( {})" , interface, id, msg_name, DisplaySlice(args)); |
| 30 | |
| 31 | // Add a new line. |
| 32 | eprintln!(); |
| 33 | } |
| 34 | |
| 35 | /// Print the send message to stderr in a following format: |
| 36 | /// |
| 37 | /// `[timestamp] -> interface@id.msg_name(args)` |
| 38 | #[cfg_attr (coverage, coverage(off))] |
| 39 | pub fn print_send_message<Id: Display, Fd: AsRawFd>( |
| 40 | interface: &str, |
| 41 | id: u32, |
| 42 | msg_name: &str, |
| 43 | args: &[Argument<Id, Fd>], |
| 44 | discarded: bool, |
| 45 | ) { |
| 46 | // Add timestamp to output. |
| 47 | print_timestamp(); |
| 48 | |
| 49 | if discarded { |
| 50 | eprint!("[discarded]" ); |
| 51 | } |
| 52 | |
| 53 | eprint!(" -> {}@ {}. {}( {})" , interface, id, msg_name, DisplaySlice(args)); |
| 54 | |
| 55 | // Add a new line. |
| 56 | eprintln!(); |
| 57 | } |
| 58 | |
| 59 | pub(crate) struct DisplaySlice<'a, D>(pub &'a [D]); |
| 60 | |
| 61 | impl<D: Display> Display for DisplaySlice<'_, D> { |
| 62 | #[cfg_attr (coverage, coverage(off))] |
| 63 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 64 | let mut it: Iter<'_, D> = self.0.iter(); |
| 65 | if let Some(val: &D) = it.next() { |
| 66 | write!(f, " {}" , val)?; |
| 67 | } |
| 68 | for val: &D in it { |
| 69 | write!(f, ", {}" , val)?; |
| 70 | } |
| 71 | Ok(()) |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | /// Print timestamp in seconds.microseconds format. |
| 76 | #[cfg_attr (coverage, coverage(off))] |
| 77 | fn print_timestamp() { |
| 78 | if let Ok(timestamp: Duration) = SystemTime::now().duration_since(UNIX_EPOCH) { |
| 79 | // NOTE this is all to make timestamps the same with libwayland, so the log doesn't look |
| 80 | // out of place when sys tries to log on their own. |
| 81 | let time: u32 = (timestamp.as_secs() * 1000000 + timestamp.subsec_nanos() as u64 / 1000) as u32; |
| 82 | // NOTE annotate timestamp so we know which library emmited the log entry. |
| 83 | eprint!("[ {:7}. {:03}][rs]" , time / 1000, time % 1000); |
| 84 | } |
| 85 | } |
| 86 | |