wp_knowledge/
telemetry.rs1use std::sync::{Arc, OnceLock, RwLock};
2use std::time::Duration;
3
4use crate::loader::ProviderKind;
5use crate::runtime::QueryModeTag;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum CacheLayer {
9 Local,
10 Result,
11 Metadata,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum CacheOutcome {
16 Hit,
17 Miss,
18}
19
20#[derive(Debug, Clone)]
21pub struct CacheTelemetryEvent {
22 pub layer: CacheLayer,
23 pub outcome: CacheOutcome,
24 pub provider_kind: Option<ProviderKind>,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum ReloadOutcome {
29 Success,
30 Failure,
31}
32
33#[derive(Debug, Clone)]
34pub struct ReloadTelemetryEvent {
35 pub outcome: ReloadOutcome,
36 pub provider_kind: ProviderKind,
37}
38
39#[derive(Debug, Clone)]
40pub struct QueryTelemetryEvent {
41 pub provider_kind: ProviderKind,
42 pub mode: QueryModeTag,
43 pub success: bool,
44 pub elapsed: Duration,
45}
46
47pub trait KnowledgeTelemetry: Send + Sync {
48 fn on_cache(&self, _event: &CacheTelemetryEvent) {}
49 fn on_reload(&self, _event: &ReloadTelemetryEvent) {}
50 fn on_query(&self, _event: &QueryTelemetryEvent) {}
51}
52
53#[derive(Debug, Default)]
54pub struct NoopTelemetry;
55
56impl KnowledgeTelemetry for NoopTelemetry {}
57
58fn telemetry_slot() -> &'static RwLock<Arc<dyn KnowledgeTelemetry>> {
59 static SLOT: OnceLock<RwLock<Arc<dyn KnowledgeTelemetry>>> = OnceLock::new();
60 SLOT.get_or_init(|| RwLock::new(Arc::new(NoopTelemetry)))
61}
62
63pub fn telemetry() -> Arc<dyn KnowledgeTelemetry> {
64 telemetry_slot()
65 .read()
66 .expect("knowledge telemetry lock poisoned")
67 .clone()
68}
69
70pub fn install_telemetry(telemetry: Arc<dyn KnowledgeTelemetry>) -> Arc<dyn KnowledgeTelemetry> {
71 let mut guard = telemetry_slot()
72 .write()
73 .expect("knowledge telemetry lock poisoned");
74 std::mem::replace(&mut *guard, telemetry)
75}
76
77pub fn reset_telemetry() -> Arc<dyn KnowledgeTelemetry> {
78 install_telemetry(Arc::new(NoopTelemetry))
79}