// Event sites construct detailed payloads lazily. macro_rules! emit { ($kind:expr, $payload:expr $(,)?) => { crate::logging::progress::emit_event($kind, || $payload) }; } pub(crate) use emit; #[track_caller] pub(crate) fn emit_event(kind: &str, payload: impl FnOnce() -> serde_json::Value) { let level = event_level(kind); if super::observer::observes(kind) { let fields = payload(); super::observer::event(kind, &fields); super::emit(level, kind, || fields); } else { super::emit(level, kind, payload); } } pub(crate) fn event_level(kind: &str) -> crate::logging::Level { registered_event_level(kind).unwrap_or(crate::logging::Level::Debug) } fn registered_event_level(kind: &str) -> Option { Some( if matches!( kind, "http_fetch_failed" | "rrdp_sync_failed" | "rrdp_cross_origin_rejected" | "repo_terminal_failure" | "rrdp_failed_fallback_rsync" ) { crate::logging::Level::Warn } else if matches!(kind, "validation_failed" | "object_failed") { crate::logging::Level::Error } else if matches!(kind, "validation_warning" | "validation_warnings") { crate::logging::Level::Warn } else if matches!( kind, "publication_point_start" | "publication_point_repo_sync_done" | "publication_point_finish" | "publication_point_object" | "phase2_repo_events_drain" | "phase2_ready_queue_stage_fresh_breakdown" | "phase2_stage_pool_stats" | "phase2_publication_point_reduced" | "phase2_build_tree_output" | "phase2_roa_dispatch_batch" | "phase2_object_results_drain" | "phase2_finalize_task_submit" | "phase2_finalize_results_drain" | "phase2_ready_queue_batch" | "phase2_ready_queue_control_breakdown" | "phase2_ready_publication_point_control_snapshot_breakdown" | "phase2_finalize_worker_breakdown" ) { crate::logging::Level::Trace } else if matches!( kind, "validation_started" | "validation_completed" | "validation_summary" ) { crate::logging::Level::Info } else if matches!( kind, "repository_sync_selected" | "repo_sync_rrdp_ok" | "rrdp_fallback_rsync" | "repo_sync_rsync_direct" | "rrdp_sync_attempt" | "rrdp_sync_success" | "rsync_sync_start" | "rsync_sync_fetch_done" | "rsync_sync_done" | "rsync_sync_slow" | "http_fetch_slow" | "rrdp_redirect_checked" | "phase2_control_loop_slow" | "phase2_stage_fresh_slow" | "phase2_ready_publication_point_control_slow" | "phase1_repo_task_enqueued" | "phase1_repo_task_waiting" | "phase1_repo_task_reused" | "phase1_repo_task_dispatched" | "phase1_repo_task_result" | "phase1_repo_worker_execute_start" | "phase1_repo_worker_execute_finish" | "rrdp_sync_selected" | "rrdp_download_completed" ) { crate::logging::Level::Debug } else { return None; }, ) } pub fn slow_threshold_secs() -> f64 { 30.0 } pub fn stage_fresh_slow_threshold_ms() -> u64 { 1_000 } pub fn pp_control_slow_threshold_ms() -> u64 { 100 } pub fn control_loop_slow_threshold_ms() -> u64 { 1_000 } #[cfg(test)] mod tests { use super::event_level; use crate::logging::Level; #[test] fn all_literal_progress_sites_are_registered() { fn visit(path: &std::path::Path) { for entry in std::fs::read_dir(path).unwrap() { let path = entry.unwrap().path(); if path.is_dir() { visit(&path); } else if path.extension().is_some_and(|extension| extension == "rs") { let source = std::fs::read_to_string(&path).unwrap(); for site in source.split(concat!("progress::", "emit!(")).skip(1) { if let Some(literal) = site.trim_start().strip_prefix('"') { let event = literal.split('"').next().unwrap(); assert!( super::registered_event_level(event).is_some(), "unregistered event {event} in {}", path.display() ); } } } } } visit(&std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src")); assert_eq!( super::registered_event_level("phase2_finalize_worker_breakdown"), Some(Level::Trace) ); assert_eq!(event_level("rrdp_cross_origin_rejected"), Level::Warn); assert_eq!(event_level("phase2_control_loop_slow"), Level::Debug); } #[test] fn event_levels_keep_default_output_quiet() { assert_eq!(event_level("validation_started"), Level::Info); assert_eq!(event_level("repository_sync_selected"), Level::Debug); assert_eq!(event_level("publication_point_object"), Level::Trace); assert_eq!(event_level("validation_warning"), Level::Warn); assert_eq!(event_level("validation_warnings"), Level::Warn); assert_eq!(event_level("validation_failed"), Level::Error); assert_eq!(event_level("object_failed"), Level::Error); assert_eq!(event_level("http_fetch_failed"), Level::Warn); assert_eq!(event_level("rrdp_sync_failed"), Level::Warn); } }