use serde::Serialize;
use tracing::warn;
#[derive(Serialize)]
pub struct AuditEvent<'a> {
pub actor: &'a str,
pub action: &'a str,
pub target: Option<&'a str>,
pub payload: serde_json::Value,
pub occurred_at: chrono::DateTime<chrono::Utc>,
}
pub async fn record(
client: &async_nats::Client,
actor: &str,
action: &str,
target: Option<&str>,
payload: serde_json::Value,
) {
let subject = match target {
Some(t) => format!("audit.{actor}.{action}.{t}"),
None => format!("audit.{actor}.{action}"),
};
let event = AuditEvent {
actor,
action,
target,
payload,
occurred_at: chrono::Utc::now(),
};
let body = match serde_json::to_vec(&event) {
Ok(b) => b,
Err(e) => {
warn!(error = %e, subject = %subject, "audit serialize failed");
return;
}
};
if let Err(e) = client.publish(subject.clone(), body.into()).await {
warn!(error = %e, subject = %subject, "audit publish failed");
}
}