xref: /cloud-hypervisor/event_monitor/src/lib.rs (revision b440cb7d2330770cd415b63544a371d4caa2db3a)
1 // Copyright © 2021 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 
6 use serde::Serialize;
7 use std::borrow::Cow;
8 use std::collections::HashMap;
9 use std::fs::File;
10 use std::io::Write;
11 use std::os::unix::io::AsRawFd;
12 use std::time::{Duration, Instant};
13 
14 static mut MONITOR: Option<(File, Instant)> = None;
15 
16 /// This function must only be called once from the main process before any threads
17 /// are created to avoid race conditions
18 pub fn set_monitor(file: File) -> Result<(), std::io::Error> {
19     assert!(unsafe { MONITOR.is_none() });
20     let fd = file.as_raw_fd();
21     let ret = unsafe {
22         let mut flags = libc::fcntl(fd, libc::F_GETFL);
23         flags |= libc::O_NONBLOCK;
24         libc::fcntl(fd, libc::F_SETFL, flags)
25     };
26     if ret < 0 {
27         return Err(std::io::Error::last_os_error());
28     }
29     unsafe {
30         MONITOR = Some((file, Instant::now()));
31     };
32     Ok(())
33 }
34 
35 #[derive(Serialize)]
36 struct Event<'a> {
37     timestamp: Duration,
38     source: &'a str,
39     event: &'a str,
40     properties: Option<&'a HashMap<Cow<'a, str>, Cow<'a, str>>>,
41 }
42 
43 pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) {
44     if let Some((file, start)) = unsafe { MONITOR.as_ref() } {
45         let e = Event {
46             timestamp: start.elapsed(),
47             source,
48             event,
49             properties,
50         };
51         serde_json::to_writer_pretty(file, &e).ok();
52 
53         let mut file = file;
54         file.write_all(b"\n\n").ok();
55     }
56 }
57 
58 /*
59     Through the use of Cow<'a, str> it is possible to use String as well as
60     &str as the parameters:
61     e.g.
62     event!("cpu_manager", "create_vcpu", "id", cpu_id.to_string());
63 */
64 #[macro_export]
65 macro_rules! event {
66     ($source:expr, $event:expr) => {
67         $crate::event_log($source, $event, None)
68     };
69     ($source:expr, $event:expr, $($key:expr, $value:expr),*) => {
70         {
71             let mut properties = ::std::collections::HashMap::new();
72             $(
73                 properties.insert($key.into(), $value.into());
74             )+
75             $crate::event_log($source, $event, Some(&properties))
76         }
77      };
78 
79 }
80