use crate::cassandra_sys::CassLogLevel_;
use crate::cassandra_sys::CassLogMessage;
use crate::cassandra::util::ProtectedInner;
use crate::cassandra_sys::cass_log_set_callback;
use crate::cassandra_sys::cass_log_set_level;
#[cfg(feature = "slog")]
use slog;
use std::boxed::Box;
use std::ffi::CStr;
use std::os::raw;
use std::ptr;
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Copy, Clone, Hash)]
#[allow(missing_docs)] #[allow(non_camel_case_types)] pub enum LogLevel {
DISABLED,
CRITICAL,
ERROR,
WARN,
INFO,
DEBUG,
TRACE,
LAST_ENTRY,
}
enhance_nullary_enum!(LogLevel, CassLogLevel_, {
(DISABLED, CASS_LOG_DISABLED, "DISABLED"),
(CRITICAL, CASS_LOG_CRITICAL, "CRITICAL"),
(ERROR, CASS_LOG_ERROR, "ERROR"),
(WARN, CASS_LOG_WARN, "WARN"),
(INFO, CASS_LOG_INFO, "INFO"),
(DEBUG, CASS_LOG_DEBUG, "DEBUG"),
(TRACE, CASS_LOG_TRACE, "TRACE"),
(LAST_ENTRY, CASS_LOG_LAST_ENTRY, "LAST_ENTRY"),
});
pub fn set_level(level: LogLevel) {
unsafe { cass_log_set_level(level.inner()) }
}
pub fn unset_logger() {
unsafe { cass_log_set_callback(None, ptr::null_mut()) }
}
#[cfg(feature = "slog")]
unsafe extern "C" fn slog_callback(log: *const CassLogMessage, data: *mut raw::c_void) {
let log = &*log;
let logger: &slog::Logger = &*(data as *const _);
let message: &str = &CStr::from_ptr(log.message.as_ptr()).to_string_lossy();
let time_ms: u64 = log.time_ms;
let file: &str = &CStr::from_ptr(log.file).to_string_lossy();
let line: i32 = log.line;
let function: &str = &CStr::from_ptr(log.function).to_string_lossy();
let kv = o!(
"time_ms" => time_ms,
"file" => file,
"line" => line,
"function" => function
);
match log.severity {
CassLogLevel_::CASS_LOG_DISABLED | CassLogLevel_::CASS_LOG_CRITICAL => {
crit!(logger, "{}", message; kv)
}
CassLogLevel_::CASS_LOG_ERROR => error!(logger, "{}", message; kv),
CassLogLevel_::CASS_LOG_WARN => warn!(logger, "{}", message; kv),
CassLogLevel_::CASS_LOG_INFO => info!(logger, "{}", message; kv),
CassLogLevel_::CASS_LOG_DEBUG => debug!(logger, "{}", message; kv),
CassLogLevel_::CASS_LOG_TRACE | CassLogLevel_::CASS_LOG_LAST_ENTRY => {
trace!(logger, "{}", message; kv)
}
};
}
#[doc(hidden)]
#[deprecated(note = "Please use set_slog_logger instead")]
#[cfg(feature = "slog")]
pub fn set_logger(logger: Option<slog::Logger>) {
if let Some(logger) = logger {
set_slog_logger(logger);
} else {
unset_logger();
}
}
#[cfg(feature = "slog")]
pub fn set_slog_logger(logger: slog::Logger) {
unsafe {
let data = Box::new(logger);
cass_log_set_callback(Some(slog_callback), Box::into_raw(data) as _)
}
}
#[cfg(feature = "log")]
unsafe extern "C" fn log_callback(log: *const CassLogMessage, _data: *mut raw::c_void) {
use log::{logger, Level, Record};
let log = &*log;
let message: &str = &CStr::from_ptr(log.message.as_ptr()).to_string_lossy();
let file = &CStr::from_ptr(log.file).to_string_lossy();
let line = log.line as u32;
let function = &CStr::from_ptr(log.function).to_string_lossy();
let module_and_function_name = function_definition_to_module_name(function).unwrap_or(function);
let level = match log.severity {
CassLogLevel_::CASS_LOG_DISABLED | CassLogLevel_::CASS_LOG_CRITICAL => Level::Error,
CassLogLevel_::CASS_LOG_ERROR => Level::Error,
CassLogLevel_::CASS_LOG_WARN => Level::Warn,
CassLogLevel_::CASS_LOG_INFO => Level::Info,
CassLogLevel_::CASS_LOG_DEBUG => Level::Debug,
CassLogLevel_::CASS_LOG_TRACE | CassLogLevel_::CASS_LOG_LAST_ENTRY => Level::Trace,
};
logger().log(
&Record::builder()
.level(level)
.args(format_args!("{}", message))
.line(Some(line))
.file(Some(file))
.module_path(Some(module_and_function_name))
.target(module_and_function_name)
.build(),
);
}
fn function_definition_to_module_name(definition: &str) -> Option<&str> {
let mut definition_iter = definition.split(' ');
definition_iter.next()?;
definition_iter.next()?.split('(').next()
}
#[cfg(feature = "log")]
pub fn set_log_logger() {
unsafe { cass_log_set_callback(Some(log_callback), ptr::null_mut()) }
}