discord_cassandra_cpp/cassandra/
log.rs

1use crate::cassandra_sys::CassLogLevel_;
2use crate::cassandra_sys::CassLogMessage;
3// use cassandra_sys::cass_log_cleanup; @deprecated
4use crate::cassandra::util::ProtectedInner;
5use crate::cassandra_sys::cass_log_set_callback;
6use crate::cassandra_sys::cass_log_set_level;
7use crate::cassandra_sys::CassLogCallback;
8// use cassandra_sys::cass_log_set_queue_size; @deprecated
9
10use slog;
11use std::borrow::Borrow;
12use std::boxed::Box;
13use std::ffi::CStr;
14use std::os::raw;
15use std::ptr;
16
17/// The possible logging levels that can be set.
18#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Copy, Clone, Hash)]
19#[allow(missing_docs)] // Meanings are defined in CQL documentation.
20#[allow(non_camel_case_types)] // Names are traditional.
21pub enum LogLevel {
22    DISABLED,
23    CRITICAL,
24    ERROR,
25    WARN,
26    INFO,
27    DEBUG,
28    TRACE,
29    LAST_ENTRY,
30}
31
32enhance_nullary_enum!(LogLevel, CassLogLevel_, {
33    (DISABLED, CASS_LOG_DISABLED, "DISABLED"),
34    (CRITICAL, CASS_LOG_CRITICAL, "CRITICAL"),
35    (ERROR, CASS_LOG_ERROR, "ERROR"),
36    (WARN, CASS_LOG_WARN, "WARN"),
37    (INFO, CASS_LOG_INFO, "INFO"),
38    (DEBUG, CASS_LOG_DEBUG, "DEBUG"),
39    (TRACE, CASS_LOG_TRACE, "TRACE"),
40    (LAST_ENTRY, CASS_LOG_LAST_ENTRY, "LAST_ENTRY"),
41});
42
43/// Sets the log level.
44///
45/// <b>Note:</b> This needs to be done before any call that might log, such as
46/// any of the cass_cluster_*() or cass_ssl_*() functions.
47/// <b>Default:</b> WARN
48pub fn set_level(level: LogLevel) {
49    unsafe { cass_log_set_level(level.inner()) }
50}
51
52/// Called by Cassandra for every log if logging is enabled. Passes the log to the configured
53/// slog logger.
54unsafe extern "C" fn logger_callback(log: *const CassLogMessage, data: *mut raw::c_void) {
55    let log = &*log;
56    let logger: &slog::Logger = &*(data as *const _);
57
58    let message: &str = &CStr::from_ptr(log.message.as_ptr()).to_string_lossy();
59    let time_ms: u64 = log.time_ms;
60    let file: &str = &CStr::from_ptr(log.file).to_string_lossy();
61    let line: i32 = log.line;
62    let function: &str = &CStr::from_ptr(log.file).to_string_lossy();
63    let kv = o!(
64        "time_ms" => time_ms,
65        "file" => file,
66        "line" => line,
67        "function" => function
68    );
69
70    // Issue the correct level of log call. Sadly even though the `log!` macro exists,
71    // it's fundamental to slog that the log level is statically known for a given invocation.
72    // We can't do that in this case, so we have to use this tedious workaround.
73    match log.severity {
74        CassLogLevel_::CASS_LOG_DISABLED | CassLogLevel_::CASS_LOG_CRITICAL => {
75            crit!(logger, "{}", message; kv)
76        }
77        CassLogLevel_::CASS_LOG_ERROR => error!(logger, "{}", message; kv),
78        CassLogLevel_::CASS_LOG_WARN => warn!(logger, "{}", message; kv),
79        CassLogLevel_::CASS_LOG_INFO => info!(logger, "{}", message; kv),
80        CassLogLevel_::CASS_LOG_DEBUG => debug!(logger, "{}", message; kv),
81        CassLogLevel_::CASS_LOG_TRACE | CassLogLevel_::CASS_LOG_LAST_ENTRY => {
82            trace!(logger, "{}", message; kv)
83        }
84    };
85}
86
87/// Set or unset a logger to receive all Cassandra driver logs.
88pub fn set_logger(logger: Option<slog::Logger>) {
89    unsafe {
90        match logger {
91            Some(logger) => {
92                // Pass ownership to C. In fact we leak the logger; it never gets freed.
93                // We don't expect this to be called many times, so we're not worried.
94                let data = Box::new(logger);
95                cass_log_set_callback(Some(logger_callback), Box::into_raw(data) as _)
96            }
97            None => cass_log_set_callback(None, ptr::null_mut()),
98        }
99    }
100}