Skip to content

Commit 751e3b1

Browse files
committed
Add network_status metric and canonical_name labels
* canonical_name is the preffered method of linking stuff to chains * network_status is a (WIP) metric to determine network "tier" or status, meaning: live (production, users) or preview (working on it) so you can drive your alerting needs based on it
1 parent a272dd6 commit 751e3b1

23 files changed

+110
-27
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ local*
1515
# Python
1616
venv
1717
__pycache__
18+
.coverage

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
prometheus-client==0.13.1
3-
pyyaml==6.0
3+
pyyaml==6.0.1
44
schema==0.7.5
55
websockets==10.4
66
structlog==22.1.0

src/collectors.py

+20-8
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
class EvmCollector():
66
"""A collector to fetch information about evm compatible RPC endpoints."""
77

8-
def __init__(self, url, labels, chain_id, **client_parameters):
8+
def __init__(self, url, labels, chain_id, network_status, **client_parameters):
99
self.labels = labels
1010
self.chain_id = chain_id
11+
self.network_status = network_status
1112

1213
sub_payload = {
1314
"method": 'eth_subscribe',
@@ -58,9 +59,10 @@ def client_version(self):
5859
class ConfluxCollector():
5960
"""A collector to fetch information about conflux RPC endpoints."""
6061

61-
def __init__(self, url, labels, chain_id, **client_parameters):
62+
def __init__(self, url, labels, chain_id, network_status, **client_parameters):
6263
self.labels = labels
6364
self.chain_id = chain_id
65+
self.network_status = network_status
6466

6567
sub_payload = {
6668
"method": 'cfx_subscribe',
@@ -111,9 +113,10 @@ def client_version(self):
111113
class CardanoCollector():
112114
"""A collector to fetch information about cardano RPC endpoints."""
113115

114-
def __init__(self, url, labels, chain_id, **client_parameters):
116+
def __init__(self, url, labels, chain_id, network_status, **client_parameters):
115117
self.labels = labels
116118
self.chain_id = chain_id
119+
self.network_status = network_status
117120
self.block_height_payload = {
118121
"id": "exporter",
119122
"jsonrpc": "2.0",
@@ -140,10 +143,11 @@ def latency(self):
140143
class BitcoinCollector():
141144
"""A collector to fetch information about Bitcoin RPC endpoints."""
142145

143-
def __init__(self, url, labels, chain_id, **client_parameters):
146+
def __init__(self, url, labels, chain_id, network_status, **client_parameters):
144147

145148
self.labels = labels
146149
self.chain_id = chain_id
150+
self.network_status = network_status
147151
self.interface = HttpsInterface(url, client_parameters.get('open_timeout'),
148152
client_parameters.get('ping_timeout'))
149153
self._logger_metadata = {
@@ -209,10 +213,11 @@ def latency(self):
209213
class FilecoinCollector():
210214
"""A collector to fetch information about filecoin RPC endpoints."""
211215

212-
def __init__(self, url, labels, chain_id, **client_parameters):
216+
def __init__(self, url, labels, chain_id, network_status, **client_parameters):
213217

214218
self.labels = labels
215219
self.chain_id = chain_id
220+
self.network_status = network_status
216221
self.interface = HttpsInterface(url, client_parameters.get('open_timeout'),
217222
client_parameters.get('ping_timeout'))
218223
self._logger_metadata = {
@@ -264,14 +269,19 @@ def latency(self):
264269
"""Returns connection latency."""
265270
return self.interface.latest_query_latency
266271

272+
def network_status(self):
273+
"""Returns network status."""
274+
return self.interface.network_status
275+
267276

268277
class SolanaCollector():
269278
"""A collector to fetch information about solana RPC endpoints."""
270279

271-
def __init__(self, url, labels, chain_id, **client_parameters):
280+
def __init__(self, url, labels, chain_id, network_status, **client_parameters):
272281

273282
self.labels = labels
274283
self.chain_id = chain_id
284+
self.network_status = network_status
275285
self.interface = HttpsInterface(url, client_parameters.get('open_timeout'),
276286
client_parameters.get('ping_timeout'))
277287
self._logger_metadata = {
@@ -321,10 +331,11 @@ def latency(self):
321331
class StarknetCollector():
322332
"""A collector to fetch information about starknet RPC endpoints."""
323333

324-
def __init__(self, url, labels, chain_id, **client_parameters):
334+
def __init__(self, url, labels, chain_id, network_status, **client_parameters):
325335

326336
self.labels = labels
327337
self.chain_id = chain_id
338+
self.network_status = network_status
328339
self.interface = HttpsInterface(url, client_parameters.get('open_timeout'),
329340
client_parameters.get('ping_timeout'))
330341

@@ -356,10 +367,11 @@ def latency(self):
356367
class AptosCollector():
357368
"""A collector to fetch information about Aptos endpoints."""
358369

359-
def __init__(self, url, labels, chain_id, **client_parameters):
370+
def __init__(self, url, labels, chain_id, network_status, **client_parameters):
360371

361372
self.labels = labels
362373
self.chain_id = chain_id
374+
self.network_status = network_status
363375
self.interface = HttpsInterface(url, client_parameters.get('open_timeout'),
364376
client_parameters.get('ping_timeout'))
365377

src/configuration.py

+4
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ def _load_configuration(self):
5757
And(int),
5858
'network_name':
5959
And(str),
60+
'canonical_name':
61+
And(str),
62+
'network_status':
63+
And(str),
6064
'network_type':
6165
And(str, lambda s: s in ('Testnet', 'Mainnet')),
6266
'collector':

src/metrics.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class MetricsLoader():
1212
def __init__(self):
1313
self._labels = [
1414
'url', 'provider', 'blockchain', 'network_name', 'network_type',
15-
'evmChainID'
15+
'evmChainID', 'canonical_name'
1616
]
1717

1818
@property
@@ -51,6 +51,14 @@ def client_version_metric(self):
5151
'brpc_client_version',
5252
'Client version for the particular RPC endpoint.',
5353
labels=self._labels)
54+
55+
@property
56+
def network_status_metric(self):
57+
"""Returns instantiated network status metric."""
58+
return InfoMetricFamily(
59+
'brpc_network_status',
60+
'Network status - live, preview, degraded',
61+
labels=['canonical_name', 'status'])
5462

5563
@property
5664
def total_difficulty_metric(self):
@@ -126,6 +134,7 @@ def collect(self):
126134
disconnects_metric = self._metrics_loader.disconnects_metric
127135
block_height_metric = self._metrics_loader.block_height_metric
128136
client_version_metric = self._metrics_loader.client_version_metric
137+
network_status_metric = self._metrics_loader.network_status_metric
129138
total_difficulty_metric = self._metrics_loader.total_difficulty_metric
130139
latency_metric = self._metrics_loader.latency_metric
131140
block_height_delta_metric = self._metrics_loader.block_height_delta_metric
@@ -149,6 +158,7 @@ def collect(self):
149158
total_difficulty_metric, 'total_difficulty')
150159
for collector in self._collector_registry:
151160
self._write_metric(collector, latency_metric, 'latency')
161+
self._write_metric(collector, network_status_metric, 'network_status')
152162
self.delta_compared_to_max(
153163
block_height_metric, block_height_delta_metric)
154164
self.delta_compared_to_max(
@@ -161,5 +171,6 @@ def collect(self):
161171
yield client_version_metric
162172
yield total_difficulty_metric
163173
yield latency_metric
174+
yield network_status_metric
164175
yield block_height_delta_metric
165176
yield difficulty_delta_metric

src/registries.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ class Endpoint(): # pylint: disable=too-few-public-methods
1010
"""RPC Endpoint class, to store metadata."""
1111

1212
def __init__( # pylint: disable=too-many-arguments
13-
self, url, provider, blockchain, network_name, network_type,
13+
self, url, provider, blockchain, network_name, canonical_name, network_type, network_status,
1414
chain_id, **client_parameters):
1515
self.url = url
1616
self.chain_id = chain_id
17+
self.canonical_name = canonical_name
18+
self.network_status = network_status
1719
self.labels = [
18-
url, provider, blockchain, network_name, network_type,
20+
url, provider, blockchain, network_name, network_type, canonical_name,
1921
str(chain_id)
2022
]
2123
self.client_parameters = client_parameters
@@ -50,6 +52,8 @@ def get_endpoint_registry(self) -> list:
5052
self.blockchain,
5153
self.get_property('network_name'),
5254
self.get_property('network_type'),
55+
self.get_property('network_status'),
56+
self.get_property('canonical_name'),
5357
self.get_property('chain_id'),
5458
**self.client_parameters))
5559
return endpoints_list
@@ -96,5 +100,6 @@ def get_collector_registry(self) -> list:
96100
else:
97101
collectors_list.append(collector(item.url,
98102
item.labels, item.chain_id,
103+
item.network_status,
99104
**self.client_parameters))
100105
return collectors_list

src/test_collectors.py

+16-8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def setUp(self):
1212
self.url = "wss://test.com"
1313
self.labels = ["dummy", "labels"]
1414
self.chain_id = 123
15+
self.network_status = "live"
1516
self.client_params = {"param1": "dummy", "param2": "data"}
1617
self.sub_payload = {
1718
"method": 'eth_subscribe',
@@ -21,7 +22,7 @@ def setUp(self):
2122
}
2223
with mock.patch('collectors.WebsocketInterface') as mocked_websocket:
2324
self.evm_collector = collectors.EvmCollector(
24-
self.url, self.labels, self.chain_id, **self.client_params)
25+
self.url, self.labels, self.chain_id, self.network_status, **self.client_params)
2526
self.mocked_websocket = mocked_websocket
2627

2728
def test_websocket_interface_created(self):
@@ -99,6 +100,7 @@ def setUp(self):
99100
self.url = "wss://test.com"
100101
self.labels = ["dummy", "labels"]
101102
self.chain_id = 123
103+
self.network_status = "live"
102104
self.client_params = {"param1": "dummy", "param2": "data"}
103105
self.sub_payload = {
104106
"method": 'cfx_subscribe',
@@ -108,7 +110,7 @@ def setUp(self):
108110
}
109111
with mock.patch('collectors.WebsocketInterface') as mocked_websocket:
110112
self.conflux_collector = collectors.ConfluxCollector(
111-
self.url, self.labels, self.chain_id, **self.client_params)
113+
self.url, self.labels, self.chain_id, self.network_status, **self.client_params)
112114
self.mocked_websocket = mocked_websocket
113115

114116
def test_websocket_interface_created(self):
@@ -186,6 +188,7 @@ def setUp(self):
186188
self.url = "wss://test.com"
187189
self.labels = ["dummy", "labels"]
188190
self.chain_id = 123
191+
self.network_status = "live"
189192
self.client_params = {"param1": "dummy", "param2": "data"}
190193
self.block_height_payload = {
191194
"id": "exporter",
@@ -194,7 +197,7 @@ def setUp(self):
194197
}
195198
with mock.patch('collectors.WebsocketInterface') as mocked_websocket:
196199
self.cardano_collector = collectors.CardanoCollector(
197-
self.url, self.labels, self.chain_id, **self.client_params)
200+
self.url, self.labels, self.chain_id, self.network_status, **self.client_params)
198201
self.mocked_websocket = mocked_websocket
199202

