use crate::ignore::Ignore;
use crate::session;
use crate::CONFIG;
use log::Record;
use std::cell::RefCell;
use std::ffi::{OsStr, OsString};
use std::io::Write;
#[cfg(windows)]
use std::net::TcpStream;
#[cfg(unix)]
use std::os::unix::net::UnixStream;
use std::time::{SystemTime, UNIX_EPOCH};
#[cfg(windows)]
use winapi::um::processthreadsapi::GetCurrentThreadId;
#[cfg(windows)]
type SessionTransport = TcpStream;
#[cfg(unix)]
type SessionTransport = UnixStream;
thread_local! {
static OUTPUT: RefCell<Option<session::EstablishedSession<SessionTransport>>> = RefCell::new(None);
}
fn get_thread_id() -> Option<usize> {
if std::thread::current().name() == Some("main") {
return None;
}
#[cfg(target_os = "linux")]
return Some(nix::unistd::gettid().as_raw() as usize);
#[cfg(all(not(target_os = "linux"), unix))]
return Some(nix::sys::pthread::pthread_self() as usize);
#[cfg(windows)]
return Some(unsafe { GetCurrentThreadId() } as usize);
}
fn get_thread_file(filename: &OsStr) -> OsString {
let mut result = OsString::from(filename);
if let Some(tid) = get_thread_id() {
result.push(format!(".{}", tid));
}
result
}
pub fn log(record: &Record) {
OUTPUT
.with(|output| -> Result<(), Ignore> {
if output.borrow().is_none() {
let filename = get_thread_file(unsafe { &CONFIG.as_ref().unwrap().base_filename });
let session = session::Session::connect()?.establish(filename.to_str().unwrap())?;
output.replace(Some(session));
}
let mut borrow = output.borrow_mut();
let session = borrow.as_mut().unwrap();
let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
let now = now.as_millis() as u64;
session.write_all(&now.to_le_bytes())?;
writeln!(session, "[{}] {} -- {}", record.level(), record.target(), record.args())?;
Ok(())
})
.ok();
}
pub fn flush() {
OUTPUT.with(|output| {
output.replace(None);
})
}