Skip to main content

cachekit/metrics/
exporter.rs

1use std::io::Write;
2use std::sync::Mutex;
3
4use crate::metrics::snapshot::{
5    ArcMetricsSnapshot, CacheMetricsSnapshot, CarMetricsSnapshot, ClockMetricsSnapshot,
6    ClockProMetricsSnapshot, CoreOnlyMetricsSnapshot, LfuMetricsSnapshot, LruKMetricsSnapshot,
7    LruMetricsSnapshot, MfuMetricsSnapshot, NruMetricsSnapshot, S3FifoMetricsSnapshot,
8    SlruMetricsSnapshot, TwoQMetricsSnapshot,
9};
10use crate::metrics::traits::MetricsExporter;
11
12/// Prometheus text exporter for cache metrics snapshots.
13///
14/// Writes metrics in the [Prometheus text exposition format] so they can be
15/// scraped by Prometheus or forwarded to an OpenTelemetry collector.
16/// Implements [`MetricsExporter`] for every policy-specific snapshot type.
17///
18/// I/O errors during export are silently ignored — this is intentional for
19/// fire-and-forget monitoring where a write failure should not interrupt
20/// cache operations.
21///
22/// # Panics
23///
24/// [`export`](MetricsExporter::export) panics if the internal [`Mutex`] is
25/// poisoned (i.e. a previous thread panicked while holding the writer lock).
26///
27/// # Examples
28///
29/// ```
30/// use cachekit::metrics::exporter::PrometheusTextExporter;
31/// use cachekit::metrics::traits::MetricsExporter;
32/// use cachekit::metrics::snapshot::CoreOnlyMetricsSnapshot;
33///
34/// let exporter = PrometheusTextExporter::new("myapp_cache", Vec::new());
35/// let snapshot = CoreOnlyMetricsSnapshot::default();
36/// exporter.export(&snapshot);
37/// ```
38///
39/// [Prometheus text exposition format]: https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format
40#[derive(Debug)]
41pub struct PrometheusTextExporter<W> {
42    prefix: String,
43    writer: Mutex<W>,
44}
45
46impl<W: Write + Send> PrometheusTextExporter<W> {
47    /// Creates a new exporter that writes metrics with the given `prefix` to `writer`.
48    pub fn new(prefix: impl Into<String>, writer: W) -> Self {
49        Self {
50            prefix: prefix.into(),
51            writer: Mutex::new(writer),
52        }
53    }
54
55    fn write_counter(&self, name: &str, value: u64) {
56        let mut writer = self
57            .writer
58            .lock()
59            .expect("metrics exporter writer poisoned");
60        let _ = writeln!(writer, "# TYPE {} counter", name);
61        let _ = writeln!(writer, "{} {}", name, value);
62    }
63
64    fn write_gauge(&self, name: &str, value: u64) {
65        let mut writer = self
66            .writer
67            .lock()
68            .expect("metrics exporter writer poisoned");
69        let _ = writeln!(writer, "# TYPE {} gauge", name);
70        let _ = writeln!(writer, "{} {}", name, value);
71    }
72
73    fn metric_name(&self, suffix: &str) -> String {
74        if self.prefix.is_empty() {
75            suffix.to_string()
76        } else {
77            format!("{}_{}", self.prefix, suffix)
78        }
79    }
80}
81
82impl<W: Write + Send> MetricsExporter<CacheMetricsSnapshot> for PrometheusTextExporter<W> {
83    fn export(&self, snapshot: &CacheMetricsSnapshot) {
84        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
85        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
86        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
87        self.write_counter(
88            &self.metric_name("insert_calls_total"),
89            snapshot.insert_calls,
90        );
91        self.write_counter(
92            &self.metric_name("insert_updates_total"),
93            snapshot.insert_updates,
94        );
95        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
96        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
97        self.write_counter(
98            &self.metric_name("evicted_entries_total"),
99            snapshot.evicted_entries,
100        );
101        self.write_counter(&self.metric_name("stale_skips_total"), snapshot.stale_skips);
102        self.write_counter(
103            &self.metric_name("evict_scan_steps_total"),
104            snapshot.evict_scan_steps,
105        );
106        self.write_counter(
107            &self.metric_name("pop_oldest_calls_total"),
108            snapshot.pop_oldest_calls,
109        );
110        self.write_counter(
111            &self.metric_name("pop_oldest_found_total"),
112            snapshot.pop_oldest_found,
113        );
114        self.write_counter(
115            &self.metric_name("pop_oldest_empty_or_stale_total"),
116            snapshot.pop_oldest_empty_or_stale,
117        );
118        self.write_counter(
119            &self.metric_name("peek_oldest_calls_total"),
120            snapshot.peek_oldest_calls,
121        );
122        self.write_counter(
123            &self.metric_name("peek_oldest_found_total"),
124            snapshot.peek_oldest_found,
125        );
126        self.write_counter(
127            &self.metric_name("age_rank_calls_total"),
128            snapshot.age_rank_calls,
129        );
130        self.write_counter(
131            &self.metric_name("age_rank_found_total"),
132            snapshot.age_rank_found,
133        );
134        self.write_counter(
135            &self.metric_name("age_rank_scan_steps_total"),
136            snapshot.age_rank_scan_steps,
137        );
138        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
139        self.write_gauge(
140            &self.metric_name("insertion_order_len"),
141            snapshot.insertion_order_len as u64,
142        );
143        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
144    }
145}
146
147impl<W: Write + Send> MetricsExporter<LruMetricsSnapshot> for PrometheusTextExporter<W> {
148    fn export(&self, snapshot: &LruMetricsSnapshot) {
149        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
150        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
151        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
152        self.write_counter(
153            &self.metric_name("insert_calls_total"),
154            snapshot.insert_calls,
155        );
156        self.write_counter(
157            &self.metric_name("insert_updates_total"),
158            snapshot.insert_updates,
159        );
160        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
161        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
162        self.write_counter(
163            &self.metric_name("evicted_entries_total"),
164            snapshot.evicted_entries,
165        );
166        self.write_counter(
167            &self.metric_name("pop_lru_calls_total"),
168            snapshot.pop_lru_calls,
169        );
170        self.write_counter(
171            &self.metric_name("pop_lru_found_total"),
172            snapshot.pop_lru_found,
173        );
174        self.write_counter(
175            &self.metric_name("peek_lru_calls_total"),
176            snapshot.peek_lru_calls,
177        );
178        self.write_counter(
179            &self.metric_name("peek_lru_found_total"),
180            snapshot.peek_lru_found,
181        );
182        self.write_counter(&self.metric_name("touch_calls_total"), snapshot.touch_calls);
183        self.write_counter(&self.metric_name("touch_found_total"), snapshot.touch_found);
184        self.write_counter(
185            &self.metric_name("recency_rank_calls_total"),
186            snapshot.recency_rank_calls,
187        );
188        self.write_counter(
189            &self.metric_name("recency_rank_found_total"),
190            snapshot.recency_rank_found,
191        );
192        self.write_counter(
193            &self.metric_name("recency_rank_scan_steps_total"),
194            snapshot.recency_rank_scan_steps,
195        );
196        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
197        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
198    }
199}
200
201impl<W: Write + Send> MetricsExporter<LfuMetricsSnapshot> for PrometheusTextExporter<W> {
202    fn export(&self, snapshot: &LfuMetricsSnapshot) {
203        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
204        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
205        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
206        self.write_counter(
207            &self.metric_name("insert_calls_total"),
208            snapshot.insert_calls,
209        );
210        self.write_counter(
211            &self.metric_name("insert_updates_total"),
212            snapshot.insert_updates,
213        );
214        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
215        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
216        self.write_counter(
217            &self.metric_name("evicted_entries_total"),
218            snapshot.evicted_entries,
219        );
220        self.write_counter(
221            &self.metric_name("pop_lfu_calls_total"),
222            snapshot.pop_lfu_calls,
223        );
224        self.write_counter(
225            &self.metric_name("pop_lfu_found_total"),
226            snapshot.pop_lfu_found,
227        );
228        self.write_counter(
229            &self.metric_name("peek_lfu_calls_total"),
230            snapshot.peek_lfu_calls,
231        );
232        self.write_counter(
233            &self.metric_name("peek_lfu_found_total"),
234            snapshot.peek_lfu_found,
235        );
236        self.write_counter(
237            &self.metric_name("frequency_calls_total"),
238            snapshot.frequency_calls,
239        );
240        self.write_counter(
241            &self.metric_name("frequency_found_total"),
242            snapshot.frequency_found,
243        );
244        self.write_counter(
245            &self.metric_name("reset_frequency_calls_total"),
246            snapshot.reset_frequency_calls,
247        );
248        self.write_counter(
249            &self.metric_name("reset_frequency_found_total"),
250            snapshot.reset_frequency_found,
251        );
252        self.write_counter(
253            &self.metric_name("increment_frequency_calls_total"),
254            snapshot.increment_frequency_calls,
255        );
256        self.write_counter(
257            &self.metric_name("increment_frequency_found_total"),
258            snapshot.increment_frequency_found,
259        );
260        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
261        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
262    }
263}
264
265impl<W: Write + Send> MetricsExporter<LruKMetricsSnapshot> for PrometheusTextExporter<W> {
266    fn export(&self, snapshot: &LruKMetricsSnapshot) {
267        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
268        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
269        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
270        self.write_counter(
271            &self.metric_name("insert_calls_total"),
272            snapshot.insert_calls,
273        );
274        self.write_counter(
275            &self.metric_name("insert_updates_total"),
276            snapshot.insert_updates,
277        );
278        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
279        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
280        self.write_counter(
281            &self.metric_name("evicted_entries_total"),
282            snapshot.evicted_entries,
283        );
284        self.write_counter(
285            &self.metric_name("pop_lru_calls_total"),
286            snapshot.pop_lru_calls,
287        );
288        self.write_counter(
289            &self.metric_name("pop_lru_found_total"),
290            snapshot.pop_lru_found,
291        );
292        self.write_counter(
293            &self.metric_name("peek_lru_calls_total"),
294            snapshot.peek_lru_calls,
295        );
296        self.write_counter(
297            &self.metric_name("peek_lru_found_total"),
298            snapshot.peek_lru_found,
299        );
300        self.write_counter(&self.metric_name("touch_calls_total"), snapshot.touch_calls);
301        self.write_counter(&self.metric_name("touch_found_total"), snapshot.touch_found);
302        self.write_counter(
303            &self.metric_name("recency_rank_calls_total"),
304            snapshot.recency_rank_calls,
305        );
306        self.write_counter(
307            &self.metric_name("recency_rank_found_total"),
308            snapshot.recency_rank_found,
309        );
310        self.write_counter(
311            &self.metric_name("recency_rank_scan_steps_total"),
312            snapshot.recency_rank_scan_steps,
313        );
314        self.write_counter(
315            &self.metric_name("pop_lru_k_calls_total"),
316            snapshot.pop_lru_k_calls,
317        );
318        self.write_counter(
319            &self.metric_name("pop_lru_k_found_total"),
320            snapshot.pop_lru_k_found,
321        );
322        self.write_counter(
323            &self.metric_name("peek_lru_k_calls_total"),
324            snapshot.peek_lru_k_calls,
325        );
326        self.write_counter(
327            &self.metric_name("peek_lru_k_found_total"),
328            snapshot.peek_lru_k_found,
329        );
330        self.write_counter(
331            &self.metric_name("k_distance_calls_total"),
332            snapshot.k_distance_calls,
333        );
334        self.write_counter(
335            &self.metric_name("k_distance_found_total"),
336            snapshot.k_distance_found,
337        );
338        self.write_counter(
339            &self.metric_name("k_distance_rank_calls_total"),
340            snapshot.k_distance_rank_calls,
341        );
342        self.write_counter(
343            &self.metric_name("k_distance_rank_found_total"),
344            snapshot.k_distance_rank_found,
345        );
346        self.write_counter(
347            &self.metric_name("k_distance_rank_scan_steps_total"),
348            snapshot.k_distance_rank_scan_steps,
349        );
350        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
351        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
352    }
353}
354
355impl<W: Write + Send> MetricsExporter<CoreOnlyMetricsSnapshot> for PrometheusTextExporter<W> {
356    fn export(&self, snapshot: &CoreOnlyMetricsSnapshot) {
357        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
358        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
359        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
360        self.write_counter(
361            &self.metric_name("insert_calls_total"),
362            snapshot.insert_calls,
363        );
364        self.write_counter(
365            &self.metric_name("insert_updates_total"),
366            snapshot.insert_updates,
367        );
368        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
369        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
370        self.write_counter(
371            &self.metric_name("evicted_entries_total"),
372            snapshot.evicted_entries,
373        );
374        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
375        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
376    }
377}
378
379impl<W: Write + Send> MetricsExporter<ArcMetricsSnapshot> for PrometheusTextExporter<W> {
380    fn export(&self, snapshot: &ArcMetricsSnapshot) {
381        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
382        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
383        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
384        self.write_counter(
385            &self.metric_name("insert_calls_total"),
386            snapshot.insert_calls,
387        );
388        self.write_counter(
389            &self.metric_name("insert_updates_total"),
390            snapshot.insert_updates,
391        );
392        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
393        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
394        self.write_counter(
395            &self.metric_name("evicted_entries_total"),
396            snapshot.evicted_entries,
397        );
398        self.write_counter(
399            &self.metric_name("t1_to_t2_promotions_total"),
400            snapshot.t1_to_t2_promotions,
401        );
402        self.write_counter(
403            &self.metric_name("b1_ghost_hits_total"),
404            snapshot.b1_ghost_hits,
405        );
406        self.write_counter(
407            &self.metric_name("b2_ghost_hits_total"),
408            snapshot.b2_ghost_hits,
409        );
410        self.write_counter(&self.metric_name("p_increases_total"), snapshot.p_increases);
411        self.write_counter(&self.metric_name("p_decreases_total"), snapshot.p_decreases);
412        self.write_counter(
413            &self.metric_name("t1_evictions_total"),
414            snapshot.t1_evictions,
415        );
416        self.write_counter(
417            &self.metric_name("t2_evictions_total"),
418            snapshot.t2_evictions,
419        );
420        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
421        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
422    }
423}
424
425impl<W: Write + Send> MetricsExporter<CarMetricsSnapshot> for PrometheusTextExporter<W> {
426    fn export(&self, snapshot: &CarMetricsSnapshot) {
427        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
428        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
429        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
430        self.write_counter(
431            &self.metric_name("insert_calls_total"),
432            snapshot.insert_calls,
433        );
434        self.write_counter(
435            &self.metric_name("insert_updates_total"),
436            snapshot.insert_updates,
437        );
438        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
439        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
440        self.write_counter(
441            &self.metric_name("evicted_entries_total"),
442            snapshot.evicted_entries,
443        );
444        self.write_counter(
445            &self.metric_name("recent_to_frequent_promotions_total"),
446            snapshot.recent_to_frequent_promotions,
447        );
448        self.write_counter(
449            &self.metric_name("ghost_recent_hits_total"),
450            snapshot.ghost_recent_hits,
451        );
452        self.write_counter(
453            &self.metric_name("ghost_frequent_hits_total"),
454            snapshot.ghost_frequent_hits,
455        );
456        self.write_counter(
457            &self.metric_name("target_increases_total"),
458            snapshot.target_increases,
459        );
460        self.write_counter(
461            &self.metric_name("target_decreases_total"),
462            snapshot.target_decreases,
463        );
464        self.write_counter(&self.metric_name("hand_sweeps_total"), snapshot.hand_sweeps);
465        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
466        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
467    }
468}
469
470impl<W: Write + Send> MetricsExporter<ClockMetricsSnapshot> for PrometheusTextExporter<W> {
471    fn export(&self, snapshot: &ClockMetricsSnapshot) {
472        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
473        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
474        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
475        self.write_counter(
476            &self.metric_name("insert_calls_total"),
477            snapshot.insert_calls,
478        );
479        self.write_counter(
480            &self.metric_name("insert_updates_total"),
481            snapshot.insert_updates,
482        );
483        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
484        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
485        self.write_counter(
486            &self.metric_name("evicted_entries_total"),
487            snapshot.evicted_entries,
488        );
489        self.write_counter(
490            &self.metric_name("hand_advances_total"),
491            snapshot.hand_advances,
492        );
493        self.write_counter(
494            &self.metric_name("ref_bit_resets_total"),
495            snapshot.ref_bit_resets,
496        );
497        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
498        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
499    }
500}
501
502impl<W: Write + Send> MetricsExporter<ClockProMetricsSnapshot> for PrometheusTextExporter<W> {
503    fn export(&self, snapshot: &ClockProMetricsSnapshot) {
504        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
505        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
506        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
507        self.write_counter(
508            &self.metric_name("insert_calls_total"),
509            snapshot.insert_calls,
510        );
511        self.write_counter(
512            &self.metric_name("insert_updates_total"),
513            snapshot.insert_updates,
514        );
515        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
516        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
517        self.write_counter(
518            &self.metric_name("evicted_entries_total"),
519            snapshot.evicted_entries,
520        );
521        self.write_counter(
522            &self.metric_name("cold_to_hot_promotions_total"),
523            snapshot.cold_to_hot_promotions,
524        );
525        self.write_counter(
526            &self.metric_name("hot_to_cold_demotions_total"),
527            snapshot.hot_to_cold_demotions,
528        );
529        self.write_counter(
530            &self.metric_name("test_insertions_total"),
531            snapshot.test_insertions,
532        );
533        self.write_counter(&self.metric_name("test_hits_total"), snapshot.test_hits);
534        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
535        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
536    }
537}
538
539impl<W: Write + Send> MetricsExporter<MfuMetricsSnapshot> for PrometheusTextExporter<W> {
540    fn export(&self, snapshot: &MfuMetricsSnapshot) {
541        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
542        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
543        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
544        self.write_counter(
545            &self.metric_name("insert_calls_total"),
546            snapshot.insert_calls,
547        );
548        self.write_counter(
549            &self.metric_name("insert_updates_total"),
550            snapshot.insert_updates,
551        );
552        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
553        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
554        self.write_counter(
555            &self.metric_name("evicted_entries_total"),
556            snapshot.evicted_entries,
557        );
558        self.write_counter(
559            &self.metric_name("pop_mfu_calls_total"),
560            snapshot.pop_mfu_calls,
561        );
562        self.write_counter(
563            &self.metric_name("pop_mfu_found_total"),
564            snapshot.pop_mfu_found,
565        );
566        self.write_counter(
567            &self.metric_name("peek_mfu_calls_total"),
568            snapshot.peek_mfu_calls,
569        );
570        self.write_counter(
571            &self.metric_name("peek_mfu_found_total"),
572            snapshot.peek_mfu_found,
573        );
574        self.write_counter(
575            &self.metric_name("frequency_calls_total"),
576            snapshot.frequency_calls,
577        );
578        self.write_counter(
579            &self.metric_name("frequency_found_total"),
580            snapshot.frequency_found,
581        );
582        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
583        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
584    }
585}
586
587impl<W: Write + Send> MetricsExporter<NruMetricsSnapshot> for PrometheusTextExporter<W> {
588    fn export(&self, snapshot: &NruMetricsSnapshot) {
589        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
590        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
591        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
592        self.write_counter(
593            &self.metric_name("insert_calls_total"),
594            snapshot.insert_calls,
595        );
596        self.write_counter(
597            &self.metric_name("insert_updates_total"),
598            snapshot.insert_updates,
599        );
600        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
601        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
602        self.write_counter(
603            &self.metric_name("evicted_entries_total"),
604            snapshot.evicted_entries,
605        );
606        self.write_counter(&self.metric_name("sweep_steps_total"), snapshot.sweep_steps);
607        self.write_counter(
608            &self.metric_name("ref_bit_resets_total"),
609            snapshot.ref_bit_resets,
610        );
611        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
612        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
613    }
614}
615
616impl<W: Write + Send> MetricsExporter<SlruMetricsSnapshot> for PrometheusTextExporter<W> {
617    fn export(&self, snapshot: &SlruMetricsSnapshot) {
618        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
619        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
620        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
621        self.write_counter(
622            &self.metric_name("insert_calls_total"),
623            snapshot.insert_calls,
624        );
625        self.write_counter(
626            &self.metric_name("insert_updates_total"),
627            snapshot.insert_updates,
628        );
629        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
630        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
631        self.write_counter(
632            &self.metric_name("evicted_entries_total"),
633            snapshot.evicted_entries,
634        );
635        self.write_counter(
636            &self.metric_name("probationary_to_protected_total"),
637            snapshot.probationary_to_protected,
638        );
639        self.write_counter(
640            &self.metric_name("protected_evictions_total"),
641            snapshot.protected_evictions,
642        );
643        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
644        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
645    }
646}
647
648impl<W: Write + Send> MetricsExporter<TwoQMetricsSnapshot> for PrometheusTextExporter<W> {
649    fn export(&self, snapshot: &TwoQMetricsSnapshot) {
650        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
651        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
652        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
653        self.write_counter(
654            &self.metric_name("insert_calls_total"),
655            snapshot.insert_calls,
656        );
657        self.write_counter(
658            &self.metric_name("insert_updates_total"),
659            snapshot.insert_updates,
660        );
661        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
662        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
663        self.write_counter(
664            &self.metric_name("evicted_entries_total"),
665            snapshot.evicted_entries,
666        );
667        self.write_counter(
668            &self.metric_name("a1in_to_am_promotions_total"),
669            snapshot.a1in_to_am_promotions,
670        );
671        self.write_counter(
672            &self.metric_name("a1out_ghost_hits_total"),
673            snapshot.a1out_ghost_hits,
674        );
675        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
676        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
677    }
678}
679
680impl<W: Write + Send> MetricsExporter<S3FifoMetricsSnapshot> for PrometheusTextExporter<W> {
681    fn export(&self, snapshot: &S3FifoMetricsSnapshot) {
682        self.write_counter(&self.metric_name("get_calls_total"), snapshot.get_calls);
683        self.write_counter(&self.metric_name("get_hits_total"), snapshot.get_hits);
684        self.write_counter(&self.metric_name("get_misses_total"), snapshot.get_misses);
685        self.write_counter(
686            &self.metric_name("insert_calls_total"),
687            snapshot.insert_calls,
688        );
689        self.write_counter(
690            &self.metric_name("insert_updates_total"),
691            snapshot.insert_updates,
692        );
693        self.write_counter(&self.metric_name("insert_new_total"), snapshot.insert_new);
694        self.write_counter(&self.metric_name("evict_calls_total"), snapshot.evict_calls);
695        self.write_counter(
696            &self.metric_name("evicted_entries_total"),
697            snapshot.evicted_entries,
698        );
699        self.write_counter(&self.metric_name("promotions_total"), snapshot.promotions);
700        self.write_counter(
701            &self.metric_name("main_reinserts_total"),
702            snapshot.main_reinserts,
703        );
704        self.write_counter(
705            &self.metric_name("small_evictions_total"),
706            snapshot.small_evictions,
707        );
708        self.write_counter(
709            &self.metric_name("main_evictions_total"),
710            snapshot.main_evictions,
711        );
712        self.write_counter(&self.metric_name("ghost_hits_total"), snapshot.ghost_hits);
713        self.write_gauge(&self.metric_name("cache_len"), snapshot.cache_len as u64);
714        self.write_gauge(&self.metric_name("capacity"), snapshot.capacity as u64);
715    }
716}