event_monitor: Send events to info! level logging

The resulting output looks like:

Event: source = virtio-device event = activated id = _disk0

See: #7484

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
This commit is contained in:
Rob Bradford 2025-11-25 17:02:42 +00:00 committed by Bo Chen
parent 6a86c157af
commit e3fb425615
3 changed files with 23 additions and 1 deletions

1
Cargo.lock generated
View file

@ -710,6 +710,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"flume", "flume",
"libc", "libc",
"log",
"serde", "serde",
"serde_json", "serde_json",
] ]

View file

@ -7,6 +7,7 @@ version = "0.1.0"
[dependencies] [dependencies]
flume = { workspace = true } flume = { workspace = true }
libc = { workspace = true } libc = { workspace = true }
log = { workspace = true }
serde = { workspace = true, features = ["derive", "rc"] } serde = { workspace = true, features = ["derive", "rc"] }
serde_json = { workspace = true } serde_json = { workspace = true }

View file

@ -6,11 +6,12 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::sync::{Arc, OnceLock}; use std::sync::{Arc, OnceLock};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::{fmt, io};
use log::info;
use serde::Serialize; use serde::Serialize;
static MONITOR: OnceLock<MonitorHandle> = OnceLock::new(); static MONITOR: OnceLock<MonitorHandle> = OnceLock::new();
@ -88,12 +89,31 @@ pub fn set_monitor(file: Option<File>) -> io::Result<Monitor> {
Ok(monitor) Ok(monitor)
} }
struct PropertiesFormatter<'a>(&'a Option<&'a HashMap<Cow<'a, str>, Cow<'a, str>>>);
impl<'a> fmt::Display for PropertiesFormatter<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(map) = self.0 {
for (i, (key, value)) in map.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{key} = {value}")?;
}
}
Ok(())
}
}
pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) { pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) {
// `MONITOR` is always in a valid state (None or Some), because it is set // `MONITOR` is always in a valid state (None or Some), because it is set
// only once before any threads are spawned, and it's not mutated // only once before any threads are spawned, and it's not mutated
// afterwards. This function only creates immutable references to `MONITOR`. // afterwards. This function only creates immutable references to `MONITOR`.
// Because `MONITOR.tx` is `Sync`, it's safe to share `MONITOR` across // Because `MONITOR.tx` is `Sync`, it's safe to share `MONITOR` across
// threads, making this function thread-safe. // threads, making this function thread-safe.
info!(
"Event: source = {source} event = {event} {}",
PropertiesFormatter(&properties)
);
if let Some(monitor_handle) = MONITOR.get().as_ref() { if let Some(monitor_handle) = MONITOR.get().as_ref() {
let event = Event { let event = Event {
timestamp: monitor_handle.start.elapsed(), timestamp: monitor_handle.start.elapsed(),