tor_log.rs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // Copyright (c) 2016-2018, The Tor Project, Inc. */
  2. // See LICENSE for licensing information */
  3. // Note that these functions are untested due to the fact that there are no
  4. // return variables to test and they are calling into a C API.
  5. /// The related domain which the logging message is relevant. For example,
  6. /// log messages relevant to networking would use LogDomain::LdNet, whereas
  7. /// general messages can use LdGeneral.
  8. #[derive(Eq, PartialEq)]
  9. pub enum LogDomain {
  10. Net,
  11. General,
  12. }
  13. /// The severity level at which to log messages.
  14. #[derive(Eq, PartialEq)]
  15. pub enum LogSeverity {
  16. Notice,
  17. Warn,
  18. }
  19. /// Main entry point for Rust modules to log messages.
  20. ///
  21. /// # Inputs
  22. ///
  23. /// * A `severity` of type LogSeverity, which defines the level of severity the
  24. /// message will be logged.
  25. /// * A `domain` of type LogDomain, which defines the domain the log message
  26. /// will be associated with.
  27. /// * A `function` of type &str, which defines the name of the function where
  28. /// the message is being logged. There is a current RFC for a macro that
  29. /// defines function names. When it is, we should use it. See
  30. /// https://github.com/rust-lang/rfcs/pull/1719
  31. /// * A `message` of type &str, which is the log message itself.
  32. #[macro_export]
  33. macro_rules! tor_log_msg {
  34. ($severity: path,
  35. $domain: path,
  36. $function: expr,
  37. $($message:tt)*) =>
  38. {
  39. {
  40. let msg = format!($($message)*);
  41. $crate::tor_log_msg_impl($severity, $domain, $function, msg)
  42. }
  43. };
  44. }
  45. #[inline]
  46. pub fn tor_log_msg_impl(severity: LogSeverity, domain: LogDomain, function: &str, message: String) {
  47. use std::ffi::CString;
  48. /// Default function name to log in case of errors when converting
  49. /// a function name to a CString
  50. const ERR_LOG_FUNCTION: &str = "tor_log_msg";
  51. /// Default message to log in case of errors when converting a log
  52. /// message to a CString
  53. const ERR_LOG_MSG: &str = "Unable to log message from Rust \
  54. module due to error when converting to CString";
  55. let func = match CString::new(function) {
  56. Ok(n) => n,
  57. Err(_) => CString::new(ERR_LOG_FUNCTION).unwrap(),
  58. };
  59. let msg = match CString::new(message) {
  60. Ok(n) => n,
  61. Err(_) => CString::new(ERR_LOG_MSG).unwrap(),
  62. };
  63. // Bind to a local variable to preserve ownership. This is essential so
  64. // that ownership is guaranteed until these local variables go out of scope
  65. let func_ptr = func.as_ptr();
  66. let msg_ptr = msg.as_ptr();
  67. let c_severity = unsafe { log::translate_severity(severity) };
  68. let c_domain = unsafe { log::translate_domain(domain) };
  69. unsafe { log::tor_log_string(c_severity, c_domain, func_ptr, msg_ptr) }
  70. }
  71. /// This implementation is used when compiling for actual use, as opposed to
  72. /// testing.
  73. #[cfg(not(test))]
  74. pub mod log {
  75. use super::LogDomain;
  76. use super::LogSeverity;
  77. use libc::{c_char, c_int};
  78. /// Severity log types. These mirror definitions in src/lib/log/log.h
  79. /// C_RUST_COUPLED: src/lib/log/log.c, log domain types
  80. extern "C" {
  81. static LOG_WARN_: c_int;
  82. static LOG_NOTICE_: c_int;
  83. }
  84. /// Domain log types. These mirror definitions in src/lib/log/log.h
  85. /// C_RUST_COUPLED: src/lib/log/log.c, log severity types
  86. extern "C" {
  87. static LD_NET_: u32;
  88. static LD_GENERAL_: u32;
  89. }
  90. /// Translate Rust defintions of log domain levels to C. This exposes a 1:1
  91. /// mapping between types.
  92. #[inline]
  93. pub unsafe fn translate_domain(domain: LogDomain) -> u32 {
  94. match domain {
  95. LogDomain::Net => LD_NET_,
  96. LogDomain::General => LD_GENERAL_,
  97. }
  98. }
  99. /// Translate Rust defintions of log severity levels to C. This exposes a
  100. /// 1:1 mapping between types.
  101. #[inline]
  102. pub unsafe fn translate_severity(severity: LogSeverity) -> c_int {
  103. match severity {
  104. LogSeverity::Warn => LOG_WARN_,
  105. LogSeverity::Notice => LOG_NOTICE_,
  106. }
  107. }
  108. /// The main entry point into Tor's logger. When in non-test mode, this
  109. /// will link directly with `tor_log_string` in torlog.c
  110. extern "C" {
  111. pub fn tor_log_string(
  112. severity: c_int,
  113. domain: u32,
  114. function: *const c_char,
  115. string: *const c_char,
  116. );
  117. }
  118. }
  119. /// This module exposes no-op functionality for testing other Rust modules
  120. /// without linking to C.
  121. #[cfg(test)]
  122. pub mod log {
  123. use super::LogDomain;
  124. use super::LogSeverity;
  125. use libc::{c_char, c_int};
  126. pub static mut LAST_LOGGED_FUNCTION: *mut String = 0 as *mut String;
  127. pub static mut LAST_LOGGED_MESSAGE: *mut String = 0 as *mut String;
  128. pub unsafe fn tor_log_string(
  129. _severity: c_int,
  130. _domain: u32,
  131. function: *const c_char,
  132. message: *const c_char,
  133. ) {
  134. use std::ffi::CStr;
  135. let f = CStr::from_ptr(function);
  136. let fct = match f.to_str() {
  137. Ok(n) => n,
  138. Err(_) => "",
  139. };
  140. LAST_LOGGED_FUNCTION = Box::into_raw(Box::new(String::from(fct)));
  141. let m = CStr::from_ptr(message);
  142. let msg = match m.to_str() {
  143. Ok(n) => n,
  144. Err(_) => "",
  145. };
  146. LAST_LOGGED_MESSAGE = Box::into_raw(Box::new(String::from(msg)));
  147. }
  148. pub unsafe fn translate_domain(_domain: LogDomain) -> u32 {
  149. 1
  150. }
  151. pub unsafe fn translate_severity(_severity: LogSeverity) -> c_int {
  152. 1
  153. }
  154. }
  155. #[cfg(test)]
  156. mod test {
  157. use tor_log::log::{LAST_LOGGED_FUNCTION, LAST_LOGGED_MESSAGE};
  158. use tor_log::*;
  159. #[test]
  160. fn test_get_log_message() {
  161. {
  162. fn test_macro() {
  163. tor_log_msg!(
  164. LogSeverity::Warn,
  165. LogDomain::Net,
  166. "test_macro",
  167. "test log message {}",
  168. "a",
  169. );
  170. }
  171. test_macro();
  172. let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
  173. assert_eq!("test_macro", *function);
  174. let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
  175. assert_eq!("test log message a", *message);
  176. }
  177. // test multiple inputs into the log message
  178. {
  179. fn test_macro() {
  180. tor_log_msg!(
  181. LogSeverity::Warn,
  182. LogDomain::Net,
  183. "next_test_macro",
  184. "test log message {} {} {} {} {}",
  185. 1,
  186. 2,
  187. 3,
  188. 4,
  189. 5
  190. );
  191. }
  192. test_macro();
  193. let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
  194. assert_eq!("next_test_macro", *function);
  195. let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
  196. assert_eq!("test log message 1 2 3 4 5", *message);
  197. }
  198. // test how a long log message will be formatted
  199. {
  200. fn test_macro() {
  201. tor_log_msg!(
  202. LogSeverity::Warn,
  203. LogDomain::Net,
  204. "test_macro",
  205. "{}",
  206. "All the world's a stage, and all the men and women \
  207. merely players: they have their exits and their \
  208. entrances; and one man in his time plays many parts, his \
  209. acts being seven ages."
  210. );
  211. }
  212. test_macro();
  213. let expected_string = "All the world's a \
  214. stage, and all the men \
  215. and women merely players: \
  216. they have their exits and \
  217. their entrances; and one man \
  218. in his time plays many parts, \
  219. his acts being seven ages.";
  220. let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
  221. assert_eq!("test_macro", *function);
  222. let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
  223. assert_eq!(expected_string, *message);
  224. }
  225. }
  226. }