shared_framework/monitoring/mod.rs
1//! Log monitoring events and sinks.
2//!
3//! [`MonitoringEvent`] is the structured record emitted for a log entry and
4//! [`ILogMonitor`] is the async sink that receives and flushes those events.
5//!
6//! ```ignore
7//! let event = MonitoringEvent {
8//! event_id: "evt-1".to_string(),
9//! timestamp: chrono::Utc::now(),
10//! duration_ms: None,
11//! level: LogLevel::Info,
12//! message: "started".to_string(),
13//! data: None,
14//! correlation_id: ctx.correlation_id(),
15//! };
16//! monitor.log(event).await?;
17//! ```
18
19use chrono::{DateTime, Utc};
20use serde::{Deserialize, Serialize};
21
22/// Severity of a [`MonitoringEvent`].
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub enum LogLevel {
25 /// Command execution.
26 Exec,
27 /// Failures.
28 Error,
29 /// Noteworthy normal events.
30 Info,
31 /// Diagnostic detail.
32 Debug,
33 /// Potential problems.
34 Warn,
35 /// Timed-operation records.
36 Time,
37}
38
39/// Structured log record sent to an [`ILogMonitor`].
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct MonitoringEvent {
42 /// Unique ID of this event.
43 pub event_id: String,
44 /// When the event occurred.
45 pub timestamp: DateTime<Utc>,
46 /// Operation duration, when the event measures timed work.
47 pub duration_ms: Option<u64>,
48 /// Severity of the event.
49 pub level: LogLevel,
50 /// Human-readable message.
51 pub message: String,
52 /// Optional structured payload.
53 pub data: Option<serde_json::Value>,
54 /// Correlation ID of the request that produced the event.
55 pub correlation_id: String,
56}
57
58/// Async sink for [`MonitoringEvent`] records.
59#[async_trait::async_trait]
60pub trait ILogMonitor: Send + Sync {
61 /// Receives one monitoring event. Returns an error if the event cannot be recorded.
62 async fn log(&self, event: MonitoringEvent) -> anyhow::Result<()>;
63 /// Flushes any buffered events. Returns an error if the flush fails.
64 async fn flush(&self) -> anyhow::Result<()>;
65}