use crate::{level::Level, logmod::ScopeEnv, options::*};
use chrono::{DateTime, Utc};
use std::{
fmt::{self, Display, Debug, Arguments},
borrow::Cow,
process,
thread,
};
#[derive(Debug)]
pub struct Message<'a> {
options: &'a Options,
time: DateTime<Utc>,
binname: &'a str,
severity: Option<&'a Level>,
modname: Option<Cow<'a, str>>,
scope: Option<&'a ScopeEnv>,
scope_ident: Option<&'a str>,
file: &'a str,
func: &'a str,
line: u32,
fmt: Cow<'a, str>,
}
impl<'a> Display for Message<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.options.has(DATESTAMP) {
write!(f, "{} ", self.time.format("%F"))?;
}
if self.options.has(TIMESTAMP) {
match self.options.has(NANOSEC) {
true => write!(f, "{} ", self.time.format("%X.%f"))?,
false => write!(f, "{} ", self.time.format("%X"))?,
};
}
if self.options.has(BINNAME) {
write!(f, "{}", self.binname)?;
}
if self.options.has(PID) {
if self.options.has(TID) {
write!(f, "[{}/{}] ", process::id(), Self::get_current_thread_id())?;
} else {
write!(f, "[{}] ", process::id())?;
}
} else if self.options.has(TID) {
write!(f, "[{}] ", Self::get_current_thread_id())?;
} else if self.options.has(BINNAME) {
write!(f, " ")?;
}
if let Some(s) = self.severity {
write!(f, "{} ", s)?;
}
if let Some(ref m) = self.modname {
write!(f, "{} ", m)?;
}
if let Some(s) = self.scope {
if let Some(ref i) = self.scope_ident {
write!(f, "{}[{}] ", s, i)?;
} else {
write!(f, "{} ", s)?;
}
}
if self.options.has(FILE) {
if self.options.has(LINE) {
write!(f, "{}:{} ", self.file, self.line)?;
} else {
write!(f, "{} ", self.file)?;
}
}
if self.options.has(FUNC) {
if !self.func.is_empty() {
write!(f, "{} ", self.func)?;
}
}
write!(f, "{}", self.fmt)
}
}
impl<'a> Message<'a> {
pub (crate) fn new(
options: &'a Options, binname: &'a str, file: &'a str, func: &'a str,
line: u32, fmt: &'a Arguments,
) -> Self {
let fmt = match fmt.as_str() {
Some(s) => Cow::Borrowed(s),
None => Cow::Owned(fmt.to_string()),
};
Self {
options,
time: Utc::now(),
binname,
severity: None,
modname: None,
scope: None,
scope_ident: None,
file,
func,
line,
fmt,
}
}
pub (crate) fn set_severity(&mut self, lvl: &'a Level) -> &mut Self {
if self.options.has(SEVERITY) {
self.severity = Some(lvl);
}
self
}
pub (crate) fn set_modname(&mut self, name: &'a str) -> &mut Self {
if self.options.has(MODULE) {
self.modname = Some(Cow::Borrowed(name));
}
self
}
pub (crate) fn set_scope(&mut self, scope: &'a ScopeEnv, ident: Option<&'a str>) -> &mut Self {
if self.options.has(SCOPE) {
self.scope = Some(scope);
self.scope_ident = ident;
}
self
}
fn get_current_thread_id() -> u64 {
let tid = format!("{:?}", thread::current().id());
let tid = tid.strip_prefix("ThreadId(").unwrap_or(&tid);
let tid = tid.strip_suffix(")").unwrap_or(tid);
tid.parse::<u64>().unwrap()
}
}