use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use windows::core::GUID;
use crate::native::tdh;
use crate::native::tdh::TraceEventInfo;
use crate::native::etw_types::event_record::EventRecord;
use crate::schema::Schema;
#[derive(Debug)]
pub enum SchemaError {
TdhNativeError(tdh::TdhNativeError),
}
impl From<tdh::TdhNativeError> for SchemaError {
fn from(err: tdh::TdhNativeError) -> Self {
SchemaError::TdhNativeError(err)
}
}
type SchemaResult<T> = Result<T, SchemaError>;
#[derive(Debug, Eq, PartialEq, Hash)]
struct SchemaKey {
provider: GUID,
id: u16,
version: u8,
opcode: u8,
level: u8,
}
impl SchemaKey {
pub fn new(event: &EventRecord) -> Self {
SchemaKey {
provider: event.provider_id(),
id: event.event_id(),
opcode: event.opcode(),
version: event.version(),
level: event.level(),
}
}
}
#[derive(Default)]
pub struct SchemaLocator {
schemas: Mutex<HashMap<SchemaKey, Arc<Schema>>>,
}
impl std::fmt::Debug for SchemaLocator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SchemaLocator")
.field("len", &self.schemas.try_lock().map(|guard| guard.len()))
.finish()
}
}
impl SchemaLocator {
pub(crate) fn new() -> Self {
SchemaLocator {
schemas: Mutex::new(HashMap::new()),
}
}
pub fn event_schema(&self, event: &EventRecord) -> SchemaResult<Arc<Schema>> {
let key = SchemaKey::new(event);
let mut schemas = self.schemas.lock().unwrap();
match schemas.get(&key) {
Some(s) => Ok(Arc::clone(s)),
None => {
let tei = TraceEventInfo::build_from_event(event)?;
let new_schema = Arc::from(Schema::new(tei));
schemas.insert(key, Arc::clone(&new_schema));
Ok(new_schema)
}
}
}
}