Skip to content

Commit 7e2a2d5

Browse files
authored
Merge pull request #414 from yungwine/prometheus
add Prometheus metrics pusher
2 parents 7018d54 + 1b388e4 commit 7e2a2d5

File tree

4 files changed

+91
-1
lines changed

4 files changed

+91
-1
lines changed

modules/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from modules.controller import ControllerModule
1010
from modules.liteserver import LiteserverModule
1111
from modules.alert_bot import AlertBotModule
12+
from modules.prometheus import PrometheusModule
1213

1314

1415
MODES = {
@@ -17,7 +18,8 @@
1718
'single-nominator': SingleNominatorModule,
1819
'liquid-staking': ControllerModule,
1920
'liteserver': LiteserverModule,
20-
'alert-bot': AlertBotModule
21+
'alert-bot': AlertBotModule,
22+
'prometheus': PrometheusModule
2123
}
2224

2325

@@ -61,6 +63,7 @@ class Setting:
6163
'ChatId': Setting('alert-bot', None, 'Alerting Telegram chat id'),
6264
'auto_backup': Setting('validator', None, 'Make validator backup every election'),
6365
'auto_backup_path': Setting('validator', '/tmp/mytoncore/auto_backups/', 'Path to store auto-backups'),
66+
'prometheus_url': Setting('prometheus', None, 'Prometheus pushgateway url'),
6467
'onlyNode': Setting(None, None, 'MyTonCtrl will work only for collecting validator telemetry (if `sendTelemetry` is True), without participating in Elections and etc.')
6568
}
6669

modules/prometheus.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from modules.module import MtcModule
2+
import dataclasses
3+
import requests
4+
5+
6+
@dataclasses.dataclass
7+
class Metric:
8+
name: str
9+
description: str
10+
type: str
11+
12+
def to_format(self, value):
13+
return f"""
14+
# HELP {self.name} {self.description}
15+
# TYPE {self.name} {self.type}
16+
{self.name} {value}
17+
"""
18+
19+
20+
METRICS = {
21+
'master_out_of_sync': Metric('validator_masterchain_out_of_sync_seconds', 'Time difference between current time and timestamp of the last known block', 'gauge'),
22+
'shard_out_of_sync': Metric('validator_shardchain_out_of_sync_blocks', 'Number of blocks node\'s shardclient is behind the last known block', 'gauge'),
23+
'out_of_ser': Metric('validator_out_of_serialization', 'Number of blocks last state serialization was ago', 'gauge'),
24+
'vc_up': Metric('validator_console_up', 'Is `validator-console` up', 'gauge'),
25+
'validator_id': Metric('validator_index', 'Validator index', 'gauge'),
26+
'stake': Metric('validator_stake', 'Validator stake', 'gauge'),
27+
'celldb_gc_block': Metric('validator_celldb_gc_block', 'Celldb GC block latency', 'gauge'),
28+
'celldb_gc_state': Metric('validator_celldb_gc_state', 'Celldb GC queue size', 'gauge'),
29+
}
30+
31+
32+
class PrometheusModule(MtcModule):
33+
34+
description = 'Prometheus format data exporter'
35+
default_value = False
36+
37+
def __init__(self, ton, local, *args, **kwargs):
38+
super().__init__(ton, local, *args, **kwargs)
39+
40+
def get_validator_status_metrics(self, result: list):
41+
status = self.ton.GetValidatorStatus()
42+
is_working = status.is_working or (status.unixtime is not None)
43+
if status.masterchain_out_of_sync is not None:
44+
result.append(METRICS['master_out_of_sync'].to_format(status.masterchain_out_of_sync))
45+
if status.shardchain_out_of_sync is not None:
46+
result.append(METRICS['shard_out_of_sync'].to_format(status.shardchain_out_of_sync))
47+
if status.masterchain_out_of_ser is not None:
48+
result.append(METRICS['out_of_ser'].to_format(status.masterchain_out_of_ser))
49+
if status.masterchainblock is not None and status.gcmasterchainblock is not None:
50+
result.append(METRICS['celldb_gc_block'].to_format(status.masterchainblock - status.gcmasterchainblock))
51+
if status.gcmasterchainblock is not None and status.last_deleted_mc_state is not None:
52+
result.append(METRICS['celldb_gc_state'].to_format(status.gcmasterchainblock - status.last_deleted_mc_state))
53+
result.append(METRICS['vc_up'].to_format(int(is_working)))
54+
55+
def get_validator_validation_metrics(self, result: list):
56+
index = self.ton.GetValidatorIndex()
57+
result.append(METRICS['validator_id'].to_format(index))
58+
config = self.ton.GetConfig34()
59+
save_elections = self.ton.GetSaveElections()
60+
elections = save_elections.get(str(config["startWorkTime"]))
61+
if elections is not None:
62+
adnl = self.ton.GetAdnlAddr()
63+
stake = elections.get(adnl, {}).get('stake')
64+
if stake:
65+
result.append(METRICS['stake'].to_format(round(stake, 2)))
66+
67+
def push_metrics(self):
68+
if not self.ton.using_prometheus():
69+
return
70+
71+
url = self.ton.local.db.get('prometheus_url')
72+
if url is None:
73+
raise Exception('Prometheus url is not set')
74+
metrics = []
75+
self.local.try_function(self.get_validator_status_metrics, args=[metrics])
76+
self.local.try_function(self.get_validator_validation_metrics, args=[metrics])
77+
requests.post(url, data='\n'.join(metrics).encode())
78+
79+
def add_console_commands(self, console):
80+
...

mytoncore/functions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,9 @@ def General(local):
576576
from modules.alert_bot import AlertBotModule
577577
local.start_cycle(AlertBotModule(ton, local).check_status, sec=60, args=())
578578

579+
from modules.prometheus import PrometheusModule
580+
local.start_cycle(PrometheusModule(ton, local).push_metrics, sec=30, args=())
581+
579582
thr_sleep()
580583
# end define
581584

mytoncore/mytoncore.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@ def GetValidatorStatus(self):
796796
status.masterchain_out_of_ser = status.masterchainblock - status.stateserializermasterchainseqno
797797
status.out_of_sync = status.masterchain_out_of_sync if status.masterchain_out_of_sync > status.shardchain_out_of_sync else status.shardchain_out_of_sync
798798
status.out_of_ser = status.masterchain_out_of_ser
799+
status.last_deleted_mc_state = int(parse(result, "last_deleted_mc_state", '\n'))
799800
except Exception as ex:
800801
self.local.add_log(f"GetValidatorStatus warning: {ex}", "warning")
801802
status.is_working = False
@@ -3123,6 +3124,9 @@ def using_liteserver(self):
31233124
def using_alert_bot(self):
31243125
return self.get_mode_value('alert-bot')
31253126

3127+
def using_prometheus(self):
3128+
return self.get_mode_value('prometheus')
3129+
31263130
def Tlb2Json(self, text):
31273131
# Заменить скобки
31283132
start = 0

0 commit comments

Comments
 (0)