reth_provider/providers/static_file/
metrics.rs
1use std::{collections::HashMap, time::Duration};
2
3use itertools::Itertools;
4use metrics::{Counter, Gauge, Histogram};
5use reth_metrics::Metrics;
6use reth_primitives::StaticFileSegment;
7use strum::{EnumIter, IntoEnumIterator};
8
9#[derive(Debug)]
11pub struct StaticFileProviderMetrics {
12 segments: HashMap<StaticFileSegment, StaticFileSegmentMetrics>,
13 segment_operations: HashMap<
14 (StaticFileSegment, StaticFileProviderOperation),
15 StaticFileProviderOperationMetrics,
16 >,
17}
18
19impl Default for StaticFileProviderMetrics {
20 fn default() -> Self {
21 Self {
22 segments: StaticFileSegment::iter()
23 .map(|segment| {
24 (
25 segment,
26 StaticFileSegmentMetrics::new_with_labels(&[("segment", segment.as_str())]),
27 )
28 })
29 .collect(),
30 segment_operations: StaticFileSegment::iter()
31 .cartesian_product(StaticFileProviderOperation::iter())
32 .map(|(segment, operation)| {
33 (
34 (segment, operation),
35 StaticFileProviderOperationMetrics::new_with_labels(&[
36 ("segment", segment.as_str()),
37 ("operation", operation.as_str()),
38 ]),
39 )
40 })
41 .collect(),
42 }
43 }
44}
45
46impl StaticFileProviderMetrics {
47 pub(crate) fn record_segment(
48 &self,
49 segment: StaticFileSegment,
50 size: u64,
51 files: usize,
52 entries: usize,
53 ) {
54 self.segments.get(&segment).expect("segment metrics should exist").size.set(size as f64);
55 self.segments.get(&segment).expect("segment metrics should exist").files.set(files as f64);
56 self.segments
57 .get(&segment)
58 .expect("segment metrics should exist")
59 .entries
60 .set(entries as f64);
61 }
62
63 pub(crate) fn record_segment_operation(
64 &self,
65 segment: StaticFileSegment,
66 operation: StaticFileProviderOperation,
67 duration: Option<Duration>,
68 ) {
69 self.segment_operations
70 .get(&(segment, operation))
71 .expect("segment operation metrics should exist")
72 .calls_total
73 .increment(1);
74
75 if let Some(duration) = duration {
76 self.segment_operations
77 .get(&(segment, operation))
78 .expect("segment operation metrics should exist")
79 .write_duration_seconds
80 .record(duration.as_secs_f64());
81 }
82 }
83
84 pub(crate) fn record_segment_operations(
85 &self,
86 segment: StaticFileSegment,
87 operation: StaticFileProviderOperation,
88 count: u64,
89 duration: Option<Duration>,
90 ) {
91 self.segment_operations
92 .get(&(segment, operation))
93 .expect("segment operation metrics should exist")
94 .calls_total
95 .increment(count);
96
97 if let Some(duration) = duration {
98 self.segment_operations
99 .get(&(segment, operation))
100 .expect("segment operation metrics should exist")
101 .write_duration_seconds
102 .record(duration.as_secs_f64() / count as f64);
103 }
104 }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
108pub(crate) enum StaticFileProviderOperation {
109 InitCursor,
110 OpenWriter,
111 Append,
112 Prune,
113 IncrementBlock,
114 CommitWriter,
115}
116
117impl StaticFileProviderOperation {
118 const fn as_str(&self) -> &'static str {
119 match self {
120 Self::InitCursor => "init-cursor",
121 Self::OpenWriter => "open-writer",
122 Self::Append => "append",
123 Self::Prune => "prune",
124 Self::IncrementBlock => "increment-block",
125 Self::CommitWriter => "commit-writer",
126 }
127 }
128}
129
130#[derive(Metrics)]
132#[metrics(scope = "static_files.segment")]
133pub(crate) struct StaticFileSegmentMetrics {
134 size: Gauge,
136 files: Gauge,
138 entries: Gauge,
140}
141
142#[derive(Metrics)]
143#[metrics(scope = "static_files.jar_provider")]
144pub(crate) struct StaticFileProviderOperationMetrics {
145 calls_total: Counter,
147 write_duration_seconds: Histogram,
149}