ckb_metrics/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
#![allow(missing_docs)]
//! A lightweight metrics facade used in CKB.
//!
//! The `ckb-metrics` crate is a set of tools for metrics.
//! The crate [`ckb-metrics-service`] is the runtime which handles the metrics data in CKB.
//!
//! [`ckb-metrics-service`]: ../ckb_metrics_service/index.html

use prometheus_static_metric::make_static_metric;
use std::cell::Cell;

pub use prometheus::*;

pub fn gather() -> Vec<prometheus::proto::MetricFamily> {
    prometheus::gather()
}

make_static_metric! {
    // Struct for the CKB sys mem process statistics type label
    struct CkbSysMemProcessStatistics: IntGauge{
        "type" => {
            rss,
            vms,
        },
    }

    // Struct for the CKB sys mem jemalloc statistics type label
    struct CkbSysMemJemallocStatistics: IntGauge{
        "type" => {
            allocated,
            resident,
            active,
            mapped,
            retained,
            metadata,
        },
    }

    // Struct for CKB tx-pool entry status statistics type label
    struct CkbTxPoolEntryStatistics: IntGauge{
        "type" => {
            pending,
            gap,
            proposed,
        },
    }

    struct CkbHeaderMapMemoryHitMissStatistics: IntCounter{
        "type" => {
            hit,
            miss,
        },
    }
}

pub struct Metrics {
    /// Gauge metric for CKB chain tip header number
    pub ckb_chain_tip: IntGauge,
    /// CKB chain unverified tip header number
    pub ckb_chain_unverified_tip: IntGauge,
    /// ckb_chain asynchronous_process duration (seconds)
    pub ckb_chain_async_process_block_duration: Histogram,
    /// ckb_chain consume_orphan thread's process_lonely_block duration (seconds)
    pub ckb_chain_process_lonely_block_duration: Histogram,
    /// ckb_chain consume_unverified thread's consume_unverified_block duration (seconds)
    pub ckb_chain_consume_unverified_block_duration: Histogram,
    /// ckb_chain consume_unverified thread's consume_unverified_block waiting for block duration (seconds)
    pub ckb_chain_consume_unverified_block_waiting_block_duration: Histogram,
    /// ckb_chain execute_callback duration (seconds)
    pub ckb_chain_execute_callback_duration: Histogram,
    /// ckb_chain orphan blocks count
    pub ckb_chain_orphan_count: IntGauge,
    pub ckb_chain_lonely_block_ch_len: IntGauge,
    pub ckb_chain_unverified_block_ch_len: IntGauge,
    pub ckb_chain_preload_unverified_block_ch_len: IntGauge,
    pub ckb_chain_load_full_unverified_block: Histogram,
    /// ckb_sync_msg_process duration (seconds)
    pub ckb_sync_msg_process_duration: HistogramVec,
    /// ckb_sync_block_fetch duraiton (seconds)
    pub ckb_sync_block_fetch_duration: Histogram,
    // ckb_header_map_limit_memory duration (seconds)
    pub ckb_header_map_limit_memory_duration: Histogram,
    // ckb_header_map_limit_memory operation duration (seconds)
    pub ckb_header_map_ops_duration: HistogramVec,
    // how many headers in the HeaderMap's memory map?
    pub ckb_header_map_memory_count: IntGauge,
    // how many times the HeaderMap's memory map is hit?
    pub ckb_header_map_memory_hit_miss_count: CkbHeaderMapMemoryHitMissStatistics,
    /// Gauge for tracking the size of all frozen data
    pub ckb_freezer_size: IntGauge,
    /// Counter for measuring the effective amount of data read
    pub ckb_freezer_read: IntCounter,
    /// Gauge for tracking the number of ckb_freezer
    pub ckb_freezer_number: IntGauge,
    /// Counter for relay transaction short id collide
    pub ckb_relay_transaction_short_id_collide: IntCounter,
    /// Histogram for relay compact block verify duration
    pub ckb_relay_cb_verify_duration: Histogram,
    /// Histogram for block process duration
    pub ckb_block_process_duration: Histogram,
    /// Histogram for sync process tx in txpool
    pub ckb_tx_pool_sync_process: Histogram,
    /// Histogram for async process tx in txpool
    pub ckb_tx_pool_async_process: Histogram,
    /// Counter for relay compact block transaction count
    pub ckb_relay_cb_transaction_count: IntCounter,
    /// Counter for relay compact block reconstruct ok
    pub ckb_relay_cb_reconstruct_ok: IntCounter,
    /// Counter for relay compact block fresh transaction count
    pub ckb_relay_cb_fresh_tx_cnt: IntCounter,
    /// Counter for relay compact block reconstruct fail
    pub ckb_relay_cb_reconstruct_fail: IntCounter,
    // Gauge for CKB shared best number
    pub ckb_shared_best_number: IntGauge,
    // GaugeVec for CKB system memory process statistics
    pub ckb_sys_mem_process: CkbSysMemProcessStatistics,
    // GaugeVec for CKB system memory jemalloc statistics
    pub ckb_sys_mem_jemalloc: CkbSysMemJemallocStatistics,
    // GaugeVec for CKB tx-pool tx entry status statistics
    pub ckb_tx_pool_entry: CkbTxPoolEntryStatistics,
    /// Histogram for CKB network connections
    pub ckb_message_bytes: HistogramVec,
    /// Gauge for CKB rocksdb statistics
    pub ckb_sys_mem_rocksdb: IntGaugeVec,
    /// Counter for CKB network ban peers
    pub ckb_network_ban_peer: IntCounter,
    pub ckb_inflight_blocks_count: IntGauge,
    pub ckb_inflight_timeout_count: IntCounter,
}

