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