#[cfg(feature = "stacktrace")]
use backtrace::Backtrace;
use std::borrow::Cow;
use std::time::SystemTime;
#[derive(Debug)]
pub struct LogBuilder {
fields: Vec<LogField>,
time: Option<SystemTime>,
}
impl LogBuilder {
pub fn field<T: Into<LogField>>(&mut self, field: T) -> &mut Self {
self.fields.push(field.into());
self
}
pub fn time(&mut self, time: SystemTime) -> &mut Self {
self.time = Some(time);
self
}
pub fn std(&mut self) -> StdLogFieldsBuilder {
StdLogFieldsBuilder(self)
}
pub fn error(&mut self) -> StdErrorLogFieldsBuilder {
self.field(LogField::new("event", "error"));
StdErrorLogFieldsBuilder(self)
}
pub(crate) fn new() -> Self {
LogBuilder {
fields: Vec::new(),
time: None,
}
}
pub(crate) fn finish(mut self) -> Option<Log> {
if self.fields.is_empty() {
None
} else {
self.fields.reverse();
self.fields.sort_by(|a, b| a.name.cmp(&b.name));
self.fields.dedup_by(|a, b| a.name == b.name);
Some(Log {
fields: self.fields,
time: self.time.unwrap_or_else(SystemTime::now),
})
}
}
}
#[derive(Debug, Clone)]
pub struct Log {
fields: Vec<LogField>,
time: SystemTime,
}
impl Log {
pub fn fields(&self) -> &[LogField] {
&self.fields
}
pub fn time(&self) -> SystemTime {
self.time
}
}
#[derive(Debug, Clone)]
pub struct LogField {
name: Cow<'static, str>,
value: Cow<'static, str>,
}
impl LogField {
pub fn new<N, V>(name: N, value: V) -> Self
where
N: Into<Cow<'static, str>>,
V: Into<Cow<'static, str>>,
{
LogField {
name: name.into(),
value: value.into(),
}
}
pub fn name(&self) -> &str {
self.name.as_ref()
}
pub fn value(&self) -> &str {
self.value.as_ref()
}
}
impl<N, V> From<(N, V)> for LogField
where
N: Into<Cow<'static, str>>,
V: Into<Cow<'static, str>>,
{
fn from((n, v): (N, V)) -> Self {
LogField::new(n, v)
}
}
#[derive(Debug)]
pub struct StdLogFieldsBuilder<'a>(&'a mut LogBuilder);
impl<'a> StdLogFieldsBuilder<'a> {
pub fn event<T>(&mut self, event: T) -> &mut Self
where
T: Into<Cow<'static, str>>,
{
self.0.field(LogField::new("event", event));
self
}
pub fn message<T>(&mut self, message: T) -> &mut Self
where
T: Into<Cow<'static, str>>,
{
self.0.field(LogField::new("message", message));
self
}
#[cfg(feature = "stacktrace")]
pub fn stack(&mut self) -> &mut Self {
self.0
.field(LogField::new("stack", format!("{:?}", Backtrace::new())));
self
}
}
#[derive(Debug)]
pub struct StdErrorLogFieldsBuilder<'a>(&'a mut LogBuilder);
impl<'a> StdErrorLogFieldsBuilder<'a> {
pub fn kind<T>(&mut self, kind: T) -> &mut Self
where
T: Into<Cow<'static, str>>,
{
self.0.field(LogField::new("error.kind", kind));
self
}
pub fn message<T>(&mut self, message: T) -> &mut Self
where
T: Into<Cow<'static, str>>,
{
self.0.field(LogField::new("message", message));
self
}
#[cfg(feature = "stacktrace")]
pub fn stack(&mut self) -> &mut Self {
self.0
.field(LogField::new("stack", format!("{:?}", Backtrace::new())));
self
}
}