hashtree_cli/
diagnostics.rs1use nostr::Filter;
2
3#[derive(Debug, Clone, Copy, Default)]
4pub struct ProcessMemorySnapshot {
5 pub vm_rss_kb: Option<u64>,
6 pub rss_anon_kb: Option<u64>,
7 pub anonymous_kb: Option<u64>,
8 pub threads: Option<u64>,
9}
10
11#[cfg(target_os = "linux")]
12pub fn process_memory_snapshot() -> ProcessMemorySnapshot {
13 let mut snapshot = ProcessMemorySnapshot::default();
14
15 if let Ok(status) = std::fs::read_to_string("/proc/self/status") {
16 for line in status.lines() {
17 if let Some(value) = line.strip_prefix("VmRSS:") {
18 snapshot.vm_rss_kb = parse_status_kb(value);
19 } else if let Some(value) = line.strip_prefix("RssAnon:") {
20 snapshot.rss_anon_kb = parse_status_kb(value);
21 } else if let Some(value) = line.strip_prefix("Threads:") {
22 snapshot.threads = value.trim().parse::<u64>().ok();
23 }
24 }
25 }
26
27 if let Ok(rollup) = std::fs::read_to_string("/proc/self/smaps_rollup") {
28 for line in rollup.lines() {
29 if let Some(value) = line.strip_prefix("Anonymous:") {
30 snapshot.anonymous_kb = parse_status_kb(value);
31 break;
32 }
33 }
34 }
35
36 snapshot
37}
38
39#[cfg(not(target_os = "linux"))]
40pub fn process_memory_snapshot() -> ProcessMemorySnapshot {
41 ProcessMemorySnapshot::default()
42}
43
44pub fn nostr_filter_summary(filter: &Filter) -> String {
45 let generic_tag_values = filter
46 .generic_tags
47 .values()
48 .map(|values| values.len())
49 .sum::<usize>();
50 format!(
51 "ids={} authors={} kinds={} tags={} tag_values={} search={} since={} until={} limit={}",
52 filter.ids.as_ref().map(|ids| ids.len()).unwrap_or(0),
53 filter
54 .authors
55 .as_ref()
56 .map(|authors| authors.len())
57 .unwrap_or(0),
58 filter.kinds.as_ref().map(|kinds| kinds.len()).unwrap_or(0),
59 filter.generic_tags.len(),
60 generic_tag_values,
61 filter.search.is_some(),
62 filter.since.is_some(),
63 filter.until.is_some(),
64 filter
65 .limit
66 .map(|limit| limit.to_string())
67 .unwrap_or_else(|| "none".to_string()),
68 )
69}
70
71pub fn nostr_filters_summary(filters: &[Filter]) -> String {
72 const MAX_FILTERS_IN_LOG: usize = 4;
73 let mut summaries = filters
74 .iter()
75 .take(MAX_FILTERS_IN_LOG)
76 .map(nostr_filter_summary)
77 .collect::<Vec<_>>();
78 if filters.len() > MAX_FILTERS_IN_LOG {
79 summaries.push(format!(
80 "...+{} filters",
81 filters.len() - MAX_FILTERS_IN_LOG
82 ));
83 }
84 summaries.join("; ")
85}
86
87#[cfg(target_os = "linux")]
88pub fn trim_process_allocations() {
89 unsafe {
91 libc::malloc_trim(0);
92 }
93}
94
95#[cfg(not(target_os = "linux"))]
96pub fn trim_process_allocations() {}
97
98#[cfg(target_os = "linux")]
99fn parse_status_kb(value: &str) -> Option<u64> {
100 value.split_whitespace().next()?.parse::<u64>().ok()
101}