mod config;
mod events;
mod shared;
#[cfg(feature = "telemetry")]
mod client;
mod queue;
pub use config::TelemetryConfig;
pub use events::{TelemetryEvent, ValidationRunEvent, is_valid_rule_id};
pub use queue::EventQueue;
#[cfg(feature = "telemetry")]
pub use client::TelemetryClient;
use std::collections::HashMap;
#[cfg(feature = "telemetry")]
use std::thread;
pub fn record_validation(
file_type_counts: HashMap<String, u32>,
rule_trigger_counts: HashMap<String, u32>,
error_count: u32,
warning_count: u32,
info_count: u32,
duration_ms: u64,
) {
let config = match TelemetryConfig::load() {
Ok(c) => c,
Err(_) => return,
};
if !config.is_enabled() {
return;
}
let event = TelemetryEvent::ValidationRun(ValidationRunEvent {
file_type_counts,
rule_trigger_counts,
error_count,
warning_count,
info_count,
duration_ms,
timestamp: chrono_timestamp(),
});
let mut queue = match EventQueue::load() {
Ok(q) => q,
Err(_) => return,
};
if queue.push(event).is_ok() {
#[cfg(feature = "telemetry")]
{
thread::spawn(move || {
try_submit_queued_events(&config, &mut queue);
});
}
}
}
#[cfg(feature = "telemetry")]
fn try_submit_queued_events(config: &TelemetryConfig, queue: &mut EventQueue) {
if let Ok(client) = TelemetryClient::new(config) {
let events = queue.take_batch(10);
if !events.is_empty() {
match client.submit_batch(&events) {
Ok(_) => {
queue.remove_batch(events.len());
let _ = queue.save();
}
Err(_) => {
}
}
}
}
}
fn chrono_timestamp() -> String {
shared::chrono_timestamp()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_chrono_timestamp_format() {
let ts = chrono_timestamp();
assert!(ts.len() == 20);
assert!(ts.ends_with('Z'));
assert!(ts.contains('T'));
let year: i32 = ts[0..4].parse().unwrap();
assert!((2020..=2100).contains(&year));
}
}