Skip to main content

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_static_file_types::{StaticFileMap, StaticFileSegment};
7use strum::{EnumIter, IntoEnumIterator};
8
9/// Metrics for the static file provider.
10#[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/// Metrics for a specific static file segment.
133#[derive(Metrics)]
134#[metrics(scope = "static_files.segment")]
135pub(crate) struct StaticFileSegmentMetrics {
136    /// The size of a static file segment
137    size: Gauge,
138    /// The number of files for a static file segment
139    files: Gauge,
140    /// The number of entries for a static file segment
141    entries: Gauge,
142}
143
144#[derive(Metrics)]
145#[metrics(scope = "static_files.jar_provider")]
146pub(crate) struct StaticFileProviderOperationMetrics {
147    /// Total number of static file jar provider operations made.
148    calls_total: Counter,
149    /// The time it took to execute the static file jar provider operation that writes data.
150    write_duration_seconds: Histogram,
151}