use crate::events::{BackoffSource, Event, EventKind};
use crate::subscribers::Subscribe;
#[derive(Default)]
pub struct LogWriter;
impl Subscribe for LogWriter {
fn on_event(&self, e: &Event) {
self.print_event(e);
}
fn name(&self) -> &str {
"LogWriter"
}
}
impl LogWriter {
fn print_event(&self, e: &Event) {
let head = format!("[{:03}] [{}]", e.seq % 1000, e.kind.as_label());
fn fmt_ms(ms: Option<u32>) -> String {
match ms {
Some(v) if v >= 1000 && v % 1000 == 0 => format!("{}s", v / 1000),
Some(v) if v >= 1000 => format!("{:.1}s", v as f64 / 1000.0),
Some(v) => format!("{}ms", v),
None => "0ms".to_string(),
}
}
fn or<'a>(s: Option<&'a str>, def: &'a str) -> &'a str {
s.unwrap_or(def)
}
match e.kind {
EventKind::ShutdownRequested
| EventKind::AllStoppedWithinGrace
| EventKind::GraceExceeded => {
println!("{head}");
}
EventKind::TaskStopped
| EventKind::TaskCanceled
| EventKind::TaskAddRequested
| EventKind::TaskAdded
| EventKind::TaskRemoveRequested
| EventKind::TaskRemoved => {
println!("{head} task={}", or(e.task.as_deref(), "none"));
}
EventKind::TaskStarting => {
println!(
"{head} task={} attempt={}",
or(e.task.as_deref(), "none"),
e.attempt.unwrap_or(0)
);
}
EventKind::TaskFailed => {
println!(
"{head} task={} reason=\"{}\" attempt={}",
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "unknown"),
e.attempt.unwrap_or(0)
);
}
EventKind::TaskAddFailed => {
println!(
"{head} task={} reason=\"{}\"",
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "unknown")
);
}
EventKind::TimeoutHit => {
println!(
"{head} task={} timeout={}",
or(e.task.as_deref(), "none"),
fmt_ms(e.timeout_ms)
);
}
EventKind::BackoffScheduled => {
let src = match e.backoff_source {
Some(BackoffSource::Success) => "success",
Some(BackoffSource::Failure) => "failure",
None => "unknown",
};
println!(
"{head} task={} source={} delay={} after_attempt={} reason=\"{}\"",
or(e.task.as_deref(), "none"),
src,
fmt_ms(e.delay_ms),
e.attempt.unwrap_or(0),
or(e.reason.as_deref(), "none")
);
}
EventKind::SubscriberOverflow | EventKind::SubscriberPanicked => {
println!(
"{head} subscriber={} reason=\"{}\"",
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "unknown")
);
}
EventKind::ActorExhausted => {
println!(
"{head} task={} reason=\"{}\"",
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "policy")
);
}
EventKind::ActorDead => {
println!(
"{head} task={} reason=\"{}\"",
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "fatal")
);
}
#[cfg(feature = "controller")]
EventKind::ControllerRejected | EventKind::ControllerSlotTransition => {
println!(
"{head} slot={} reason=\"{}\"",
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "unknown")
);
}
#[cfg(feature = "controller")]
EventKind::ControllerSubmitted => {
println!(
"{head} slot={} {}",
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "")
);
}
}
}
}