1use anyhow::Result;
5use serde_json::Value;
6use std::time::Duration;
7
8#[cfg(feature = "telemetry-datadog")]
9mod datadog;
10#[cfg(feature = "telemetry-posthog")]
11mod posthog;
12mod pull_import;
13
14#[derive(Debug, Clone, Copy)]
16pub struct PullWindow {
17 pub days: u32,
18}
19
20impl Default for PullWindow {
21 fn default() -> Self {
22 Self { days: 7 }
23 }
24}
25
26#[derive(Debug, Clone, Default)]
28pub struct PullPage {
29 pub next_cursor: Option<String>,
30 pub items: Vec<Value>,
31}
32
33pub use pull_import::import_pull_page_to_remote;
34
35pub trait TelemetryQueryProvider: Send + Sync {
37 fn health(&self) -> Result<()>;
38 fn schema_version(&self) -> &str;
40 fn pull(&self, window: PullWindow, cursor: Option<&str>) -> Result<PullPage>;
41}
42
43#[allow(dead_code)]
45const HTTP_TIMEOUT: Duration = Duration::from_secs(30);
46
47pub fn from_config(
49 q: &crate::core::config::TelemetryQueryConfig,
50) -> Option<std::sync::Arc<dyn TelemetryQueryProvider>> {
51 use crate::core::config::QueryAuthority;
52 match q.provider {
53 QueryAuthority::None => None,
54 #[cfg(feature = "telemetry-posthog")]
55 QueryAuthority::Posthog => {
56 posthog::posthog_from_env()
58 }
59 #[cfg(not(feature = "telemetry-posthog"))]
60 QueryAuthority::Posthog => {
61 tracing::warn!(
62 "telemetry query provider is posthog but `telemetry-posthog` feature is off"
63 );
64 None
65 }
66 #[cfg(feature = "telemetry-datadog")]
67 QueryAuthority::Datadog => datadog::datadog_from_env(),
68 #[cfg(not(feature = "telemetry-datadog"))]
69 QueryAuthority::Datadog => {
70 tracing::warn!(
71 "telemetry query provider is datadog but `telemetry-datadog` feature is off"
72 );
73 None
74 }
75 }
76}
77
78#[allow(dead_code)]
79pub(crate) fn http_timeout() -> Duration {
80 HTTP_TIMEOUT
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 struct Nop;
88 impl TelemetryQueryProvider for Nop {
89 fn health(&self) -> Result<()> {
90 Ok(())
91 }
92 fn schema_version(&self) -> &'static str {
93 "test"
94 }
95 fn pull(&self, _window: PullWindow, _cursor: Option<&str>) -> Result<PullPage> {
96 Ok(PullPage::default())
97 }
98 }
99
100 #[test]
101 fn nop_pull_empty() {
102 let p = Nop;
103 assert_eq!(p.schema_version(), "test");
104 let page = p.pull(PullWindow { days: 1 }, None).unwrap();
105 assert!(page.items.is_empty());
106 }
107}