1 //! Modify the Bluetooth logging configuration to enable debug logging. 2 //! 3 //! There are two logging implementations depending on whether the log is 4 //! emitted from Rust or C/C++. In order to keep log levels in sync between the 5 //! two, the |BluetoothLogging| struct will configure both the Rust logging and 6 //! the C/C++ logging (via topshim). 7 use bt_topshim::syslog::{set_default_log_level, set_log_level_for_tag, Level}; 8 use log::LevelFilter; 9 use syslog::{BasicLogger, Error, Facility, Formatter3164}; 10 11 use log_panics; 12 13 /// API to modify log levels that is exposed via RPC. 14 pub trait IBluetoothLogging { 15 /// Check whether debug logging is enabled. is_debug_enabled(&self) -> bool16 fn is_debug_enabled(&self) -> bool; 17 18 /// Change whether debug logging is enabled. set_debug_logging(&mut self, enabled: bool)19 fn set_debug_logging(&mut self, enabled: bool); 20 21 /// Set the log level. set_log_level(&mut self, level: Level)22 fn set_log_level(&mut self, level: Level); 23 24 /// Get the log level. get_log_level(&self) -> Level25 fn get_log_level(&self) -> Level; 26 } 27 28 /// Logging related implementation. 29 pub struct BluetoothLogging { 30 /// Current log level 31 /// If the level is not verbose, `VERBOSE_ONLY_LOG_TAGS` will be set to emit up to `INFO` only. 32 log_level: Level, 33 34 /// Log to stderr? 35 is_stderr: bool, 36 37 /// Is logging already initialized? 38 is_initialized: bool, 39 } 40 41 const VERBOSE_ONLY_LOG_TAGS: &[&str] = &[ 42 "bt_bta_av", // AV apis 43 "btm_sco", // SCO data path logs 44 "l2c_csm", // L2CAP state machine 45 "l2c_link", // L2CAP link layer logs 46 "sco_hci", // SCO over HCI 47 "uipc", // Userspace IPC implementation 48 ]; 49 50 impl BluetoothLogging { new(is_debug: bool, is_verbose_debug: bool, log_output: &str) -> Self51 pub fn new(is_debug: bool, is_verbose_debug: bool, log_output: &str) -> Self { 52 let is_stderr = log_output == "stderr"; 53 54 let log_level = match (is_debug, is_verbose_debug) { 55 (true, true) => Level::Verbose, 56 (true, false) => Level::Debug, 57 _ => Level::Info, 58 }; 59 60 Self { log_level, is_stderr, is_initialized: false } 61 } 62 initialize(&mut self) -> Result<(), Error>63 pub fn initialize(&mut self) -> Result<(), Error> { 64 if self.is_stderr { 65 env_logger::Builder::new().filter(None, self.get_log_level_filter()).init(); 66 } else { 67 let formatter = Formatter3164 { 68 facility: Facility::LOG_USER, 69 hostname: None, 70 process: "btadapterd".into(), 71 pid: 0, 72 }; 73 74 let logger = syslog::unix(formatter)?; 75 let _ = log::set_boxed_logger(Box::new(BasicLogger::new(logger))) 76 .map(|()| self.apply_linux_log_level()); 77 log_panics::init(); 78 } 79 80 // Set initial log levels and filter out tags if not verbose debug. 81 self.apply_libbluetooth_log_level(); 82 83 // Initialize the underlying system as well. 84 self.is_initialized = true; 85 Ok(()) 86 } 87 should_enable_debug_mode(&self) -> bool88 fn should_enable_debug_mode(&self) -> bool { 89 self.log_level == Level::Debug || self.log_level == Level::Verbose 90 } 91 get_log_level_filter(&self) -> LevelFilter92 fn get_log_level_filter(&self) -> LevelFilter { 93 match self.should_enable_debug_mode() { 94 true => LevelFilter::Debug, 95 false => LevelFilter::Info, 96 } 97 } 98 apply_linux_log_level(&self)99 fn apply_linux_log_level(&self) { 100 log::set_max_level(self.get_log_level_filter()); 101 } 102 apply_libbluetooth_log_level(&self)103 fn apply_libbluetooth_log_level(&self) { 104 set_default_log_level(self.log_level); 105 106 // TODO(b/371889111): Don't set log level for tag until b/371889111 is fixed. 107 /* 108 // Levels for verbose-only tags. 109 let level = match self.log_level { 110 Level::Verbose => Level::Verbose, 111 _ => Level::Info, 112 }; 113 for tag in VERBOSE_ONLY_LOG_TAGS { 114 log::info!("Setting log level for tag {} to {:?}", tag, level); 115 set_log_level_for_tag(tag, level); 116 } 117 */ 118 } 119 } 120 121 impl IBluetoothLogging for BluetoothLogging { is_debug_enabled(&self) -> bool122 fn is_debug_enabled(&self) -> bool { 123 self.is_initialized && self.should_enable_debug_mode() 124 } 125 set_debug_logging(&mut self, enabled: bool)126 fn set_debug_logging(&mut self, enabled: bool) { 127 if enabled { 128 match self.log_level { 129 Level::Verbose => { 130 self.set_log_level(Level::Verbose); 131 } 132 _ => { 133 self.set_log_level(Level::Debug); 134 } 135 } 136 } else { 137 self.set_log_level(Level::Info); 138 } 139 } 140 set_log_level(&mut self, level: Level)141 fn set_log_level(&mut self, level: Level) { 142 if !self.is_initialized { 143 return; 144 } 145 146 self.log_level = level; 147 148 // Update log level in Linux stack. 149 self.apply_linux_log_level(); 150 151 // Update log level in libbluetooth. 152 self.apply_libbluetooth_log_level(); 153 154 // Mark the start of debug logging with a debug print. 155 if self.is_debug_enabled() { 156 log::debug!("Debug logging successfully enabled!"); 157 } 158 159 log::info!("Setting log level to {:?}", level); 160 } 161 get_log_level(&self) -> Level162 fn get_log_level(&self) -> Level { 163 self.log_level 164 } 165 } 166