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 // SAFETY: there is only one caller of this function, so MONITOR is written to only once 20 assert!(unsafe { MONITOR.is_none() }); 21 let fd = file.as_raw_fd(); 22 // SAFETY: FFI call to configure the fd 23 let ret = unsafe { 24 let mut flags = libc::fcntl(fd, libc::F_GETFL); 25 flags |= libc::O_NONBLOCK; 26 libc::fcntl(fd, libc::F_SETFL, flags) 27 }; 28 if ret < 0 { 29 return Err(std::io::Error::last_os_error()); 30 } 31 // SAFETY: MONITOR is None. Nobody else can hold a reference to it. 32 unsafe { 33 MONITOR = Some((file, Instant::now())); 34 }; 35 Ok(()) 36 } 37 38 #[derive(Serialize)] 39 struct Event<'a> { 40 timestamp: Duration, 41 source: &'a str, 42 event: &'a str, 43 properties: Option<&'a HashMap<Cow<'a, str>, Cow<'a, str>>>, 44 } 45 46 pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) { 47 // SAFETY: MONITOR is always in a valid state (None or Some). 48 if let Some((file, start)) = unsafe { MONITOR.as_ref() } { 49 let e = Event { 50 timestamp: start.elapsed(), 51 source, 52 event, 53 properties, 54 }; 55 serde_json::to_writer_pretty(file, &e).ok(); 56 57 let mut file = file; 58 file.write_all(b"\n\n").ok(); 59 } 60 } 61 62 /* 63 Through the use of Cow<'a, str> it is possible to use String as well as 64 &str as the parameters: 65 e.g. 66 event!("cpu_manager", "create_vcpu", "id", cpu_id.to_string()); 67 */ 68 #[macro_export] 69 macro_rules! event { 70 ($source:expr, $event:expr) => { 71 $crate::event_log($source, $event, None) 72 }; 73 ($source:expr, $event:expr, $($key:expr, $value:expr),*) => { 74 { 75 let mut properties = ::std::collections::HashMap::new(); 76 $( 77 properties.insert($key.into(), $value.into()); 78 )+ 79 $crate::event_log($source, $event, Some(&properties)) 80 } 81 }; 82 83 } 84