200203
def test_websocket_interface_created(self):
@@ -242,6 +245,7 @@ def setUp(self):
242245
self.url = "wss://test.com"
243246
self.labels = ["dummy", "labels"]
244247
self.chain_id = 123
248+
self.network_status = "live"
245249
self.open_timeout = 8
246250
self.ping_timeout = 9
247251
self.client_params = {
@@ -259,7 +263,7 @@ def setUp(self):
259263
}
260264
with mock.patch('collectors.HttpsInterface') as mocked_connection:
261265
self.bitcoin_collector = collectors.BitcoinCollector(
262-
self.url, self.labels, self.chain_id, **self.client_params)
266+
self.url, self.labels, self.chain_id, self.network_status, **self.client_params)
263267
self.mocked_connection = mocked_connection
264268

265269
def test_logger_metadata(self):
@@ -384,6 +388,7 @@ def setUp(self):
384388
self.url = "wss://test.com"
385389
self.labels = ["dummy", "labels"]
386390
self.chain_id = 123
391+
self.network_status = "live"
387392
self.open_timeout = 8
388393
self.ping_timeout = 9
389394
self.client_params = {
@@ -400,7 +405,7 @@ def setUp(self):
400405
}
401406
with mock.patch('collectors.HttpsInterface') as mocked_connection:
402407
self.filecoin_collector = collectors.FilecoinCollector(
403-
self.url, self.labels, self.chain_id, **self.client_params)
408+
self.url, self.labels, self.chain_id, self.network_status, **self.client_params)
404409
self.mocked_connection = mocked_connection
405410