static METRICS: std::sync::LazyLock<Metrics> = std::sync::LazyLock::new(|| {
    Metrics {
    ckb_chain_tip: register_int_gauge!("ckb_chain_tip", "The CKB chain tip header number").unwrap(),
    ckb_chain_unverified_tip: register_int_gauge!(
        "ckb_chain_unverified_tip",
        "The CKB chain unverified tip header number"
    )
            .unwrap(),
    ckb_chain_async_process_block_duration: register_histogram!(
        "ckb_chain_async_process_block_duration",
        "The CKB chain asynchronous_process_block duration (seconds)"
    )
            .unwrap(),
    ckb_chain_process_lonely_block_duration: register_histogram!(
        "ckb_chain_process_lonely_block_duration",
        "The CKB chain consume_orphan thread's process_lonely_block duration (seconds)"
    )
            .unwrap(),
    ckb_chain_consume_unverified_block_duration: register_histogram!(
        "ckb_chain_consume_unverified_block_duration",
        "The CKB chain consume_unverified thread's consume_unverified_block duration (seconds)"
    )
            .unwrap(),
    ckb_chain_consume_unverified_block_waiting_block_duration: register_histogram!(
        "ckb_chain_consume_unverified_block_waiting_block_duration",
        "The CKB chain consume_unverified thread's consume_unverified_block waiting for block duration (seconds)"
    ).unwrap(),
    ckb_chain_execute_callback_duration: register_histogram!(
            "ckb_chain_execute_callback_duration",
            "The CKB chain execute_callback duration (seconds)"
        ).unwrap(),
    ckb_chain_orphan_count: register_int_gauge!(
            "ckb_chain_orphan_count",
            "The CKB chain orphan blocks count",
        ).unwrap(),
    ckb_chain_lonely_block_ch_len: register_int_gauge!(
            "ckb_chain_lonely_block_ch_len",
            "The CKB chain lonely block channel length",
        ).unwrap(),
    ckb_chain_unverified_block_ch_len: register_int_gauge!(
            "ckb_chain_unverified_block_ch_len",
            "The CKB chain unverified block channel length",
        ).unwrap(),
    ckb_chain_preload_unverified_block_ch_len: register_int_gauge!(
            "ckb_chain_preload_unverified_block_ch_len",
            "The CKB chain fill unverified block channel length",
        ).unwrap(),
    ckb_chain_load_full_unverified_block: register_histogram!(
            "ckb_chain_load_full_unverified_block",
            "The CKB chain load_full_unverified_block duration (seconds)"
        ).unwrap(),
    ckb_sync_msg_process_duration: register_histogram_vec!(
            "ckb_sync_msg_process_duration",
            "The CKB sync message process duration (seconds)",
            &["msg_type"],
        ).unwrap(),
    ckb_sync_block_fetch_duration: register_histogram!(
            "ckb_sync_block_fetch_duration",
            "The CKB sync block fetch duration (seconds)"
        ).unwrap(),
    ckb_header_map_limit_memory_duration: register_histogram!(
            "ckb_header_map_limit_memory_duration",
            "The CKB header map limit_memory job duration (seconds)"
        ).unwrap(),
    ckb_header_map_ops_duration: register_histogram_vec!(
            "ckb_header_map_ops_duration",
            "The CKB header map operation duration (seconds)",
            &["operation"],
        ).unwrap(),
    ckb_header_map_memory_count: register_int_gauge!(
            "ckb_header_map_memory_count",
            "The CKB HeaderMap memory count",
        ).unwrap(),
    ckb_header_map_memory_hit_miss_count: CkbHeaderMapMemoryHitMissStatistics::from(
            &register_int_counter_vec!(
            "ckb_header_map_memory_hit_miss_count",
            "The CKB HeaderMap memory hit count",
            &["type"]
        )
                .unwrap()
        ),
    ckb_freezer_size: register_int_gauge!("ckb_freezer_size", "The CKB freezer size").unwrap(),
    ckb_freezer_read: register_int_counter!("ckb_freezer_read", "The CKB freezer read").unwrap(),
    ckb_freezer_number: register_int_gauge!("ckb_freezer_number", "The CKB freezer number").unwrap(),
    ckb_relay_transaction_short_id_collide: register_int_counter!(
        "ckb_relay_transaction_short_id_collide",
        "The CKB relay transaction short id collide"
    )
            .unwrap(),
    ckb_relay_cb_verify_duration: register_histogram!(
        "ckb_relay_cb_verify_duration",
        "The CKB relay compact block verify duration"
    )
            .unwrap(),
    ckb_block_process_duration: register_histogram!(
        "ckb_block_process_duration",
        "The CKB block process duration"
    )
    .unwrap(),
    ckb_tx_pool_sync_process: register_histogram!(
        "ckb_tx_pool_sync_process",
        "The CKB tx_pool sync process tx duration"
    )
    .unwrap(),
    ckb_tx_pool_async_process: register_histogram!(
        "ckb_tx_pool_async_process",
        "The CKB tx_pool async process tx duration"
    )
    .unwrap(),
    ckb_relay_cb_transaction_count: register_int_counter!(
        "ckb_relay_cb_transaction_count",
        "The CKB relay compact block transaction count"
    ).unwrap(),
    ckb_relay_cb_reconstruct_ok: register_int_counter!(
        "ckb_relay_cb_reconstruct_ok",
        "The CKB relay compact block reconstruct ok count"
    ).unwrap(),
    ckb_relay_cb_fresh_tx_cnt: register_int_counter!(
        "ckb_relay_cb_fresh_tx_cnt",
        "The CKB relay compact block fresh tx count"
    ).unwrap(),
    ckb_relay_cb_reconstruct_fail: register_int_counter!(
        "ckb_relay_cb_reconstruct_fail",
        "The CKB relay compact block reconstruct fail count"
    )
            .unwrap(),
    ckb_shared_best_number: register_int_gauge!(
        "ckb_shared_best_number",
        "The CKB shared best header number"
    )
            .unwrap(),
    ckb_sys_mem_process: CkbSysMemProcessStatistics::from(
            &register_int_gauge_vec!(
            "ckb_sys_mem_process",
            "CKB system memory for process statistics",
            &["type"]
        )
                .unwrap(),
        ),
    ckb_sys_mem_jemalloc: CkbSysMemJemallocStatistics::from(
            &register_int_gauge_vec!(
            "ckb_sys_mem_jemalloc",
            "CKB system memory for jemalloc statistics",
            &["type"]
        )
                .unwrap(),
        ),
    ckb_tx_pool_entry: CkbTxPoolEntryStatistics::from(
            &register_int_gauge_vec!(
            "ckb_tx_pool_entry",
            "CKB tx-pool entry status statistics",
            &["type"]
        )
                .unwrap(),
        ),
    ckb_message_bytes: register_histogram_vec!(
        "ckb_message_bytes",
        "The CKB message bytes",
        &["direction", "protocol_name", "msg_item_name", "status_code"],
        vec![
            500.0, 1000.0, 2000.0, 5000.0, 10000.0, 20000.0, 50000.0, 100000.0, 200000.0, 500000.0
        ]
    )
            .unwrap(),
    ckb_sys_mem_rocksdb: register_int_gauge_vec!(
        "ckb_sys_mem_rocksdb",
        "CKB system memory for rocksdb statistics",
        &["type", "cf"]
    )
            .unwrap(),
    ckb_network_ban_peer: register_int_counter!(
        "ckb_network_ban_peer",
        "CKB network baned peer count"
    )
            .unwrap(),
    ckb_inflight_blocks_count: register_int_gauge!(
            "ckb_inflight_blocks_count",
            "The CKB inflight blocks count"
    )
            .unwrap(),
    ckb_inflight_timeout_count: register_int_counter!(
            "ckb_inflight_timeout_count",
            "The CKB inflight timeout count"
    ).unwrap(),
    }
});

