Skip to main content

btcnode_metrics/
metrics.rs

1use prometheus::{Gauge, Registry, Opts};
2
3use crate::Error;
4
5pub struct BitcoinMetrics {
6    pub registry: Registry,
7
8    // Blockchain info
9    pub blocks: Gauge,
10    pub headers: Gauge,
11    pub difficulty: Gauge,
12    pub verification_progress: Gauge,
13    pub size_on_disk: Gauge,
14    pub initial_block_download: Gauge,
15    pub chain_pruned: Gauge,
16
17    // Mempool info
18    pub mempool_transactions: Gauge,
19    pub mempool_bytes: Gauge,
20    pub mempool_usage: Gauge,
21    pub mempool_max_bytes: Gauge,
22    pub mempool_min_fee: Gauge,
23    pub mempool_total_fee: Gauge,
24    pub mempool_min_relay_tx_fee: Gauge,
25    pub mempool_incremental_relay_fee: Gauge,
26    pub mempool_unbroadcast_count: Gauge,
27    pub mempool_full_rbf: Gauge,
28
29    // Network info
30    pub connections: Gauge,
31    pub connections_in: Gauge,
32    pub connections_out: Gauge,
33    pub network_active: Gauge,
34    pub node_version: Gauge,
35    pub protocol_version: Gauge,
36    pub time_offset: Gauge,
37    pub relay_fee: Gauge,
38    pub incremental_fee: Gauge,
39
40    // Peer info (aggregated)
41    pub peer_count: Gauge,
42    pub peers_inbound: Gauge,
43    pub peers_outbound: Gauge,
44    pub peers_total_bytes_sent: Gauge,
45    pub peers_total_bytes_received: Gauge,
46    pub peers_avg_ping_seconds: Gauge,
47
48    // Mining info
49    pub network_hash_ps: Gauge,
50    pub mining_pooled_tx: Gauge,
51
52    // Chain tx stats
53    pub chain_tx_count: Gauge,
54    pub chain_tx_rate: Gauge,
55    pub chain_tx_window_block_count: Gauge,
56    pub chain_tx_window_tx_count: Gauge,
57    pub chain_tx_window_interval: Gauge,
58
59    // Net totals
60    pub net_total_bytes_received: Gauge,
61    pub net_total_bytes_sent: Gauge,
62
63    // Fee estimation (BTC/kvB for various confirmation targets)
64    pub fee_estimate_2_blocks: Gauge,
65    pub fee_estimate_6_blocks: Gauge,
66    pub fee_estimate_12_blocks: Gauge,
67    pub fee_estimate_144_blocks: Gauge,
68
69    // Chain tips
70    pub chain_tips_count: Gauge,
71
72    // Uptime
73    pub node_uptime_seconds: Gauge,
74
75    // Latest block stats
76    pub latest_block_txs: Gauge,
77    pub latest_block_size: Gauge,
78    pub latest_block_weight: Gauge,
79    pub latest_block_avg_fee: Gauge,
80    pub latest_block_avg_fee_rate: Gauge,
81    pub latest_block_median_fee: Gauge,
82    pub latest_block_min_fee: Gauge,
83    pub latest_block_max_fee: Gauge,
84    pub latest_block_min_fee_rate: Gauge,
85    pub latest_block_max_fee_rate: Gauge,
86    pub latest_block_total_fee: Gauge,
87    pub latest_block_subsidy: Gauge,
88    pub latest_block_inputs: Gauge,
89    pub latest_block_outputs: Gauge,
90    pub latest_block_segwit_txs: Gauge,
91    pub latest_block_segwit_total_size: Gauge,
92    pub latest_block_segwit_total_weight: Gauge,
93    pub latest_block_total_out: Gauge,
94    pub latest_block_utxo_increase: Gauge,
95    pub latest_block_fee_rate_10th: Gauge,
96    pub latest_block_fee_rate_25th: Gauge,
97    pub latest_block_fee_rate_50th: Gauge,
98    pub latest_block_fee_rate_75th: Gauge,
99    pub latest_block_fee_rate_90th: Gauge,
100
101    // Collector meta
102    pub scrape_duration_seconds: Gauge,
103    pub scrape_error: Gauge,
104}
105
106macro_rules! register_gauge {
107    ($registry:expr, $name:expr, $help:expr) => {{
108        let gauge = Gauge::with_opts(Opts::new($name, $help))?;
109        $registry.register(Box::new(gauge.clone()))?;
110        gauge
111    }};
112}
113
114impl BitcoinMetrics {
115    pub fn new() -> Result<Self, Error> {
116        let registry = Registry::new();
117
118        // Blockchain info
119        let blocks = register_gauge!(registry, "bitcoin_blocks", "Current block height");
120        let headers = register_gauge!(registry, "bitcoin_headers", "Current number of headers");
121        let difficulty = register_gauge!(registry, "bitcoin_difficulty", "Current mining difficulty");
122        let verification_progress = register_gauge!(registry, "bitcoin_verification_progress", "Estimate of verification progress [0..1]");
123        let size_on_disk = register_gauge!(registry, "bitcoin_size_on_disk_bytes", "Estimated size of the block and undo files on disk");
124        let initial_block_download = register_gauge!(registry, "bitcoin_initial_block_download", "Whether node is in initial block download (1=true, 0=false)");
125        let chain_pruned = register_gauge!(registry, "bitcoin_chain_pruned", "Whether the blockchain is pruned (1=true, 0=false)");
126
127        // Mempool info
128        let mempool_transactions = register_gauge!(registry, "bitcoin_mempool_transactions", "Current number of transactions in the mempool");
129        let mempool_bytes = register_gauge!(registry, "bitcoin_mempool_bytes", "Sum of all virtual transaction sizes in the mempool");
130        let mempool_usage = register_gauge!(registry, "bitcoin_mempool_usage_bytes", "Total memory usage for the mempool");
131        let mempool_max_bytes = register_gauge!(registry, "bitcoin_mempool_max_bytes", "Maximum memory usage for the mempool");
132        let mempool_min_fee = register_gauge!(registry, "bitcoin_mempool_min_fee_btc_per_kvb", "Minimum fee rate in BTC/kvB for tx to be accepted");
133        let mempool_total_fee = register_gauge!(registry, "bitcoin_mempool_total_fee_btc", "Total fees of all transactions in the mempool in BTC");
134        let mempool_min_relay_tx_fee = register_gauge!(registry, "bitcoin_mempool_min_relay_tx_fee_btc_per_kvb", "Minimum relay transaction fee in BTC/kvB");
135        let mempool_incremental_relay_fee = register_gauge!(registry, "bitcoin_mempool_incremental_relay_fee_btc_per_kvb", "Minimum fee rate increment for mempool limiting or BIP 125 replacement in BTC/kvB");
136        let mempool_unbroadcast_count = register_gauge!(registry, "bitcoin_mempool_unbroadcast_count", "Number of transactions that haven't been broadcast yet");
137        let mempool_full_rbf = register_gauge!(registry, "bitcoin_mempool_full_rbf", "Whether full replace-by-fee is enabled (1=true, 0=false)");
138
139        // Network info
140        let connections = register_gauge!(registry, "bitcoin_connections", "Total number of connections");
141        let connections_in = register_gauge!(registry, "bitcoin_connections_in", "Number of inbound connections");
142        let connections_out = register_gauge!(registry, "bitcoin_connections_out", "Number of outbound connections");
143        let network_active = register_gauge!(registry, "bitcoin_network_active", "Whether p2p networking is active (1=true, 0=false)");
144        let node_version = register_gauge!(registry, "bitcoin_version", "Bitcoin node version as integer");
145        let protocol_version = register_gauge!(registry, "bitcoin_protocol_version", "Protocol version number");
146        let time_offset = register_gauge!(registry, "bitcoin_time_offset_seconds", "Time offset from network median in seconds");
147        let relay_fee = register_gauge!(registry, "bitcoin_relay_fee_btc_per_kvb", "Minimum relay fee for transactions in BTC/kvB");
148        let incremental_fee = register_gauge!(registry, "bitcoin_incremental_fee_btc_per_kvb", "Minimum fee increment for mempool limiting in BTC/kvB");
149
150        // Peer info (aggregated)
151        let peer_count = register_gauge!(registry, "bitcoin_peer_count", "Number of connected peers");
152        let peers_inbound = register_gauge!(registry, "bitcoin_peers_inbound", "Number of inbound peers");
153        let peers_outbound = register_gauge!(registry, "bitcoin_peers_outbound", "Number of outbound peers");
154        let peers_total_bytes_sent = register_gauge!(registry, "bitcoin_peers_total_bytes_sent", "Total bytes sent across all peers");
155        let peers_total_bytes_received = register_gauge!(registry, "bitcoin_peers_total_bytes_received", "Total bytes received across all peers");
156        let peers_avg_ping_seconds = register_gauge!(registry, "bitcoin_peers_avg_ping_seconds", "Average ping time across all peers in seconds");
157
158        // Mining info
159        let network_hash_ps = register_gauge!(registry, "bitcoin_network_hash_per_second", "Estimated network hashes per second");
160        let mining_pooled_tx = register_gauge!(registry, "bitcoin_mining_pooled_transactions", "Number of transactions in the mining pool");
161
162        // Chain tx stats
163        let chain_tx_count = register_gauge!(registry, "bitcoin_chain_tx_count", "Total number of transactions in the chain");
164        let chain_tx_rate = register_gauge!(registry, "bitcoin_chain_tx_rate_per_second", "Average transaction rate per second over the window");
165        let chain_tx_window_block_count = register_gauge!(registry, "bitcoin_chain_tx_window_block_count", "Number of blocks in the stats window");
166        let chain_tx_window_tx_count = register_gauge!(registry, "bitcoin_chain_tx_window_tx_count", "Number of transactions in the stats window");
167        let chain_tx_window_interval = register_gauge!(registry, "bitcoin_chain_tx_window_interval_seconds", "Elapsed time of the stats window in seconds");
168
169        // Net totals
170        let net_total_bytes_received = register_gauge!(registry, "bitcoin_net_total_bytes_received", "Total bytes received since node start");
171        let net_total_bytes_sent = register_gauge!(registry, "bitcoin_net_total_bytes_sent", "Total bytes sent since node start");
172
173        // Fee estimation
174        let fee_estimate_2_blocks = register_gauge!(registry, "bitcoin_fee_estimate_2_blocks_btc_per_kvb", "Estimated fee rate for confirmation within 2 blocks in BTC/kvB");
175        let fee_estimate_6_blocks = register_gauge!(registry, "bitcoin_fee_estimate_6_blocks_btc_per_kvb", "Estimated fee rate for confirmation within 6 blocks in BTC/kvB");
176        let fee_estimate_12_blocks = register_gauge!(registry, "bitcoin_fee_estimate_12_blocks_btc_per_kvb", "Estimated fee rate for confirmation within 12 blocks in BTC/kvB");
177        let fee_estimate_144_blocks = register_gauge!(registry, "bitcoin_fee_estimate_144_blocks_btc_per_kvb", "Estimated fee rate for confirmation within 144 blocks in BTC/kvB");
178
179        // Chain tips
180        let chain_tips_count = register_gauge!(registry, "bitcoin_chain_tips_count", "Number of known chain tips (forks)");
181
182        // Uptime
183        let node_uptime_seconds = register_gauge!(registry, "bitcoin_node_uptime_seconds", "Node uptime in seconds");
184
185        // Latest block stats
186        let latest_block_txs = register_gauge!(registry, "bitcoin_latest_block_transactions", "Number of transactions in the latest block");
187        let latest_block_size = register_gauge!(registry, "bitcoin_latest_block_size_bytes", "Total size of the latest block in bytes");
188        let latest_block_weight = register_gauge!(registry, "bitcoin_latest_block_weight", "Total weight of the latest block");
189        let latest_block_avg_fee = register_gauge!(registry, "bitcoin_latest_block_avg_fee_sat", "Average fee per transaction in the latest block in satoshis");
190        let latest_block_avg_fee_rate = register_gauge!(registry, "bitcoin_latest_block_avg_fee_rate_sat_per_vb", "Average fee rate in the latest block in sat/vB");
191        let latest_block_median_fee = register_gauge!(registry, "bitcoin_latest_block_median_fee_sat", "Median fee in the latest block in satoshis");
192        let latest_block_min_fee = register_gauge!(registry, "bitcoin_latest_block_min_fee_sat", "Minimum fee in the latest block in satoshis");
193        let latest_block_max_fee = register_gauge!(registry, "bitcoin_latest_block_max_fee_sat", "Maximum fee in the latest block in satoshis");
194        let latest_block_min_fee_rate = register_gauge!(registry, "bitcoin_latest_block_min_fee_rate_sat_per_vb", "Minimum fee rate in the latest block in sat/vB");
195        let latest_block_max_fee_rate = register_gauge!(registry, "bitcoin_latest_block_max_fee_rate_sat_per_vb", "Maximum fee rate in the latest block in sat/vB");
196        let latest_block_total_fee = register_gauge!(registry, "bitcoin_latest_block_total_fee_sat", "Total fees in the latest block in satoshis");
197        let latest_block_subsidy = register_gauge!(registry, "bitcoin_latest_block_subsidy_sat", "Block subsidy (reward) of the latest block in satoshis");
198        let latest_block_inputs = register_gauge!(registry, "bitcoin_latest_block_inputs", "Number of inputs in the latest block (excluding coinbase)");
199        let latest_block_outputs = register_gauge!(registry, "bitcoin_latest_block_outputs", "Number of outputs in the latest block");
200        let latest_block_segwit_txs = register_gauge!(registry, "bitcoin_latest_block_segwit_transactions", "Number of segwit transactions in the latest block");
201        let latest_block_segwit_total_size = register_gauge!(registry, "bitcoin_latest_block_segwit_total_size_bytes", "Total size of segwit transactions in the latest block");
202        let latest_block_segwit_total_weight = register_gauge!(registry, "bitcoin_latest_block_segwit_total_weight", "Total weight of segwit transactions in the latest block");
203        let latest_block_total_out = register_gauge!(registry, "bitcoin_latest_block_total_out_sat", "Total output value in the latest block in satoshis (excluding coinbase)");
204        let latest_block_utxo_increase = register_gauge!(registry, "bitcoin_latest_block_utxo_increase", "Change in UTXO count from the latest block");
205        let latest_block_fee_rate_10th = register_gauge!(registry, "bitcoin_latest_block_fee_rate_10th_percentile_sat_per_vb", "10th percentile fee rate in the latest block in sat/vB");
206        let latest_block_fee_rate_25th = register_gauge!(registry, "bitcoin_latest_block_fee_rate_25th_percentile_sat_per_vb", "25th percentile fee rate in the latest block in sat/vB");
207        let latest_block_fee_rate_50th = register_gauge!(registry, "bitcoin_latest_block_fee_rate_50th_percentile_sat_per_vb", "50th percentile (median) fee rate in the latest block in sat/vB");
208        let latest_block_fee_rate_75th = register_gauge!(registry, "bitcoin_latest_block_fee_rate_75th_percentile_sat_per_vb", "75th percentile fee rate in the latest block in sat/vB");
209        let latest_block_fee_rate_90th = register_gauge!(registry, "bitcoin_latest_block_fee_rate_90th_percentile_sat_per_vb", "90th percentile fee rate in the latest block in sat/vB");
210
211        // Collector meta
212        let scrape_duration_seconds = register_gauge!(registry, "bitcoin_collector_last_scrape_duration_seconds", "Duration of the last metrics collection in seconds");
213        let scrape_error = register_gauge!(registry, "bitcoin_collector_last_scrape_error", "Whether the last scrape had an error (1=error, 0=ok)");
214
215        Ok(Self {
216            registry,
217            blocks,
218            headers,
219            difficulty,
220            verification_progress,
221            size_on_disk,
222            initial_block_download,
223            chain_pruned,
224            mempool_transactions,
225            mempool_bytes,
226            mempool_usage,
227            mempool_max_bytes,
228            mempool_min_fee,
229            mempool_total_fee,
230            mempool_min_relay_tx_fee,
231            mempool_incremental_relay_fee,
232            mempool_unbroadcast_count,
233            mempool_full_rbf,
234            connections,
235            connections_in,
236            connections_out,
237            network_active,
238            node_version,
239            protocol_version,
240            time_offset,
241            relay_fee,
242            incremental_fee,
243            peer_count,
244            peers_inbound,
245            peers_outbound,
246            peers_total_bytes_sent,
247            peers_total_bytes_received,
248            peers_avg_ping_seconds,
249            network_hash_ps,
250            mining_pooled_tx,
251            chain_tx_count,
252            chain_tx_rate,
253            chain_tx_window_block_count,
254            chain_tx_window_tx_count,
255            chain_tx_window_interval,
256            net_total_bytes_received,
257            net_total_bytes_sent,
258            fee_estimate_2_blocks,
259            fee_estimate_6_blocks,
260            fee_estimate_12_blocks,
261            fee_estimate_144_blocks,
262            chain_tips_count,
263            node_uptime_seconds,
264            latest_block_txs,
265            latest_block_size,
266            latest_block_weight,
267            latest_block_avg_fee,
268            latest_block_avg_fee_rate,
269            latest_block_median_fee,
270            latest_block_min_fee,
271            latest_block_max_fee,
272            latest_block_min_fee_rate,
273            latest_block_max_fee_rate,
274            latest_block_total_fee,
275            latest_block_subsidy,
276            latest_block_inputs,
277            latest_block_outputs,
278            latest_block_segwit_txs,
279            latest_block_segwit_total_size,
280            latest_block_segwit_total_weight,
281            latest_block_total_out,
282            latest_block_utxo_increase,
283            latest_block_fee_rate_10th,
284            latest_block_fee_rate_25th,
285            latest_block_fee_rate_50th,
286            latest_block_fee_rate_75th,
287            latest_block_fee_rate_90th,
288            scrape_duration_seconds,
289            scrape_error,
290        })
291    }
292}