406411
def test_logger_metadata(self):
@@ -498,6 +503,7 @@ def setUp(self):
498503
self.url = "wss://test.com"
499504
self.labels = ["dummy", "labels"]
500505
self.chain_id = 123
506+
self.network_status = "live"
501507
self.open_timeout = 8
502508
self.ping_timeout = 9
503509
self.client_params = {
@@ -514,7 +520,7 @@ def setUp(self):
514520
}
515521
with mock.patch('collectors.HttpsInterface') as mocked_connection:
516522
self.solana_collector = collectors.SolanaCollector(
517-
self.url, self.labels, self.chain_id, **self.client_params)
523+
self.url, self.labels, self.chain_id, self.network_status, **self.client_params)
518524
self.mocked_connection = mocked_connection
519525

520526
def test_logger_metadata(self):
@@ -598,6 +604,7 @@ def setUp(self):
598604
self.url = "wss://test.com"
599605
self.labels = ["dummy", "labels"]
600606
self.chain_id = 123
607+
self.network_status = "live"
601608
self.open_timeout = 8
602609
self.ping_timeout = 9
603610
self.client_params = {
@@ -609,7 +616,7 @@ def setUp(self):
609616
}
610617
with mock.patch('collectors.HttpsInterface') as mocked_connection:
611618
self.starknet_collector = collectors.StarknetCollector(
612-
self.url, self.labels, self.chain_id, **self.client_params)
619+
self.url, self.labels, self.chain_id, self.network_status, **self.client_params)
613620
self.mocked_connection = mocked_connection
614621

