1use std::ffi::CString;
20use std::mem::forget;
21
22use failure::_core::ptr::null;
23use log::{Level, Log, Metadata, Record};
24use num_traits::{FromPrimitive, ToPrimitive};
25
26pub struct TarantoolLogger {}
28
29impl Log for TarantoolLogger {
30 fn enabled(&self, metadata: &Metadata) -> bool {
31 let level: SayLevel = metadata.level().into();
32 level <= SayLevel::from_i32(unsafe { ffi::LOG_LEVEL }).unwrap()
33 }
34
35 fn log(&self, record: &Record) {
36 say(
37 record.level().into(),
38 record.file().unwrap_or_default(),
39 record.line().unwrap_or(0) as i32,
40 None,
41 record.args().to_string().as_str(),
42 )
43 }
44
45 fn flush(&self) {}
46}
47
48#[repr(u32)]
50#[derive(Debug, Clone, PartialEq, PartialOrd, ToPrimitive, FromPrimitive)]
51pub enum SayLevel {
52 Fatal = 0,
53 System = 1,
54 Error = 2,
55 Crit = 3,
56 Warn = 4,
57 Info = 5,
58 Debug = 6,
59}
60
61impl From<Level> for SayLevel {
62 fn from(level: Level) -> Self {
63 match level {
64 Level::Error => SayLevel::Error,
65 Level::Warn => SayLevel::Warn,
66 Level::Info => SayLevel::Info,
67 Level::Debug => SayLevel::Debug,
68 Level::Trace => SayLevel::Debug,
69 }
70 }
71}
72
73#[inline]
75pub fn say(level: SayLevel, file: &str, line: i32, error: Option<&str>, message: &str) {
76 let level = level.to_i32().unwrap();
77 let file = CString::new(file).unwrap();
78 let error = error.map(|e| CString::new(e).unwrap());
79 let error_ptr = match error {
80 Some(ref error) => error.as_ptr(),
81 None => null(),
82 };
83 let message = CString::new(message).unwrap();
84
85 unsafe { ffi::SAY_FN.unwrap()(level, file.as_ptr(), line, error_ptr, message.as_ptr()) };
86
87 forget(file);
88 forget(message);
89 if error.is_some() {
90 forget(error.unwrap());
91 }
92}
93
94mod ffi {
95 use std::os::raw::{c_char, c_int};
96
97 pub type SayFunc = Option<
98 unsafe extern "C" fn(c_int, *const c_char, c_int, *const c_char, *const c_char, ...),
99 >;
100
101 extern "C" {
102 #[link_name = "log_level"]
103 pub static mut LOG_LEVEL: c_int;
104
105 #[link_name = "_say"]
106 pub static mut SAY_FN: SayFunc;
107 }
108}