use std::sync::OnceLock;
use forge_core::signals::SignalEvent;
use tracing::debug;
use super::collector::SignalsCollector;
static GLOBAL_COLLECTOR: OnceLock<Option<SignalsCollector>> = OnceLock::new();
pub fn install(collector: Option<SignalsCollector>) {
if GLOBAL_COLLECTOR.set(collector).is_err() {
debug!("signals::emit global collector already installed");
}
}
pub fn is_installed() -> bool {
matches!(GLOBAL_COLLECTOR.get(), Some(Some(_)))
}
fn collector() -> Option<&'static SignalsCollector> {
GLOBAL_COLLECTOR.get().and_then(|c| c.as_ref())
}
pub fn emit_raw(event: SignalEvent) {
if let Some(c) = collector() {
c.try_send(event);
}
}
pub fn emit_server_execution(
name: &str,
kind: &str,
duration_ms: i32,
success: bool,
error_message: Option<String>,
) {
if let Some(c) = collector() {
c.try_send(SignalEvent::server_execution(
name,
kind,
duration_ms,
success,
error_message,
));
}
}
#[allow(clippy::too_many_arguments)]
pub fn emit_diagnostic(
event_name: &str,
properties: serde_json::Value,
client_ip: Option<String>,
user_agent: Option<String>,
visitor_id: Option<String>,
user_id: Option<uuid::Uuid>,
is_bot: bool,
) {
if let Some(c) = collector() {
c.try_send(SignalEvent::diagnostic(
event_name, properties, client_ip, user_agent, visitor_id, user_id, is_bot,
));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn emit_is_noop_without_installed_collector() {
emit_server_execution("not_installed", "job", 10, true, None);
emit_diagnostic(
"not_installed",
serde_json::json!({}),
None,
None,
None,
None,
false,
);
emit_raw(SignalEvent::server_execution("x", "job", 1, true, None));
}
}