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