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) -> &'static str {
"LogWriter"
}
}
impl LogWriter {
fn print_event(&self, e: &Event) {
let seq = format!("[{:03}]", e.seq % 1000);
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 => {
println!("{} [shutdown-requested]", seq);
}
EventKind::AllStoppedWithinGrace => {
println!("{} [all-stopped-within-grace]", seq);
}
EventKind::GraceExceeded => {
println!("{} [grace-exceeded]", seq);
}
EventKind::TaskStarting => {
println!(
"{} [starting] task={} attempt={}",
seq,
or(e.task.as_deref(), "none"),
e.attempt.unwrap_or(0)
);
}
EventKind::TaskStopped => {
println!("{} [stopped] task={}", seq, or(e.task.as_deref(), "none"));
}
EventKind::TaskFailed => {
println!(
"{} [failed] task={} reason=\"{}\" attempt={}",
seq,
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "unknown"),
e.attempt.unwrap_or(0)
);
}
EventKind::TimeoutHit => {
println!(
"{} [timeout] task={} timeout={}",
seq,
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!(
"{} [backoff] task={} source={} delay={} after_attempt={} reason=\"{}\"",
seq,
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 => {
println!(
"{} [subscriber-overflow] subscriber={} reason=\"{}\"",
seq,
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "unknown")
);
}
EventKind::SubscriberPanicked => {
println!(
"{} [subscriber-panicked] subscriber={} info=\"{}\"",
seq,
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "unknown")
);
}
EventKind::TaskAddRequested => {
println!(
"{} [task-add-requested] task={}",
seq,
or(e.task.as_deref(), "none")
);
}
EventKind::TaskAdded => {
println!(
"{} [task-added] task={}",
seq,
or(e.task.as_deref(), "none")
);
}
EventKind::TaskRemoveRequested => {
println!(
"{} [task-remove-requested] task={}",
seq,
or(e.task.as_deref(), "none")
);
}
EventKind::TaskRemoved => {
println!(
"{} [task-removed] task={}",
seq,
or(e.task.as_deref(), "none")
);
}
EventKind::ActorExhausted => {
println!(
"{} [actor-exhausted] task={} reason=\"{}\"",
seq,
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "policy")
);
}
EventKind::ActorDead => {
println!(
"{} [actor-dead] task={} reason=\"{}\"",
seq,
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "fatal")
);
}
#[cfg(feature = "controller")]
EventKind::ControllerRejected => {
println!(
"{} [controller-rejected] slot={} reason=\"{}\"",
seq,
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "unknown")
);
}
#[cfg(feature = "controller")]
EventKind::ControllerSubmitted => {
println!(
"{} [controller-submitted] slot={} {}",
seq,
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "")
);
}
#[cfg(feature = "controller")]
EventKind::ControllerSlotTransition => {
println!(
"{} [controller-transition] slot={} transition=\"{}\"",
seq,
or(e.task.as_deref(), "none"),
or(e.reason.as_deref(), "unknown")
);
}
}
}
}