Skip to content

Commit 1f1125c

Browse files
refactor: udpate docs and tests for the telemetry crate (#25432)
- Introduced traits, `ParquetMetrics` and `SystemInfoProvider` to enable writing easier tests - Uses mockito for code that depends on reqwest::Client and also uses mockall to generally mock any traits like `SystemInfoProvider` - Minor updates to docs
1 parent c4534b0 commit 1f1125c

File tree

12 files changed

+297
-66
lines changed

12 files changed

+297
-66
lines changed

Cargo.lock

Lines changed: 41 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ indexmap = { version = "2.2.6" }
7474
libc = { version = "0.2" }
7575
mime = "0.3.17"
7676
mockito = { version = "1.4.0", default-features = false }
77+
mockall = { version = "0.13.0" }
7778
num_cpus = "1.16.0"
7879
object_store = "0.10.2"
7980
parking_lot = "0.12.1"

influxdb3_server/src/lib.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,12 @@ mod tests {
236236
use influxdb3_id::{DbId, TableId};
237237
use influxdb3_telemetry::store::TelemetryStore;
238238
use influxdb3_wal::WalConfig;
239-
use influxdb3_write::last_cache::LastCacheProvider;
240239
use influxdb3_write::parquet_cache::test_cached_obj_store_and_oracle;
241240
use influxdb3_write::persister::Persister;
242241
use influxdb3_write::WriteBuffer;
242+
use influxdb3_write::{
243+
last_cache::LastCacheProvider, write_buffer::persisted_files::PersistedFiles,
244+
};
243245
use iox_query::exec::{DedicatedExecutor, Executor, ExecutorConfig};
244246
use iox_time::{MockProvider, Time};
245247
use object_store::DynObjectStore;
@@ -787,9 +789,10 @@ mod tests {
787789
.unwrap(),
788790
);
789791

790-
let dummy_telem_store = TelemetryStore::new_without_background_runners(Arc::clone(
791-
&write_buffer_impl.persisted_files(),
792-
));
792+
let parquet_metrics_provider: Arc<PersistedFiles> =
793+
Arc::clone(&write_buffer_impl.persisted_files());
794+
let dummy_telem_store =
795+
TelemetryStore::new_without_background_runners(parquet_metrics_provider);
793796
let write_buffer: Arc<dyn WriteBuffer> = write_buffer_impl;
794797
let common_state = crate::CommonServerState::new(
795798
Arc::clone(&metrics),

influxdb3_server/src/query_executor.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -604,8 +604,11 @@ mod tests {
604604
use influxdb3_telemetry::store::TelemetryStore;
605605
use influxdb3_wal::{Gen1Duration, WalConfig};
606606
use influxdb3_write::{
607-
last_cache::LastCacheProvider, parquet_cache::test_cached_obj_store_and_oracle,
608-
persister::Persister, write_buffer::WriteBufferImpl, WriteBuffer,
607+
last_cache::LastCacheProvider,
608+
parquet_cache::test_cached_obj_store_and_oracle,
609+
persister::Persister,
610+
write_buffer::{persisted_files::PersistedFiles, WriteBufferImpl},
611+
WriteBuffer,
609612
};
610613
use iox_query::exec::{DedicatedExecutor, Executor, ExecutorConfig};
611614
use iox_time::{MockProvider, Time};
@@ -651,7 +654,7 @@ mod tests {
651654
let host_id = Arc::from("dummy-host-id");
652655
let instance_id = Arc::from("instance-id");
653656
let catalog = Arc::new(Catalog::new(host_id, instance_id));
654-
let write_buffer = Arc::new(
657+
let write_buffer_impl = Arc::new(
655658
WriteBufferImpl::new(
656659
Arc::clone(&persister),
657660
Arc::clone(&catalog),
@@ -670,10 +673,9 @@ mod tests {
670673
.unwrap(),
671674
);
672675

673-
let dummy_telem_store = TelemetryStore::new_without_background_runners(Arc::clone(
674-
&write_buffer.persisted_files(),
675-
));
676-
let write_buffer: Arc<dyn WriteBuffer> = write_buffer;
676+
let persisted_files: Arc<PersistedFiles> = Arc::clone(&write_buffer_impl.persisted_files());
677+
let dummy_telem_store = TelemetryStore::new_without_background_runners(persisted_files);
678+
let write_buffer: Arc<dyn WriteBuffer> = write_buffer_impl;
677679
let metrics = Arc::new(Registry::new());
678680
let df_config = Arc::new(Default::default());
679681
let query_executor = QueryExecutorImpl::new(

influxdb3_telemetry/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ sysinfo.workspace = true
1818
num.workspace = true
1919
thiserror.workspace = true
2020

21-
# Local Deps
22-
influxdb3_write = { path = "../influxdb3_write" }
23-
2421
[dev-dependencies]
2522
test-log.workspace = true
2623
proptest.workspace = true
24+
mockito.workspace = true
25+
mockall.workspace = true
2726

influxdb3_telemetry/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,7 @@ pub enum TelemetryError {
2020
}
2121

2222
pub type Result<T, E = TelemetryError> = std::result::Result<T, E>;
23+
24+
pub trait ParquetMetrics: Send + Sync + std::fmt::Debug + 'static {
25+
fn get_metrics(&self) -> (u64, f64, u64);
26+
}

influxdb3_telemetry/src/sampler.rs

Lines changed: 118 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,81 @@
11
use std::{sync::Arc, time::Duration};
22

3+
#[cfg(test)]
4+
use mockall::{automock, predicate::*};
35
use observability_deps::tracing::debug;
4-
use sysinfo::{ProcessRefreshKind, System};
6+
use sysinfo::{Pid, ProcessRefreshKind, System};
57

8+
use crate::store::TelemetryStore;
69
use crate::Result;
7-
use crate::{store::TelemetryStore, TelemetryError};
810

9-
struct CpuAndMemorySampler {
11+
#[cfg_attr(test, automock)]
12+
pub trait SystemInfoProvider: Send + Sync + 'static {
13+
fn refresh_metrics(&mut self, pid: Pid);
14+
15+
fn get_pid(&self) -> Result<Pid, &'static str>;
16+
17+
fn get_process_specific_metrics(&self, pid: Pid) -> Option<(f32, u64)>;
18+
}
19+
20+
struct SystemInfo {
1021
system: System,
1122
}
1223

13-
impl CpuAndMemorySampler {
14-
pub fn new(system: System) -> Self {
15-
Self { system }
24+
impl SystemInfo {
25+
pub fn new() -> SystemInfo {
26+
Self {
27+
system: System::new(),
28+
}
1629
}
30+
}
1731

32+
impl SystemInfoProvider for SystemInfo {
1833
/// This method picks the memory and cpu usage for this process using the
1934
/// pid.
20-
pub fn get_cpu_and_mem_used(&mut self) -> Result<(f32, u64)> {
21-
let pid = sysinfo::get_current_pid().map_err(TelemetryError::CannotGetPid)?;
35+
fn refresh_metrics(&mut self, pid: Pid) {
2236
self.system.refresh_pids_specifics(
2337
&[pid],
2438
ProcessRefreshKind::new()
2539
.with_cpu()
2640
.with_memory()
2741
.with_disk_usage(),
2842
);
43+
}
2944

30-
let process = self
31-
.system
32-
.process(pid)
33-
.unwrap_or_else(|| panic!("cannot get process with pid: {}", pid));
45+
fn get_pid(&self) -> Result<Pid, &'static str> {
46+
sysinfo::get_current_pid()
47+
}
48+
49+
fn get_process_specific_metrics<'a>(&self, pid: Pid) -> Option<(f32, u64)> {
50+
let process = self.system.process(pid)?;
3451

35-
let memory_used = process.memory();
3652
let cpu_used = process.cpu_usage();
53+
let memory_used = process.memory();
54+
Some((cpu_used, memory_used))
55+
}
56+
}
57+
58+
struct CpuAndMemorySampler {
59+
system: Box<dyn SystemInfoProvider>,
60+
}
3761

62+
impl CpuAndMemorySampler {
63+
pub fn new(system: impl SystemInfoProvider) -> Self {
64+
Self {
65+
system: Box::new(system),
66+
}
67+
}
68+
69+
pub fn get_cpu_and_mem_used(&mut self) -> Option<(f32, u64)> {
70+
let pid = self.system.get_pid().ok()?;
71+
self.system.refresh_metrics(pid);
72+
let (cpu_used, memory_used) = self.system.get_process_specific_metrics(pid)?;
3873
debug!(
39-
mem_used = ?memory_used,
4074
cpu_used = ?cpu_used,
75+
mem_used = ?memory_used,
4176
"trying to sample data for cpu/memory");
4277

43-
Ok((cpu_used, memory_used))
78+
Some((cpu_used, memory_used))
4479
}
4580
}
4681

@@ -49,18 +84,81 @@ pub(crate) async fn sample_metrics(
4984
duration_secs: Duration,
5085
) -> tokio::task::JoinHandle<()> {
5186
tokio::spawn(async move {
52-
let mut sampler = CpuAndMemorySampler::new(System::new());
87+
let mut sampler = CpuAndMemorySampler::new(SystemInfo::new());
5388

5489
// sample every minute
5590
let mut interval = tokio::time::interval(duration_secs);
5691
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
5792

5893
loop {
5994
interval.tick().await;
60-
if let Ok((cpu_used, memory_used)) = sampler.get_cpu_and_mem_used() {
61-
store.add_cpu_and_memory(cpu_used, memory_used);
62-
store.rollup_events();
63-
}
95+
sample_all_metrics(&mut sampler, &store);
6496
}
6597
})
6698
}
99+
100+
fn sample_all_metrics(sampler: &mut CpuAndMemorySampler, store: &Arc<TelemetryStore>) {
101+
if let Some((cpu_used, memory_used)) = sampler.get_cpu_and_mem_used() {
102+
store.add_cpu_and_memory(cpu_used, memory_used);
103+
} else {
104+
debug!("Cannot get cpu/mem usage stats for this process");
105+
}
106+
store.rollup_events();
107+
}
108+
109+
#[cfg(test)]
110+
mod tests {
111+
112+
use crate::ParquetMetrics;
113+
114+
use super::*;
115+
116+
#[derive(Debug)]
117+
struct MockParquetMetrics;
118+
119+
impl ParquetMetrics for MockParquetMetrics {
120+
fn get_metrics(&self) -> (u64, f64, u64) {
121+
(10, 20.0, 30)
122+
}
123+
}
124+
125+
#[test]
126+
fn test_sample_all_metrics() {
127+
let mut mock_sys_info_provider = MockSystemInfoProvider::new();
128+
let store = TelemetryStore::new_without_background_runners(Arc::from(MockParquetMetrics));
129+
130+
mock_sys_info_provider
131+
.expect_get_pid()
132+
.return_const(Ok(Pid::from(5)));
133+
mock_sys_info_provider
134+
.expect_refresh_metrics()
135+
.return_const(());
136+
mock_sys_info_provider
137+
.expect_get_process_specific_metrics()
138+
.return_const(Some((10.0f32, 100u64)));
139+
140+
let mut sampler = CpuAndMemorySampler::new(mock_sys_info_provider);
141+
142+
sample_all_metrics(&mut sampler, &store);
143+
}
144+
145+
#[test]
146+
fn test_sample_all_metrics_with_call_failure() {
147+
let mut mock_sys_info_provider = MockSystemInfoProvider::new();
148+
let store = TelemetryStore::new_without_background_runners(Arc::from(MockParquetMetrics));
149+
150+
mock_sys_info_provider
151+
.expect_get_pid()
152+
.return_const(Ok(Pid::from(5)));
153+
mock_sys_info_provider
154+
.expect_refresh_metrics()
155+
.return_const(());
156+
mock_sys_info_provider
157+
.expect_get_process_specific_metrics()
158+
.return_const(None);
159+
160+
let mut sampler = CpuAndMemorySampler::new(mock_sys_info_provider);
161+
162+
sample_all_metrics(&mut sampler, &store);
163+
}
164+
}

0 commit comments

Comments
 (0)