use std::fmt::Write as _;
use std::io::Write;
use std::sync::Mutex;
use std::sync::PoisonError;
use crate::Event;
use crate::Reporter;
use crate::ReporterError;
pub struct TextReporter<W> {
writer: Mutex<W>,
}
impl<W> TextReporter<W> {
#[must_use]
pub const fn new(writer: W) -> Self {
Self {
writer: Mutex::new(writer),
}
}
pub fn into_inner(self) -> Result<W, PoisonError<W>> {
self.writer.into_inner()
}
}
impl<W> Reporter for TextReporter<W>
where
W: Write + Send,
{
fn report(&self, event: &Event) -> Result<(), ReporterError> {
let mut line = format_event(event);
line.push('\n');
let mut writer = self.writer.lock().map_err(|_| {
ReporterError::message("text reporter mutex is poisoned")
})?;
writer
.write_all(line.as_bytes())
.map_err(ReporterError::new)
}
}
fn format_event(event: &Event) -> String {
let mut line = format!(
"operation={} sequence={} phase={} elapsed={:?}",
event.operation_id(),
event.sequence(),
event.phase().as_str(),
event.elapsed(),
);
if let Some(stage) = event.stage() {
let _ = write!(
line,
" stage={}({}) position={:?} total={:?}",
stage.id().escape_default(),
stage.name().escape_default(),
stage.position_value(),
stage.total(),
);
}
for (key, value) in event.attributes().iter() {
let _ = write!(
line,
" attribute={}({})",
key.escape_default(),
value.escape_default(),
);
}
for metric in event.metrics() {
let _ = write!(
line,
" metric={}({}) total={:?} completed={} active={} succeeded={} failed={} cancelled={}",
metric.id().escape_default(),
metric.name().escape_default(),
metric.total(),
metric.completed(),
metric.active(),
metric.succeeded(),
metric.failed(),
metric.cancelled(),
);
}
line
}