615622
def test_https_interface_created(self):
@@ -658,13 +665,14 @@ def setUp(self):
658665
self.url = "https://test.com"
659666
self.labels = ["dummy", "labels"]
660667
self.chain_id = 123
668+
self.network_status = "live"
661669
self.open_timeout = 8
662670
self.ping_timeout = 9
663671
self.client_params = {
664672
"open_timeout": self.open_timeout, "ping_timeout": self.ping_timeout}
665673
with mock.patch('collectors.HttpsInterface') as mocked_connection:
666674
self.aptos_collector = collectors.AptosCollector(
667-
self.url, self.labels, self.chain_id, **self.client_params)
675+
self.url, self.labels, self.chain_id, self.network_status, **self.client_params)
668676
self.mocked_connection = mocked_connection
669677

670678
def test_logger_metadata(self):

src/test_configuration.py

+4
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,14 @@ def test_configuration_attribute(self):
4444
expected_configuration = {
4545
"blockchain":
4646
"TestChain",
47+
"canonical_name":
48+
"canonical_name",
4749
"chain_id":
4850
1234,
4951
"network_name":
5052
"TestNetwork",
53+
"network_status":
54+
"live",
5155
"network_type":
5256
"Mainnet",
5357
"collector":

0 commit comments

Comments
 (0)