1 // Copyright (c) 2016-2019, The Tor Project, Inc. */
2 // See LICENSE for licensing information */
4 // Note that these functions are untested due to the fact that there are no
5 // return variables to test and they are calling into a C API.
7 /// The related domain which the logging message is relevant. For example,
8 /// log messages relevant to networking would use LogDomain::LdNet, whereas
9 /// general messages can use LdGeneral.
10 #[derive(Eq, PartialEq)]
16 /// The severity level at which to log messages.
17 #[derive(Eq, PartialEq)]
18 pub enum LogSeverity {
23 /// Main entry point for Rust modules to log messages.
27 /// * A `severity` of type LogSeverity, which defines the level of severity the
28 /// message will be logged.
29 /// * A `domain` of type LogDomain, which defines the domain the log message
30 /// will be associated with.
31 /// * A `function` of type &str, which defines the name of the function where
32 /// the message is being logged. There is a current RFC for a macro that
33 /// defines function names. When it is, we should use it. See
34 /// https://github.com/rust-lang/rfcs/pull/1719
35 /// * A `message` of type &str, which is the log message itself.
37 macro_rules! tor_log_msg {
44 let msg = format!($($message)*);
45 $crate::tor_log_msg_impl($severity, $domain, $function, msg)
51 pub fn tor_log_msg_impl(severity: LogSeverity, domain: LogDomain, function: &str, message: String) {
52 use std::ffi::CString;
54 /// Default function name to log in case of errors when converting
55 /// a function name to a CString
56 const ERR_LOG_FUNCTION: &str = "tor_log_msg";
58 /// Default message to log in case of errors when converting a log
59 /// message to a CString
60 const ERR_LOG_MSG: &str = "Unable to log message from Rust \
61 module due to error when converting to CString";
63 let func = match CString::new(function) {
65 Err(_) => CString::new(ERR_LOG_FUNCTION).unwrap(),
68 let msg = match CString::new(message) {
70 Err(_) => CString::new(ERR_LOG_MSG).unwrap(),
73 // Bind to a local variable to preserve ownership. This is essential so
74 // that ownership is guaranteed until these local variables go out of scope
75 let func_ptr = func.as_ptr();
76 let msg_ptr = msg.as_ptr();
78 let c_severity = unsafe { log::translate_severity(severity) };
79 let c_domain = unsafe { log::translate_domain(domain) };
81 unsafe { log::tor_log_string(c_severity, c_domain, func_ptr, msg_ptr) }
84 /// This implementation is used when compiling for actual use, as opposed to
89 use super::LogSeverity;
90 use libc::{c_char, c_int};
92 /// Severity log types. These mirror definitions in src/lib/log/log.h
93 /// C_RUST_COUPLED: src/lib/log/log.c, log domain types
95 static LOG_WARN_: c_int;
96 static LOG_NOTICE_: c_int;
99 /// Domain log types. These mirror definitions in src/lib/log/log.h
100 /// C_RUST_COUPLED: src/lib/log/log.c, log severity types
103 static LD_GENERAL_: u32;
106 /// Translate Rust defintions of log domain levels to C. This exposes a 1:1
107 /// mapping between types.
109 pub unsafe fn translate_domain(domain: LogDomain) -> u32 {
111 LogDomain::Net => LD_NET_,
112 LogDomain::General => LD_GENERAL_,
116 /// Translate Rust defintions of log severity levels to C. This exposes a
117 /// 1:1 mapping between types.
119 pub unsafe fn translate_severity(severity: LogSeverity) -> c_int {
121 LogSeverity::Warn => LOG_WARN_,
122 LogSeverity::Notice => LOG_NOTICE_,
126 /// The main entry point into Tor's logger. When in non-test mode, this
127 /// will link directly with `tor_log_string` in torlog.c
129 pub fn tor_log_string(
132 function: *const c_char,
133 string: *const c_char,
138 /// This module exposes no-op functionality for testing other Rust modules
139 /// without linking to C.
142 use super::LogDomain;
143 use super::LogSeverity;
144 use libc::{c_char, c_int};
146 pub static mut LAST_LOGGED_FUNCTION: *mut String = 0 as *mut String;
147 pub static mut LAST_LOGGED_MESSAGE: *mut String = 0 as *mut String;
149 pub unsafe fn tor_log_string(
152 function: *const c_char,
153 message: *const c_char,
157 let f = CStr::from_ptr(function);
158 let fct = match f.to_str() {
162 LAST_LOGGED_FUNCTION = Box::into_raw(Box::new(String::from(fct)));
164 let m = CStr::from_ptr(message);
165 let msg = match m.to_str() {
169 LAST_LOGGED_MESSAGE = Box::into_raw(Box::new(String::from(msg)));
172 pub unsafe fn translate_domain(_domain: LogDomain) -> u32 {
176 pub unsafe fn translate_severity(_severity: LogSeverity) -> c_int {
183 use tor_log::log::{LAST_LOGGED_FUNCTION, LAST_LOGGED_MESSAGE};
187 fn test_get_log_message() {
194 "test log message {}",
201 let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
202 assert_eq!("test_macro", *function);
204 let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
205 assert_eq!("test log message a", *message);
208 // test multiple inputs into the log message
215 "test log message {} {} {} {} {}",
226 let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
227 assert_eq!("next_test_macro", *function);
229 let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
230 assert_eq!("test log message 1 2 3 4 5", *message);
233 // test how a long log message will be formatted
241 "All the world's a stage, and all the men and women \
242 merely players: they have their exits and their \
243 entrances; and one man in his time plays many parts, his \
244 acts being seven ages."
250 let expected_string = "All the world's a \
251 stage, and all the men \
252 and women merely players: \
253 they have their exits and \
254 their entrances; and one man \
255 in his time plays many parts, \
256 his acts being seven ages.";
258 let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
259 assert_eq!("test_macro", *function);
261 let message = unsafe { Box::from_raw(LAST_LOGGED_MESSAGE) };
262 assert_eq!(expected_string, *message);