125 lines
4.4 KiB
Python
125 lines
4.4 KiB
Python
|
#!/usr/bin/python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
# cribbed from https://gist.github.com/ageis/a0623ae6ec9cfc72e5cb6bde5754ab1f
|
||
|
|
||
|
import json
|
||
|
import time
|
||
|
import subprocess
|
||
|
import sys
|
||
|
import os
|
||
|
from prometheus_client import start_http_server, Gauge, Counter
|
||
|
|
||
|
# Create Prometheus metrics to track bitcoind stats.
|
||
|
LBCD_BLOCKS = Gauge('lbcd_blocks', 'Block height')
|
||
|
LBCD_DIFFICULTY = Gauge('lbcd_difficulty', 'Difficulty')
|
||
|
LBCD_PEERS = Gauge('lbcd_peers', 'Number of peers')
|
||
|
LBCD_HASHPS = Gauge('lbcd_hashps', 'Estimated network hash rate per second')
|
||
|
|
||
|
LBCD_ERRORS = Counter('lbcd_errors', 'Number of errors detected')
|
||
|
LBCD_UPTIME = Gauge('lbcd_uptime', 'Number of seconds the Bitcoin daemon has been running')
|
||
|
|
||
|
LBCD_MEMPOOL_BYTES = Gauge('lbcd_mempool_bytes', 'Size of mempool in bytes')
|
||
|
LBCD_MEMPOOL_SIZE = Gauge('lbcd_mempool_size', 'Number of unconfirmed transactions in mempool')
|
||
|
|
||
|
LBCD_LATEST_BLOCK_SIZE = Gauge('lbcd_latest_block_size', 'Size of latest block in bytes')
|
||
|
LBCD_LATEST_BLOCK_TXS = Gauge('lbcd_latest_block_txs', 'Number of transactions in latest block')
|
||
|
|
||
|
LBCD_NUM_CHAINTIPS = Gauge('lbcd_num_chaintips', 'Number of known blockchain branches')
|
||
|
|
||
|
LBCD_TOTAL_BYTES_RECV = Gauge('lbcd_total_bytes_recv', 'Total bytes received')
|
||
|
LBCD_TOTAL_BYTES_SENT = Gauge('lbcd_total_bytes_sent', 'Total bytes sent')
|
||
|
|
||
|
LBCD_LATEST_BLOCK_INPUTS = Gauge('lbcd_latest_block_inputs', 'Number of inputs in transactions of latest block')
|
||
|
LBCD_LATEST_BLOCK_OUTPUTS = Gauge('lbcd_latest_block_outputs', 'Number of outputs in transactions of latest block')
|
||
|
|
||
|
|
||
|
|
||
|
PORT = int(os.getenv('PROMETHEUS_PORT', 2112))
|
||
|
LBCCTL_PATH = os.getenv('LBCCTL_PATH')
|
||
|
if LBCCTL_PATH is None:
|
||
|
raise Exception("LBCCTL_PATH env var required")
|
||
|
|
||
|
|
||
|
|
||
|
def lbcd(cmd):
|
||
|
p = subprocess.Popen([LBCCTL_PATH, cmd], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
|
||
|
output = p.communicate()[0]
|
||
|
return json.loads(output.decode('utf-8'))
|
||
|
|
||
|
|
||
|
def lbcctl(cmd):
|
||
|
p = subprocess.Popen([LBCCTL_PATH, cmd], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
|
||
|
output = p.communicate()[0]
|
||
|
return output.decode('utf-8')
|
||
|
|
||
|
|
||
|
def get_block(block_height):
|
||
|
try:
|
||
|
blockhash = subprocess.check_output([LBCCTL_PATH, 'getblockhash', block_height]).rstrip()
|
||
|
block = subprocess.check_output([LBCCTL_PATH, 'getblock', blockhash]).rstrip()
|
||
|
except Exception as e:
|
||
|
print(e)
|
||
|
print('Error: Can\'t retrieve block number ' + block_height + ' from lbcd.')
|
||
|
return None
|
||
|
return json.loads(block.decode('utf-8'))
|
||
|
|
||
|
|
||
|
def get_raw_tx(txid):
|
||
|
try:
|
||
|
rawtx = subprocess.check_output([LBCCTL_PATH, 'getrawtransaction', txid, '1'])
|
||
|
except Exception as e:
|
||
|
print(e)
|
||
|
print('Error: Can\'t retrieve raw transaction ' + txid + ' from lbcd.')
|
||
|
return None
|
||
|
return json.loads(rawtx.decode('utf-8'))
|
||
|
|
||
|
|
||
|
def main():
|
||
|
# Start up the server to expose the metrics.
|
||
|
start_http_server(PORT)
|
||
|
while True:
|
||
|
info = lbcd('getinfo')
|
||
|
LBCD_BLOCKS.set(info['blocks'])
|
||
|
LBCD_PEERS.set(info['connections'])
|
||
|
LBCD_DIFFICULTY.set(info['difficulty'])
|
||
|
|
||
|
if info['errors']:
|
||
|
LBCD_ERRORS.inc()
|
||
|
|
||
|
LBCD_HASHPS.set(float(lbcctl('getnetworkhashps')))
|
||
|
LBCD_UPTIME.set(int(lbcctl('uptime')))
|
||
|
|
||
|
#chaintips = len(lbcd('getchaintips'))
|
||
|
#LBCD_NUM_CHAINTIPS.set(chaintips)
|
||
|
|
||
|
mempool = lbcd('getmempoolinfo')
|
||
|
LBCD_MEMPOOL_BYTES.set(mempool['bytes'])
|
||
|
LBCD_MEMPOOL_SIZE.set(mempool['size'])
|
||
|
|
||
|
nettotals = lbcd('getnettotals')
|
||
|
LBCD_TOTAL_BYTES_RECV.set(nettotals['totalbytesrecv'])
|
||
|
LBCD_TOTAL_BYTES_SENT.set(nettotals['totalbytessent'])
|
||
|
|
||
|
latest_block = get_block(str(info['blocks']))
|
||
|
if latest_block:
|
||
|
LBCD_LATEST_BLOCK_SIZE.set(latest_block['size'])
|
||
|
LBCD_LATEST_BLOCK_TXS.set(len(latest_block['tx']))
|
||
|
inputs, outputs = 0, 0
|
||
|
# counting transaction inputs and outputs requires txindex=1
|
||
|
# to be enabled, which may also necessitate reindex=1 in lbcd.conf
|
||
|
for tx in latest_block['tx']:
|
||
|
rawtx = get_raw_tx(tx)
|
||
|
if not rawtx:
|
||
|
continue
|
||
|
inputs += len(rawtx['vin'])
|
||
|
outputs += len(rawtx['vout'])
|
||
|
|
||
|
LBCD_LATEST_BLOCK_INPUTS.set(inputs)
|
||
|
LBCD_LATEST_BLOCK_OUTPUTS.set(outputs)
|
||
|
|
||
|
time.sleep(60)
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|