123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- // Copyright (c) 2016-2017, The Tor Project, Inc. */
- // See LICENSE for licensing information */
- /// The related domain which the logging message is relevant. For example,
- /// log messages relevant to networking would use LogDomain::LdNet, whereas
- /// general messages can use LdGeneral.
- #[derive(Eq, PartialEq)]
- pub enum LogDomain {
- LdNet,
- LdGeneral,
- }
- /// The severity level at which to log messages.
- #[derive(Eq, PartialEq)]
- pub enum LogSeverity {
- Notice,
- Warn,
- }
- /// Main entry point for Rust modules to log messages.
- ///
- /// # Inputs
- ///
- /// * A `severity` of type LogSeverity, which defines the level of severity the
- /// message will be logged.
- /// * A `domain` of type LogDomain, which defines the domain the log message
- /// will be associated with.
- /// * A `function` of type &str, which defines the name of the function where
- /// the message is being logged. There is a current RFC for a macro that
- /// defines function names. When it is, we should use it. See
- /// https://github.com/rust-lang/rfcs/pull/1719
- /// * A `message` of type &str, which is the log message itself.
- #[macro_export]
- macro_rules! tor_log_msg {
- ($severity: path,
- $domain: path,
- $function: expr,
- $($message:tt)*) =>
- {
- {
- use std::ffi::CString;
- /// Default function name to log in case of errors when converting
- /// a function name to a CString
- const ERR_LOG_FUNCTION: &'static str = "tor_log_msg";
- /// Default message to log in case of errors when converting a log
- /// message to a CString
- const ERR_LOG_MSG: &'static str = "Unable to log message from Rust
- module due to error when converting to CString";
- let func = match CString::new($function) {
- Ok(n) => n,
- Err(_) => CString::new(ERR_LOG_FUNCTION).unwrap(),
- };
- let msg = match CString::new(format!($($message)*)) {
- Ok(n) => n,
- Err(_) => CString::new(ERR_LOG_MSG).unwrap(),
- };
- let func_ptr = func.as_ptr();
- let msg_ptr = msg.as_ptr();
- unsafe {
- tor_log_string(translate_severity($severity),
- translate_domain($domain),
- func_ptr, msg_ptr
- )
- }
- }
- };
- }
- /// This module exposes no-op functionality purely for the purpose of testing
- /// Rust at the module level.
- #[cfg(any(test, feature = "testing"))]
- pub mod log {
- use libc::{c_char, c_int};
- use super::LogDomain;
- use super::LogSeverity;
- /// Expose a no-op logging interface purely for testing Rust modules at the
- /// module level.
- pub fn tor_log_string<'a>(
- severity: c_int,
- domain: u32,
- function: *const c_char,
- message: *const c_char,
- ) -> (c_int, u32, String, String) {
- use std::ffi::CStr;
- let func = unsafe { CStr::from_ptr(function) }.to_str().unwrap();
- let func_allocated = String::from(func);
- let msg = unsafe { CStr::from_ptr(message) }.to_str().unwrap();
- let msg_allocated = String::from(msg);
- (severity, domain, func_allocated, msg_allocated)
- }
- pub unsafe fn translate_domain(_domain: LogDomain) -> u32 {
- 1
- }
- pub unsafe fn translate_severity(_severity: LogSeverity) -> c_int {
- 1
- }
- }
- /// This implementation is used when compiling for actual use, as opposed to
- /// testing.
- #[cfg(all(not(test), not(feature = "testing")))]
- pub mod log {
- use libc::{c_char, c_int};
- use super::LogDomain;
- use super::LogSeverity;
- /// Severity log types. These mirror definitions in /src/common/torlog.h
- /// C_RUST_COUPLED: src/common/log.c, log domain types
- extern "C" {
- #[no_mangle]
- static _LOG_WARN: c_int;
- static _LOG_NOTICE: c_int;
- }
- /// Domain log types. These mirror definitions in /src/common/torlog.h
- /// C_RUST_COUPLED: src/common/log.c, log severity types
- extern "C" {
- #[no_mangle]
- static _LD_NET: u32;
- static _LD_GENERAL: u32;
- }
- /// Translate Rust defintions of log domain levels to C. This exposes a 1:1
- /// mapping between types.
- ///
- /// Allow for default cases in case Rust and C log types get out of sync
- #[allow(unreachable_patterns)]
- pub unsafe fn translate_domain(domain: LogDomain) -> u32 {
- match domain {
- LogDomain::LdNet => _LD_NET,
- LogDomain::LdGeneral => _LD_GENERAL,
- _ => _LD_GENERAL,
- }
- }
- /// Translate Rust defintions of log severity levels to C. This exposes a
- /// 1:1 mapping between types.
- ///
- /// Allow for default cases in case Rust and C log types get out of sync
- #[allow(unreachable_patterns)]
- pub unsafe fn translate_severity(severity: LogSeverity) -> c_int {
- match severity {
- LogSeverity::Warn => _LOG_WARN,
- LogSeverity::Notice => _LOG_NOTICE,
- _ => _LOG_NOTICE,
- }
- }
- /// The main entry point into Tor's logger. When in non-test mode, this
- /// will link directly with `tor_log_string` in /src/or/log.c
- extern "C" {
- pub fn tor_log_string(
- severity: c_int,
- domain: u32,
- function: *const c_char,
- string: *const c_char,
- );
- }
- }
- #[cfg(test)]
- mod test {
- use tor_log::*;
- use tor_log::log::*;
- use libc::c_int;
- #[test]
- fn test_get_log_message() {
- fn test_macro<'a>() -> (c_int, u32, String, String) {
- let (x, y, z, a) =
- tor_log_msg!(
- LogSeverity::Warn,
- LogDomain::LdNet,
- "test_macro",
- "test log message {}",
- "a",
- );
- (x, y, z, a)
- }
- let (severity, domain, function_name, log_msg) = test_macro();
- let expected_severity =
- unsafe { translate_severity(LogSeverity::Warn) };
- assert_eq!(severity, expected_severity);
- let expected_domain = unsafe { translate_domain(LogDomain::LdNet) };
- assert_eq!(domain, expected_domain);
- assert_eq!("test_macro", function_name);
- assert_eq!("test log message a", log_msg);
- }
- #[test]
- fn test_get_log_message_multiple_values() {
- fn test_macro<'a>() -> (c_int, u32, String, String) {
- let (x, y, z, a) = tor_log_msg!(
- LogSeverity::Warn,
- LogDomain::LdNet,
- "test_macro 2",
- "test log message {} {} {} {}",
- 10,
- 9,
- 8,
- 7
- );
- (x, y, z, a)
- }
- let (severity, domain, function_name, log_msg) = test_macro();
- let expected_severity =
- unsafe { translate_severity(LogSeverity::Warn) };
- assert_eq!(severity, expected_severity);
- let expected_domain = unsafe { translate_domain(LogDomain::LdNet) };
- assert_eq!(domain, expected_domain);
- assert_eq!("test_macro 2", function_name);
- assert_eq!("test log message 10 9 8 7", log_msg);
- }
- }
|