1use crate::error::Error;
2use crate::result::Result;
3use borsh::{BorshDeserialize, BorshSerialize};
4use kaspa_rpc_core::GetMetricsResponse;
5use separator::{separated_float, separated_int, separated_uint_with_output, Separatable};
6use serde::{Deserialize, Serialize};
7use workflow_core::enums::Describe;
8
9#[derive(Describe, Debug, Clone, Copy, Eq, PartialEq, Hash, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
10pub enum MetricGroup {
11 System,
12 Storage,
13 Bandwidth,
14 Connections,
15 Network,
16}
17
18impl std::fmt::Display for MetricGroup {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 match self {
21 MetricGroup::System => write!(f, "system"),
22 MetricGroup::Storage => write!(f, "storage"),
23 MetricGroup::Bandwidth => write!(f, "bandwidth"),
24 MetricGroup::Connections => write!(f, "connections"),
25 MetricGroup::Network => write!(f, "network"),
26 }
27 }
28}
29
30impl MetricGroup {
31 pub fn title(&self) -> &str {
32 match self {
33 MetricGroup::System => "System",
34 MetricGroup::Storage => "Storage",
35 MetricGroup::Bandwidth => "Bandwidth",
36 MetricGroup::Connections => "Connections",
37 MetricGroup::Network => "Network",
38 }
39 }
40}
41
42impl MetricGroup {
43 pub fn metrics(&self) -> impl Iterator<Item = &Metric> {
44 match self {
45 MetricGroup::System => [
46 Metric::NodeCpuUsage,
47 Metric::NodeResidentSetSizeBytes,
48 Metric::NodeVirtualMemorySizeBytes,
49 Metric::NodeFileHandlesCount,
50 ]
51 .as_slice()
52 .iter(),
53 MetricGroup::Storage => [
54 Metric::NodeDiskIoReadBytes,
55 Metric::NodeDiskIoReadPerSec,
56 Metric::NodeDiskIoWriteBytes,
57 Metric::NodeDiskIoWritePerSec,
58 Metric::NodeStorageSizeBytes,
59 ]
60 .as_slice()
61 .iter(),
62 MetricGroup::Bandwidth => [
63 Metric::NodeTotalBytesTx,
64 Metric::NodeTotalBytesTxPerSecond,
65 Metric::NodeTotalBytesRx,
66 Metric::NodeTotalBytesRxPerSecond,
67 Metric::NodeBorshBytesTx,
68 Metric::NodeBorshBytesTxPerSecond,
69 Metric::NodeBorshBytesRx,
70 Metric::NodeBorshBytesRxPerSecond,
71 Metric::NodeP2pBytesTx,
72 Metric::NodeP2pBytesTxPerSecond,
73 Metric::NodeP2pBytesRx,
74 Metric::NodeP2pBytesRxPerSecond,
75 Metric::NodeGrpcUserBytesTx,
76 Metric::NodeGrpcUserBytesTxPerSecond,
77 Metric::NodeGrpcUserBytesRx,
78 Metric::NodeGrpcUserBytesRxPerSecond,
79 Metric::NodeJsonBytesTx,
80 Metric::NodeJsonBytesTxPerSecond,
81 Metric::NodeJsonBytesRx,
82 Metric::NodeJsonBytesRxPerSecond,
83 ]
84 .as_slice()
85 .iter(),
86 MetricGroup::Connections => [
87 Metric::NodeActivePeers,
88 Metric::NodeBorshLiveConnections,
89 Metric::NodeBorshConnectionAttempts,
90 Metric::NodeBorshHandshakeFailures,
91 Metric::NodeJsonLiveConnections,
92 Metric::NodeJsonConnectionAttempts,
93 Metric::NodeJsonHandshakeFailures,
94 ]
95 .as_slice()
96 .iter(),
97 MetricGroup::Network => [
98 Metric::NodeBlocksSubmittedCount,
99 Metric::NodeHeadersProcessedCount,
100 Metric::NodeDependenciesProcessedCount,
101 Metric::NodeBodiesProcessedCount,
102 Metric::NodeTransactionsProcessedCount,
103 Metric::NodeChainBlocksProcessedCount,
104 Metric::NodeMassProcessedCount,
105 Metric::NodeDatabaseBlocksCount,
106 Metric::NodeDatabaseHeadersCount,
107 Metric::NetworkMempoolSize,
108 Metric::NetworkTransactionsPerSecond,
109 Metric::NetworkTipHashesCount,
110 Metric::NetworkDifficulty,
111 Metric::NetworkPastMedianTime,
112 Metric::NetworkVirtualParentHashesCount,
113 Metric::NetworkVirtualDaaScore,
114 ]
115 .as_slice()
116 .iter(),
117 }
118 }
119}
120
121impl From<Metric> for MetricGroup {
122 fn from(value: Metric) -> Self {
123 match value {
124 Metric::NodeCpuUsage | Metric::NodeResidentSetSizeBytes | Metric::NodeVirtualMemorySizeBytes => MetricGroup::System,
125 Metric::NodeFileHandlesCount
127 | Metric::NodeDiskIoReadBytes
128 | Metric::NodeDiskIoWriteBytes
129 | Metric::NodeDiskIoReadPerSec
130 | Metric::NodeDiskIoWritePerSec
131 | Metric::NodeStorageSizeBytes => MetricGroup::Storage,
132 Metric::NodeBorshLiveConnections
134 | Metric::NodeBorshConnectionAttempts
135 | Metric::NodeBorshHandshakeFailures
136 | Metric::NodeJsonLiveConnections
137 | Metric::NodeJsonConnectionAttempts
138 | Metric::NodeJsonHandshakeFailures
139 | Metric::NodeActivePeers => MetricGroup::Connections,
140 Metric::NodeBorshBytesRx
142 | Metric::NodeBorshBytesTx
143 | Metric::NodeJsonBytesTx
144 | Metric::NodeJsonBytesRx
145 | Metric::NodeP2pBytesTx
146 | Metric::NodeP2pBytesRx
147 | Metric::NodeGrpcUserBytesTx
148 | Metric::NodeGrpcUserBytesRx
149 | Metric::NodeTotalBytesRx
150 | Metric::NodeTotalBytesTx
151 | Metric::NodeBorshBytesRxPerSecond
152 | Metric::NodeBorshBytesTxPerSecond
153 | Metric::NodeJsonBytesTxPerSecond
154 | Metric::NodeJsonBytesRxPerSecond
155 | Metric::NodeP2pBytesTxPerSecond
156 | Metric::NodeP2pBytesRxPerSecond
157 | Metric::NodeGrpcUserBytesTxPerSecond
158 | Metric::NodeGrpcUserBytesRxPerSecond
159 | Metric::NodeTotalBytesRxPerSecond
160 | Metric::NodeTotalBytesTxPerSecond => MetricGroup::Bandwidth,
161 Metric::NodeBlocksSubmittedCount
163 | Metric::NodeHeadersProcessedCount
164 | Metric::NodeDependenciesProcessedCount
165 | Metric::NodeBodiesProcessedCount
166 | Metric::NodeTransactionsProcessedCount
167 | Metric::NodeChainBlocksProcessedCount
168 | Metric::NodeMassProcessedCount
169 | Metric::NodeDatabaseBlocksCount
171 | Metric::NodeDatabaseHeadersCount
172 | Metric::NetworkMempoolSize
174 | Metric::NetworkTransactionsPerSecond
175 | Metric::NetworkTipHashesCount
176 | Metric::NetworkDifficulty
177 | Metric::NetworkPastMedianTime
178 | Metric::NetworkVirtualParentHashesCount
179 | Metric::NetworkVirtualDaaScore => MetricGroup::Network,
180 }
181 }
182}
183
184#[derive(Describe, Debug, Clone, Copy, Eq, PartialEq, Hash, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
185#[serde(rename_all = "kebab-case")]
186pub enum Metric {
187 NodeCpuUsage,
190 NodeResidentSetSizeBytes,
191 NodeVirtualMemorySizeBytes,
192 NodeFileHandlesCount,
194 NodeDiskIoReadBytes,
195 NodeDiskIoWriteBytes,
196 NodeDiskIoReadPerSec,
197 NodeDiskIoWritePerSec,
198 NodeStorageSizeBytes,
199 NodeActivePeers,
201 NodeBorshLiveConnections,
202 NodeBorshConnectionAttempts,
203 NodeBorshHandshakeFailures,
204 NodeJsonLiveConnections,
205 NodeJsonConnectionAttempts,
206 NodeJsonHandshakeFailures,
207 NodeTotalBytesTx,
209 NodeTotalBytesRx,
210 NodeTotalBytesTxPerSecond,
211 NodeTotalBytesRxPerSecond,
212
213 NodeP2pBytesTx,
214 NodeP2pBytesRx,
215 NodeP2pBytesTxPerSecond,
216 NodeP2pBytesRxPerSecond,
217
218 NodeBorshBytesTx,
219 NodeBorshBytesRx,
220 NodeBorshBytesTxPerSecond,
221 NodeBorshBytesRxPerSecond,
222
223 NodeGrpcUserBytesTx,
224 NodeGrpcUserBytesRx,
225 NodeGrpcUserBytesTxPerSecond,
226 NodeGrpcUserBytesRxPerSecond,
227
228 NodeJsonBytesTx,
229 NodeJsonBytesRx,
230 NodeJsonBytesTxPerSecond,
231 NodeJsonBytesRxPerSecond,
232
233 NodeBlocksSubmittedCount,
235 NodeHeadersProcessedCount,
236 NodeDependenciesProcessedCount,
237 NodeBodiesProcessedCount,
238 NodeTransactionsProcessedCount,
239 NodeChainBlocksProcessedCount,
240 NodeMassProcessedCount,
241 NodeDatabaseBlocksCount,
243 NodeDatabaseHeadersCount,
244 NetworkMempoolSize,
246 NetworkTransactionsPerSecond,
247 NetworkTipHashesCount,
248 NetworkDifficulty,
249 NetworkPastMedianTime,
250 NetworkVirtualParentHashesCount,
251 NetworkVirtualDaaScore,
252}
253
254impl Metric {
255 pub fn is_key_performance_metric(&self) -> bool {
256 matches!(
257 self,
258 Metric::NodeCpuUsage
259 | Metric::NodeResidentSetSizeBytes
260 | Metric::NodeFileHandlesCount
261 | Metric::NodeDiskIoReadBytes
262 | Metric::NodeDiskIoWriteBytes
263 | Metric::NodeDiskIoReadPerSec
264 | Metric::NodeDiskIoWritePerSec
265 | Metric::NodeBorshBytesTx
266 | Metric::NodeBorshBytesRx
267 | Metric::NodeP2pBytesTx
268 | Metric::NodeP2pBytesRx
269 | Metric::NodeGrpcUserBytesTx
270 | Metric::NodeGrpcUserBytesRx
271 | Metric::NodeTotalBytesTx
272 | Metric::NodeTotalBytesRx
273 | Metric::NodeBorshBytesTxPerSecond
274 | Metric::NodeBorshBytesRxPerSecond
275 | Metric::NodeP2pBytesTxPerSecond
276 | Metric::NodeP2pBytesRxPerSecond
277 | Metric::NodeGrpcUserBytesTxPerSecond
278 | Metric::NodeGrpcUserBytesRxPerSecond
279 | Metric::NodeTotalBytesTxPerSecond
280 | Metric::NodeTotalBytesRxPerSecond
281 | Metric::NodeActivePeers
282 | Metric::NetworkMempoolSize
283 | Metric::NetworkTipHashesCount
284 | Metric::NetworkTransactionsPerSecond
285 | Metric::NodeTransactionsProcessedCount
286 | Metric::NodeDatabaseBlocksCount
287 | Metric::NodeDatabaseHeadersCount
288 )
289 }
290
291 pub fn format(&self, f: f64, si: bool, short: bool) -> String {
292 match self {
293 Metric::NodeCpuUsage => {
294 if f.is_nan() {
295 "---".to_string()
296 } else {
297 format!("{:1.2}%", f)
298 }
299 }
300 Metric::NodeResidentSetSizeBytes => as_mb(f, si, short),
301 Metric::NodeVirtualMemorySizeBytes => as_mb(f, si, short),
302 Metric::NodeFileHandlesCount => f.separated_string(),
303 Metric::NodeDiskIoReadBytes => as_mb(f, si, short),
305 Metric::NodeDiskIoWriteBytes => as_mb(f, si, short),
306 Metric::NodeDiskIoReadPerSec => format!("{}/s", as_data_size(f, si)),
307 Metric::NodeDiskIoWritePerSec => format!("{}/s", as_data_size(f, si)),
308 Metric::NodeStorageSizeBytes => as_gb(f, si, short),
309 Metric::NodeBorshLiveConnections => f.trunc().separated_string(),
311 Metric::NodeBorshConnectionAttempts => f.trunc().separated_string(),
312 Metric::NodeBorshHandshakeFailures => f.trunc().separated_string(),
313 Metric::NodeJsonLiveConnections => f.trunc().separated_string(),
314 Metric::NodeJsonConnectionAttempts => f.trunc().separated_string(),
315 Metric::NodeJsonHandshakeFailures => f.trunc().separated_string(),
316 Metric::NodeActivePeers => f.trunc().separated_string(),
317 Metric::NodeBorshBytesTx => as_data_size(f, si),
319 Metric::NodeBorshBytesRx => as_data_size(f, si),
320 Metric::NodeJsonBytesTx => as_data_size(f, si),
321 Metric::NodeJsonBytesRx => as_data_size(f, si),
322 Metric::NodeP2pBytesTx => as_data_size(f, si),
323 Metric::NodeP2pBytesRx => as_data_size(f, si),
324 Metric::NodeGrpcUserBytesTx => as_data_size(f, si),
325 Metric::NodeGrpcUserBytesRx => as_data_size(f, si),
326 Metric::NodeTotalBytesTx => as_data_size(f, si),
327 Metric::NodeTotalBytesRx => as_data_size(f, si),
328 Metric::NodeBorshBytesTxPerSecond => format!("{}/s", as_kb(f, si, short)),
330 Metric::NodeBorshBytesRxPerSecond => format!("{}/s", as_kb(f, si, short)),
331 Metric::NodeJsonBytesTxPerSecond => format!("{}/s", as_kb(f, si, short)),
332 Metric::NodeJsonBytesRxPerSecond => format!("{}/s", as_kb(f, si, short)),
333 Metric::NodeP2pBytesTxPerSecond => format!("{}/s", as_kb(f, si, short)),
334 Metric::NodeP2pBytesRxPerSecond => format!("{}/s", as_kb(f, si, short)),
335 Metric::NodeGrpcUserBytesTxPerSecond => format!("{}/s", as_kb(f, si, short)),
336 Metric::NodeGrpcUserBytesRxPerSecond => format!("{}/s", as_kb(f, si, short)),
337 Metric::NodeTotalBytesTxPerSecond => format!("{}/s", as_kb(f, si, short)),
338 Metric::NodeTotalBytesRxPerSecond => format!("{}/s", as_kb(f, si, short)),
339 Metric::NodeBlocksSubmittedCount => format_as_float(f, short),
341 Metric::NodeHeadersProcessedCount => format_as_float(f, short),
342 Metric::NodeDependenciesProcessedCount => format_as_float(f, short),
343 Metric::NodeBodiesProcessedCount => format_as_float(f, short),
344 Metric::NodeTransactionsProcessedCount => format_as_float(f, short),
345 Metric::NodeChainBlocksProcessedCount => format_as_float(f, short),
346 Metric::NodeMassProcessedCount => format_as_float(f, short),
347 Metric::NodeDatabaseHeadersCount => format_as_float(f, short),
349 Metric::NodeDatabaseBlocksCount => format_as_float(f, short),
350 Metric::NetworkMempoolSize => format_as_float(f.trunc(), short),
352 Metric::NetworkTransactionsPerSecond => format_as_float(f.trunc(), short),
353 Metric::NetworkTipHashesCount => format_as_float(f, short),
354 Metric::NetworkDifficulty => format_as_float(f, short),
355 Metric::NetworkPastMedianTime => format_as_float(f, false),
356 Metric::NetworkVirtualParentHashesCount => format_as_float(f, short),
357 Metric::NetworkVirtualDaaScore => format_as_float(f, false),
358 }
359 }
360
361 pub fn title(&self) -> (&str, &str) {
362 match self {
363 Metric::NodeCpuUsage => ("CPU", "CPU"),
364 Metric::NodeResidentSetSizeBytes => ("Resident Memory", "Memory"),
365 Metric::NodeVirtualMemorySizeBytes => ("Virtual Memory", "Virtual"),
366 Metric::NodeFileHandlesCount => ("File Handles", "Handles"),
368 Metric::NodeDiskIoReadBytes => ("Storage Read", "Stor Read"),
369 Metric::NodeDiskIoWriteBytes => ("Storage Write", "Stor Write"),
370 Metric::NodeDiskIoReadPerSec => ("Storage Read/s", "Stor Read"),
371 Metric::NodeDiskIoWritePerSec => ("Storage Write/s", "Stor Write"),
372 Metric::NodeStorageSizeBytes => ("Storage Size", "Stor Size"),
373 Metric::NodeActivePeers => ("Active p2p Peers", "Peers"),
375 Metric::NodeBorshLiveConnections => ("Borsh Active Connections", "Borsh Conn"),
376 Metric::NodeBorshConnectionAttempts => ("Borsh Connection Attempts", "Borsh Conn Att"),
377 Metric::NodeBorshHandshakeFailures => ("Borsh Handshake Failures", "Borsh Failures"),
378 Metric::NodeJsonLiveConnections => ("Json Active Connections", "Json Conn"),
379 Metric::NodeJsonConnectionAttempts => ("Json Connection Attempts", "Json Conn Att"),
380 Metric::NodeJsonHandshakeFailures => ("Json Handshake Failures", "Json Failures"),
381 Metric::NodeBorshBytesTx => ("wRPC Borsh Tx", "Borsh Tx"),
383 Metric::NodeBorshBytesRx => ("wRPC Borsh Rx", "Borsh Rx"),
384 Metric::NodeJsonBytesTx => ("wRPC JSON Tx", "Json Tx"),
385 Metric::NodeJsonBytesRx => ("wRPC JSON Rx", "Json Rx"),
386 Metric::NodeP2pBytesTx => ("p2p Tx", "p2p Tx"),
387 Metric::NodeP2pBytesRx => ("p2p Rx", "p2p Rx"),
388 Metric::NodeGrpcUserBytesTx => ("gRPC Tx", "gRPC Tx"),
389 Metric::NodeGrpcUserBytesRx => ("gRPC Rx", "gRPC Rx"),
390 Metric::NodeTotalBytesTx => ("Total Tx", "Total Tx"),
391 Metric::NodeTotalBytesRx => ("Total Rx", "Total Rx"),
392 Metric::NodeBorshBytesTxPerSecond => ("wRPC Borsh Tx/s", "Borsh Tx/s"),
394 Metric::NodeBorshBytesRxPerSecond => ("wRPC Borsh Rx/s", "Borsh Rx/s"),
395 Metric::NodeJsonBytesTxPerSecond => ("wRPC JSON Tx/s", "JSON Tx/s"),
396 Metric::NodeJsonBytesRxPerSecond => ("wRPC JSON Rx/s", "JSON Rx/s"),
397 Metric::NodeP2pBytesTxPerSecond => ("p2p Tx/s", "p2p Tx/s"),
398 Metric::NodeP2pBytesRxPerSecond => ("p2p Rx/s", "p2p Rx/s"),
399 Metric::NodeGrpcUserBytesTxPerSecond => ("gRPC Tx/s", "gRPC Tx/s"),
400 Metric::NodeGrpcUserBytesRxPerSecond => ("gRPC Rx/s", "gRPC Rx/s"),
401 Metric::NodeTotalBytesTxPerSecond => ("Total Tx/s", "Total Tx/s"),
402 Metric::NodeTotalBytesRxPerSecond => ("Total Rx/s", "Total Rx/s"),
403 Metric::NodeBlocksSubmittedCount => ("Submitted Blocks", "Blocks"),
405 Metric::NodeHeadersProcessedCount => ("Processed Headers", "Headers"),
406 Metric::NodeDependenciesProcessedCount => ("Processed Dependencies", "Dependencies"),
407 Metric::NodeBodiesProcessedCount => ("Processed Bodies", "Bodies"),
408 Metric::NodeTransactionsProcessedCount => ("Processed Transactions", "Transactions"),
409 Metric::NodeChainBlocksProcessedCount => ("Chain Blocks", "Chain Blocks"),
410 Metric::NodeMassProcessedCount => ("Processed Mass Counts", "Mass Processed"),
411 Metric::NodeDatabaseBlocksCount => ("Database Blocks", "DB Blocks"),
413 Metric::NodeDatabaseHeadersCount => ("Database Headers", "DB Headers"),
414 Metric::NetworkMempoolSize => ("Mempool Size", "Mempool"),
416 Metric::NetworkTransactionsPerSecond => ("TPS", "TPS"),
417 Metric::NetworkTipHashesCount => ("Tip Hashes", "Tip Hashes"),
418 Metric::NetworkDifficulty => ("Network Difficulty", "Difficulty"),
419 Metric::NetworkPastMedianTime => ("Past Median Time", "MT"),
420 Metric::NetworkVirtualParentHashesCount => ("Virtual Parent Hashes", "Virt Parents"),
421 Metric::NetworkVirtualDaaScore => ("Virtual DAA Score", "DAA"),
422 }
423 }
424}
425
426#[derive(Default, Debug, Clone, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
427pub struct MetricsData {
428 pub unixtime_millis: f64,
429
430 pub node_resident_set_size_bytes: u64,
432 pub node_virtual_memory_size_bytes: u64,
433 pub node_cpu_cores: u32,
434 pub node_cpu_usage: f32,
435 pub node_file_handles: u32,
436 pub node_disk_io_read_bytes: u64,
438 pub node_disk_io_write_bytes: u64,
439 pub node_disk_io_read_per_sec: f32,
440 pub node_disk_io_write_per_sec: f32,
441 pub node_storage_size_bytes: u64,
442 pub node_borsh_live_connections: u32,
444 pub node_borsh_connection_attempts: u64,
445 pub node_borsh_handshake_failures: u64,
446 pub node_json_live_connections: u32,
447 pub node_json_connection_attempts: u64,
448 pub node_json_handshake_failures: u64,
449 pub node_active_peers: u32,
450 pub node_borsh_bytes_tx: u64,
452 pub node_borsh_bytes_rx: u64,
453 pub node_json_bytes_tx: u64,
454 pub node_json_bytes_rx: u64,
455 pub node_p2p_bytes_tx: u64,
456 pub node_p2p_bytes_rx: u64,
457 pub node_grpc_user_bytes_tx: u64,
458 pub node_grpc_user_bytes_rx: u64,
459 pub node_total_bytes_tx: u64,
460 pub node_total_bytes_rx: u64,
461 pub node_blocks_submitted_count: u64,
463 pub node_headers_processed_count: u64,
464 pub node_dependencies_processed_count: u64,
465 pub node_bodies_processed_count: u64,
466 pub node_transactions_processed_count: u64,
467 pub node_chain_blocks_processed_count: u64,
468 pub node_mass_processed_count: u64,
469 pub node_database_blocks_count: u64,
471 pub node_database_headers_count: u64,
472 pub network_mempool_size: u64,
474 pub network_tip_hashes_count: u32,
475 pub network_difficulty: f64,
476 pub network_past_median_time: u64,
477 pub network_virtual_parent_hashes_count: u32,
478 pub network_virtual_daa_score: u64,
479}
480
481impl MetricsData {
482 pub fn new(unixtime: f64) -> Self {
483 Self { unixtime_millis: unixtime, ..Default::default() }
484 }
485}
486
487impl TryFrom<GetMetricsResponse> for MetricsData {
488 type Error = Error;
489 fn try_from(response: GetMetricsResponse) -> Result<Self> {
490 let GetMetricsResponse {
491 server_time,
492 consensus_metrics,
493 connection_metrics,
494 bandwidth_metrics,
495 process_metrics,
496 storage_metrics,
497 custom_metrics: _,
498 } = response; let consensus_metrics = consensus_metrics.ok_or(Error::MissingData("Consensus Metrics"))?;
501 let connection_metrics = connection_metrics.ok_or(Error::MissingData("Connection Metrics"))?;
502 let bandwidth_metrics = bandwidth_metrics.ok_or(Error::MissingData("Bandwidth Metrics"))?;
503 let process_metrics = process_metrics.ok_or(Error::MissingData("Process Metrics"))?;
504 let storage_metrics = storage_metrics.ok_or(Error::MissingData("Storage Metrics"))?;
505
506 Ok(MetricsData {
507 unixtime_millis: server_time as f64,
508
509 node_blocks_submitted_count: consensus_metrics.node_blocks_submitted_count,
510 node_headers_processed_count: consensus_metrics.node_headers_processed_count,
511 node_dependencies_processed_count: consensus_metrics.node_dependencies_processed_count,
512 node_bodies_processed_count: consensus_metrics.node_bodies_processed_count,
513 node_transactions_processed_count: consensus_metrics.node_transactions_processed_count,
514 node_chain_blocks_processed_count: consensus_metrics.node_chain_blocks_processed_count,
515 node_mass_processed_count: consensus_metrics.node_mass_processed_count,
516 node_database_blocks_count: consensus_metrics.node_database_blocks_count,
518 node_database_headers_count: consensus_metrics.node_database_headers_count,
519 network_mempool_size: consensus_metrics.network_mempool_size,
520 network_tip_hashes_count: consensus_metrics.network_tip_hashes_count,
521 network_difficulty: consensus_metrics.network_difficulty,
522 network_past_median_time: consensus_metrics.network_past_median_time,
523 network_virtual_parent_hashes_count: consensus_metrics.network_virtual_parent_hashes_count,
524 network_virtual_daa_score: consensus_metrics.network_virtual_daa_score,
525
526 node_borsh_live_connections: connection_metrics.borsh_live_connections,
527 node_borsh_connection_attempts: connection_metrics.borsh_connection_attempts,
528 node_borsh_handshake_failures: connection_metrics.borsh_handshake_failures,
529 node_json_live_connections: connection_metrics.json_live_connections,
530 node_json_connection_attempts: connection_metrics.json_connection_attempts,
531 node_json_handshake_failures: connection_metrics.json_handshake_failures,
532 node_active_peers: connection_metrics.active_peers,
533
534 node_borsh_bytes_tx: bandwidth_metrics.borsh_bytes_tx,
535 node_borsh_bytes_rx: bandwidth_metrics.borsh_bytes_rx,
536 node_json_bytes_tx: bandwidth_metrics.json_bytes_tx,
537 node_json_bytes_rx: bandwidth_metrics.json_bytes_rx,
538 node_p2p_bytes_tx: bandwidth_metrics.p2p_bytes_tx,
539 node_p2p_bytes_rx: bandwidth_metrics.p2p_bytes_rx,
540 node_grpc_user_bytes_tx: bandwidth_metrics.grpc_bytes_tx,
541 node_grpc_user_bytes_rx: bandwidth_metrics.grpc_bytes_rx,
542
543 node_total_bytes_tx: bandwidth_metrics.borsh_bytes_tx
544 + bandwidth_metrics.json_bytes_tx
545 + bandwidth_metrics.p2p_bytes_tx
546 + bandwidth_metrics.grpc_bytes_tx,
547
548 node_total_bytes_rx: bandwidth_metrics.borsh_bytes_rx
549 + bandwidth_metrics.json_bytes_rx
550 + bandwidth_metrics.p2p_bytes_rx
551 + bandwidth_metrics.grpc_bytes_rx,
552
553 node_resident_set_size_bytes: process_metrics.resident_set_size,
554 node_virtual_memory_size_bytes: process_metrics.virtual_memory_size,
555 node_cpu_cores: process_metrics.core_num,
556 node_cpu_usage: process_metrics.cpu_usage,
557 node_file_handles: process_metrics.fd_num,
558 node_disk_io_read_bytes: process_metrics.disk_io_read_bytes,
559 node_disk_io_write_bytes: process_metrics.disk_io_write_bytes,
560 node_disk_io_read_per_sec: process_metrics.disk_io_read_per_sec,
561 node_disk_io_write_per_sec: process_metrics.disk_io_write_per_sec,
562
563 node_storage_size_bytes: storage_metrics.storage_size_bytes,
564 })
565 }
566}
567
568#[derive(Default, Debug, Clone, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
569pub struct MetricsSnapshot {
570 pub data: MetricsData,
571
572 pub unixtime_millis: f64,
573 pub duration_millis: f64,
574 pub node_resident_set_size_bytes: f64,
576 pub node_virtual_memory_size_bytes: f64,
577 pub node_cpu_cores: f64,
578 pub node_cpu_usage: f64,
579 pub node_file_handles: f64,
581 pub node_disk_io_read_bytes: f64,
582 pub node_disk_io_write_bytes: f64,
583 pub node_disk_io_read_per_sec: f64,
584 pub node_disk_io_write_per_sec: f64,
585 pub node_borsh_active_connections: f64,
587 pub node_borsh_connection_attempts: f64,
588 pub node_borsh_handshake_failures: f64,
589 pub node_json_active_connections: f64,
590 pub node_json_connection_attempts: f64,
591 pub node_json_handshake_failures: f64,
592 pub node_active_peers: f64,
593 pub node_borsh_bytes_tx: f64,
595 pub node_borsh_bytes_rx: f64,
596 pub node_json_bytes_tx: f64,
597 pub node_json_bytes_rx: f64,
598 pub node_p2p_bytes_tx: f64,
599 pub node_p2p_bytes_rx: f64,
600 pub node_grpc_user_bytes_tx: f64,
601 pub node_grpc_user_bytes_rx: f64,
602 pub node_total_bytes_tx: f64,
603 pub node_total_bytes_rx: f64,
604
605 pub node_borsh_bytes_tx_per_second: f64,
606 pub node_borsh_bytes_rx_per_second: f64,
607 pub node_json_bytes_tx_per_second: f64,
608 pub node_json_bytes_rx_per_second: f64,
609 pub node_p2p_bytes_tx_per_second: f64,
610 pub node_p2p_bytes_rx_per_second: f64,
611 pub node_grpc_user_bytes_tx_per_second: f64,
612 pub node_grpc_user_bytes_rx_per_second: f64,
613 pub node_total_bytes_tx_per_second: f64,
614 pub node_total_bytes_rx_per_second: f64,
615
616 pub node_blocks_submitted_count: f64,
618 pub node_headers_processed_count: f64,
619 pub node_dependencies_processed_count: f64,
620 pub node_bodies_processed_count: f64,
621 pub node_transactions_processed_count: f64,
622 pub node_chain_blocks_processed_count: f64,
623 pub node_mass_processed_count: f64,
624 pub network_mempool_size: f64,
626 pub network_transactions_per_second: f64,
627 pub node_database_blocks_count: f64,
628 pub node_database_headers_count: f64,
629 pub network_tip_hashes_count: f64,
630 pub network_difficulty: f64,
631 pub network_past_median_time: f64,
632 pub network_virtual_parent_hashes_count: f64,
633 pub network_virtual_daa_score: f64,
634 pub node_storage_size_bytes: f64,
636}
637
638impl MetricsSnapshot {
639 pub fn get(&self, metric: &Metric) -> f64 {
640 match metric {
641 Metric::NodeCpuUsage => self.node_cpu_usage, Metric::NodeResidentSetSizeBytes => self.node_resident_set_size_bytes,
644 Metric::NodeVirtualMemorySizeBytes => self.node_virtual_memory_size_bytes,
645 Metric::NodeFileHandlesCount => self.node_file_handles,
646 Metric::NodeDiskIoReadBytes => self.node_disk_io_read_bytes,
647 Metric::NodeDiskIoWriteBytes => self.node_disk_io_write_bytes,
648 Metric::NodeDiskIoReadPerSec => self.node_disk_io_read_per_sec,
649 Metric::NodeDiskIoWritePerSec => self.node_disk_io_write_per_sec,
650 Metric::NodeStorageSizeBytes => self.node_storage_size_bytes,
651 Metric::NodeActivePeers => self.node_active_peers,
653 Metric::NodeBorshLiveConnections => self.node_borsh_active_connections,
654 Metric::NodeBorshConnectionAttempts => self.node_borsh_connection_attempts,
655 Metric::NodeBorshHandshakeFailures => self.node_borsh_handshake_failures,
656 Metric::NodeJsonLiveConnections => self.node_json_active_connections,
657 Metric::NodeJsonConnectionAttempts => self.node_json_connection_attempts,
658 Metric::NodeJsonHandshakeFailures => self.node_json_handshake_failures,
659 Metric::NodeBorshBytesTx => self.node_borsh_bytes_tx,
661 Metric::NodeBorshBytesRx => self.node_borsh_bytes_rx,
662 Metric::NodeJsonBytesTx => self.node_json_bytes_tx,
663 Metric::NodeJsonBytesRx => self.node_json_bytes_rx,
664 Metric::NodeP2pBytesTx => self.node_p2p_bytes_tx,
665 Metric::NodeP2pBytesRx => self.node_p2p_bytes_rx,
666 Metric::NodeGrpcUserBytesTx => self.node_grpc_user_bytes_tx,
667 Metric::NodeGrpcUserBytesRx => self.node_grpc_user_bytes_rx,
668 Metric::NodeTotalBytesTx => self.node_total_bytes_tx,
669 Metric::NodeTotalBytesRx => self.node_total_bytes_rx,
670
671 Metric::NodeBorshBytesTxPerSecond => self.node_borsh_bytes_tx_per_second,
672 Metric::NodeBorshBytesRxPerSecond => self.node_borsh_bytes_rx_per_second,
673 Metric::NodeJsonBytesTxPerSecond => self.node_json_bytes_tx_per_second,
674 Metric::NodeJsonBytesRxPerSecond => self.node_json_bytes_rx_per_second,
675 Metric::NodeP2pBytesTxPerSecond => self.node_p2p_bytes_tx_per_second,
676 Metric::NodeP2pBytesRxPerSecond => self.node_p2p_bytes_rx_per_second,
677 Metric::NodeGrpcUserBytesTxPerSecond => self.node_grpc_user_bytes_tx_per_second,
678 Metric::NodeGrpcUserBytesRxPerSecond => self.node_grpc_user_bytes_rx_per_second,
679 Metric::NodeTotalBytesTxPerSecond => self.node_total_bytes_tx_per_second,
680 Metric::NodeTotalBytesRxPerSecond => self.node_total_bytes_rx_per_second,
681 Metric::NodeBlocksSubmittedCount => self.node_blocks_submitted_count,
683 Metric::NodeHeadersProcessedCount => self.node_headers_processed_count,
684 Metric::NodeDependenciesProcessedCount => self.node_dependencies_processed_count,
685 Metric::NodeBodiesProcessedCount => self.node_bodies_processed_count,
686 Metric::NodeTransactionsProcessedCount => self.node_transactions_processed_count,
687 Metric::NodeChainBlocksProcessedCount => self.node_chain_blocks_processed_count,
688 Metric::NodeMassProcessedCount => self.node_mass_processed_count,
689 Metric::NodeDatabaseBlocksCount => self.node_database_blocks_count,
691 Metric::NodeDatabaseHeadersCount => self.node_database_headers_count,
692 Metric::NetworkMempoolSize => self.network_mempool_size,
694 Metric::NetworkTransactionsPerSecond => self.network_transactions_per_second,
695 Metric::NetworkTipHashesCount => self.network_tip_hashes_count,
696 Metric::NetworkDifficulty => self.network_difficulty,
697 Metric::NetworkPastMedianTime => self.network_past_median_time,
698 Metric::NetworkVirtualParentHashesCount => self.network_virtual_parent_hashes_count,
699 Metric::NetworkVirtualDaaScore => self.network_virtual_daa_score,
700 }
701 }
702
703 pub fn format(&self, metric: &Metric, si: bool, short: bool) -> String {
704 if short {
705 format!("{}: {}", metric.title().1, metric.format(self.get(metric), si, short))
706 } else {
707 format!("{}: {}", metric.title().0, metric.format(self.get(metric), si, short))
708 }
709 }
710}
711
712#[inline(always)]
713fn per_sec(a: u64, b: u64, duration_millis: f64) -> f64 {
714 b.checked_sub(a).unwrap_or_default() as f64 * 1000. / duration_millis
715}
716
717impl From<(&MetricsData, &MetricsData)> for MetricsSnapshot {
718 fn from((a, b): (&MetricsData, &MetricsData)) -> Self {
719 let duration_millis = b.unixtime_millis - a.unixtime_millis;
720
721 let network_transactions_per_second =
722 per_sec(a.node_transactions_processed_count, b.node_transactions_processed_count, duration_millis);
723 let node_borsh_bytes_tx_per_second = per_sec(a.node_borsh_bytes_tx, b.node_borsh_bytes_tx, duration_millis);
724 let node_borsh_bytes_rx_per_second = per_sec(a.node_borsh_bytes_rx, b.node_borsh_bytes_rx, duration_millis);
725 let node_json_bytes_tx_per_second = per_sec(a.node_json_bytes_tx, b.node_json_bytes_tx, duration_millis);
726 let node_json_bytes_rx_per_second = per_sec(a.node_json_bytes_rx, b.node_json_bytes_rx, duration_millis);
727 let node_p2p_bytes_tx_per_second = per_sec(a.node_p2p_bytes_tx, b.node_p2p_bytes_tx, duration_millis);
728 let node_p2p_bytes_rx_per_second = per_sec(a.node_p2p_bytes_rx, b.node_p2p_bytes_rx, duration_millis);
729 let node_grpc_user_bytes_tx_per_second = per_sec(a.node_grpc_user_bytes_tx, b.node_grpc_user_bytes_tx, duration_millis);
730 let node_grpc_user_bytes_rx_per_second = per_sec(a.node_grpc_user_bytes_rx, b.node_grpc_user_bytes_rx, duration_millis);
731 let node_total_bytes_tx_per_second = per_sec(a.node_total_bytes_tx, b.node_total_bytes_tx, duration_millis);
732 let node_total_bytes_rx_per_second = per_sec(a.node_total_bytes_rx, b.node_total_bytes_rx, duration_millis);
733
734 Self {
735 unixtime_millis: b.unixtime_millis,
736 duration_millis,
737 node_cpu_usage: b.node_cpu_usage as f64 / b.node_cpu_cores as f64 * 100.0,
739 node_cpu_cores: b.node_cpu_cores as f64,
740 node_resident_set_size_bytes: b.node_resident_set_size_bytes as f64,
741 node_virtual_memory_size_bytes: b.node_virtual_memory_size_bytes as f64,
742 node_file_handles: b.node_file_handles as f64,
743 node_disk_io_read_bytes: b.node_disk_io_read_bytes as f64,
744 node_disk_io_write_bytes: b.node_disk_io_write_bytes as f64,
745 node_disk_io_read_per_sec: b.node_disk_io_read_per_sec as f64,
746 node_disk_io_write_per_sec: b.node_disk_io_write_per_sec as f64,
747 node_storage_size_bytes: b.node_storage_size_bytes as f64,
748 node_borsh_active_connections: b.node_borsh_live_connections as f64,
750 node_borsh_connection_attempts: b.node_borsh_connection_attempts as f64,
751 node_borsh_handshake_failures: b.node_borsh_handshake_failures as f64,
752 node_json_active_connections: b.node_json_live_connections as f64,
753 node_json_connection_attempts: b.node_json_connection_attempts as f64,
754 node_json_handshake_failures: b.node_json_handshake_failures as f64,
755 node_active_peers: b.node_active_peers as f64,
756 node_borsh_bytes_tx: b.node_borsh_bytes_tx as f64,
758 node_borsh_bytes_rx: b.node_borsh_bytes_rx as f64,
759 node_json_bytes_tx: b.node_json_bytes_tx as f64,
760 node_json_bytes_rx: b.node_json_bytes_rx as f64,
761 node_p2p_bytes_tx: b.node_p2p_bytes_tx as f64,
762 node_p2p_bytes_rx: b.node_p2p_bytes_rx as f64,
763 node_grpc_user_bytes_tx: b.node_grpc_user_bytes_tx as f64,
764 node_grpc_user_bytes_rx: b.node_grpc_user_bytes_rx as f64,
765 node_total_bytes_tx: b.node_total_bytes_tx as f64,
766 node_total_bytes_rx: b.node_total_bytes_rx as f64,
767
768 node_borsh_bytes_tx_per_second,
769 node_borsh_bytes_rx_per_second,
770 node_json_bytes_tx_per_second,
771 node_json_bytes_rx_per_second,
772 node_p2p_bytes_tx_per_second,
773 node_p2p_bytes_rx_per_second,
774 node_grpc_user_bytes_tx_per_second,
775 node_grpc_user_bytes_rx_per_second,
776 node_total_bytes_tx_per_second,
777 node_total_bytes_rx_per_second,
778 node_blocks_submitted_count: b.node_blocks_submitted_count as f64,
780 node_headers_processed_count: b.node_headers_processed_count as f64,
781 node_dependencies_processed_count: b.node_dependencies_processed_count as f64,
782 node_bodies_processed_count: b.node_bodies_processed_count as f64,
783 node_transactions_processed_count: b.node_transactions_processed_count as f64,
784 node_chain_blocks_processed_count: b.node_chain_blocks_processed_count as f64,
785 node_mass_processed_count: b.node_mass_processed_count as f64,
786 node_database_blocks_count: b.node_database_blocks_count as f64,
788 node_database_headers_count: b.node_database_headers_count as f64,
789 network_mempool_size: b.network_mempool_size as f64,
791 network_transactions_per_second,
792 network_tip_hashes_count: b.network_tip_hashes_count as f64,
793 network_difficulty: b.network_difficulty,
794 network_past_median_time: b.network_past_median_time as f64,
795 network_virtual_parent_hashes_count: b.network_virtual_parent_hashes_count as f64,
796 network_virtual_daa_score: b.network_virtual_daa_score as f64,
797
798 data: b.clone(),
799 }
800 }
801}
802
803pub fn as_kb(bytes: f64, si: bool, short: bool) -> String {
806 let unit = if si { 1000_f64 } else { 1024_f64 };
807 if short && bytes > unit.powi(2) {
808 as_data_size(bytes, si)
809 } else {
810 let suffix = if si { " KB" } else { " KiB" };
811 let kb = bytes / unit; format_with_precision(kb) + suffix
813 }
814}
815
816pub fn as_mb(bytes: f64, si: bool, short: bool) -> String {
819 let unit = if si { 1000_f64 } else { 1024_f64 };
820 if short && bytes > unit.powi(3) {
821 as_data_size(bytes, si)
822 } else {
823 let suffix = if si { " MB" } else { " MiB" };
824 let mb = bytes / unit.powi(2); format_with_precision(mb) + suffix
826 }
827}
828
829pub fn as_gb(bytes: f64, si: bool, short: bool) -> String {
832 let unit = if si { 1000_f64 } else { 1024_f64 };
833 if short && bytes > unit.powi(4) {
834 as_data_size(bytes, si)
835 } else {
836 let suffix = if si { " GB" } else { " GiB" };
837 let gb = bytes / unit.powi(3); format_with_precision(gb) + suffix
839 }
840}
841
842pub fn as_data_size(bytes: f64, si: bool) -> String {
844 let unit = if si { 1000_f64 } else { 1024_f64 };
845 let mut size = bytes;
846 let mut unit_str = " B";
847
848 if size >= unit.powi(4) {
849 size /= unit.powi(4);
850 unit_str = " TB";
851 } else if size >= unit.powi(3) {
852 size /= unit.powi(3);
853 unit_str = " GB";
854 } else if size >= unit.powi(2) {
855 size /= unit.powi(2);
856 unit_str = " MB";
857 } else if size >= unit {
858 size /= unit;
859 unit_str = " KB";
860 }
861
862 format_with_precision(size) + unit_str
863}
864
865pub fn format_as_float(f: f64, short: bool) -> String {
867 if short {
868 if f < 1000.0 {
869 format_with_precision(f)
870 } else if f < 1000000.0 {
871 format_with_precision(f / 1000.0) + " K"
872 } else if f < 1000000000.0 {
873 format_with_precision(f / 1000000.0) + " M"
874 } else if f < 1000000000000.0 {
875 format_with_precision(f / 1000000000.0) + " G"
876 } else if f < 1000000000000000.0 {
877 format_with_precision(f / 1000000000000.0) + " T"
878 } else if f < 1000000000000000000.0 {
879 format_with_precision(f / 1000000000000000.0) + " P"
880 } else {
881 format_with_precision(f / 1000000000000000000.0) + " E"
882 }
883 } else {
884 f.separated_string()
885 }
886}
887
888fn format_with_precision(f: f64) -> String {
890 if f.fract() < 0.01 {
891 separated_float!(format!("{}", f.trunc()))
892 } else {
893 separated_float!(format!("{:.2}", f))
894 }
895}