/// Indicate whether the metrics service is enabled.
/// This value will set by ckb-metrics-service
pub static METRICS_SERVICE_ENABLED: std::sync::OnceLock<bool> = std::sync::OnceLock::new();

thread_local! {
    static ENABLE_COLLECT_METRICS: Cell<Option<bool>>= Cell::default();
}

/// if metrics service is enabled, `handle()` will return `Some(&'static METRICS)`
/// else will return `None`
pub fn handle() -> Option<&'static Metrics> {
    let enabled_collect_metrics: bool =
        ENABLE_COLLECT_METRICS.with(
            |enable_collect_metrics| match enable_collect_metrics.get() {
                Some(enabled) => enabled,
                None => match METRICS_SERVICE_ENABLED.get().copied() {
                    Some(enabled) => {
                        enable_collect_metrics.set(Some(enabled));
                        enabled
                    }
                    None => false,
                },
            },
        );

    if enabled_collect_metrics {
        Some(&METRICS)
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use crate::METRICS;
    use std::ops::Deref;

    // https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
    // The Metric names may contain ASCII letters and digits, as well as underscores and colons. It must match the regex [a-zA-Z_:][a-zA-Z0-9_:]*.
    // The Metric Label names may contain ASCII letters, numbers, as well as underscores. They must match the regex [a-zA-Z_][a-zA-Z0-9_]*. Label names beginning with __ are reserved for internal use.
    // Test that all metrics have valid names and labels
    // Just simple call .deref() method to make sure all metrics are initialized successfully
    // If the metrics name or label is invalid, this test will panic
    #[test]
    fn test_metrics_name() {
        let _ = METRICS.deref();
    }

    #[test]
    #[should_panic]
    fn test_bad_metrics_name() {
        let res = prometheus::register_int_gauge!(
            "ckb.chain.tip",
            "a bad metric which contains '.' in its name"
        );
        assert!(res.is_err());
        let res = prometheus::register_int_gauge!(
            "ckb-chain-tip",
            "a bad metric which contains '-' in its name"
        );
        assert!(res.is_err());
    }
}