event_monitor: Add new crate for event reporting

This crate exposes the abililty for the VMM to set a file that events
should be written to. The event!() macro provides an interface to report
those events allowing the specification of an event source, an event
type and optional extra data. This will be written to the provided file
descriptor as JSON data.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2021-02-17 11:16:00 +00:00
parent c1d9edbfc0
commit ddbef7450d
4 changed files with 99 additions and 0 deletions

10
Cargo.lock generated
View File

@ -341,6 +341,16 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "event_monitor"
version = "0.1.0"
dependencies = [
"libc",
"serde",
"serde_derive",
"serde_json",
]
[[package]] [[package]]
name = "failure" name = "failure"
version = "0.1.8" version = "0.1.8"

View File

@ -69,6 +69,7 @@ members = [
"arch_gen", "arch_gen",
"block_util", "block_util",
"devices", "devices",
"event_monitor",
"hypervisor", "hypervisor",
"net_gen", "net_gen",
"net_util", "net_util",

11
event_monitor/Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "event_monitor"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2018"
[dependencies]
libc = "0.2.86"
serde = {version = ">=1.0.27", features = ["rc"] }
serde_derive = ">=1.0.27"
serde_json = ">=1.0.9"

77
event_monitor/src/lib.rs Normal file
View File

@ -0,0 +1,77 @@
// Copyright © 2021 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
#[macro_use]
extern crate serde_derive;
use std::borrow::Cow;
use std::collections::HashMap;
use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::time::{Duration, Instant};
static mut MONITOR: Option<(File, Instant)> = None;
/// This function must only be called once from the main process before any threads
/// are created to avoid race conditions
pub fn set_monitor(file: File) -> Result<(), std::io::Error> {
assert!(unsafe { MONITOR.is_none() });
let fd = file.as_raw_fd();
let ret = unsafe {
let mut flags = libc::fcntl(fd, libc::F_GETFL);
flags |= libc::O_NONBLOCK;
libc::fcntl(fd, libc::F_SETFL, flags)
};
if ret < 0 {
return Err(std::io::Error::last_os_error());
}
unsafe {
MONITOR = Some((file, Instant::now()));
};
Ok(())
}
#[derive(Serialize)]
struct Event<'a> {
timestamp: Duration,
source: &'a str,
event: &'a str,
properties: Option<&'a HashMap<Cow<'a, str>, Cow<'a, str>>>,
}
pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) {
if let Some((file, start)) = unsafe { MONITOR.as_ref() } {
let e = Event {
timestamp: start.elapsed(),
source,
event,
properties,
};
serde_json::to_writer_pretty(file, &e).ok();
}
}
/*
Through the use of Cow<'a, str> it is possible to use String as well as
&str as the parameters:
e.g.
event!("cpu_manager", "create_vcpu", "id", cpu_id.to_string());
*/
#[macro_export]
macro_rules! event {
($source:expr, $event:expr) => {
$crate::event_log($source, $event, None)
};
($source:expr, $event:expr, $($key:expr, $value:expr),*) => {
{
let mut properties = ::std::collections::HashMap::new();
$(
properties.insert($key.into(), $value.into());
)+
$crate::event_log($source, $event, Some(&properties))
}
};
}