diff --git a/plugins/currency/nanopool/nanopool_ b/plugins/currency/nanopool/nanopool_ index bff0d6cb..e5c3a9be 100755 --- a/plugins/currency/nanopool/nanopool_ +++ b/plugins/currency/nanopool/nanopool_ @@ -2,14 +2,36 @@ # -*- coding: utf-8 -*- # vim: set fileencoding=utf-8 - """ =head1 NAME -nanopool_ - Munin plugin to monitor nanopool eth user data. +nanopool_ - Munin plugin to monitor nanopool ethereum user data. + + +=head1 CONFIGURATION + +[nanopool_*] + + - Copy to /usr/share/munin/plugins + - Create symlinks in /etc/munin/plugins to nanopool__, + e.g. ln -s /usr/share/munin/plugins/nanopool_ /etc/munin/plugins/nanopool_hashrate_0x1234567890abcdef1234567890 + Please use the account address in the format "0x
". + + - To enable graphs, link to one or more of the graph types available + - Then restart munin-node + +Graph types and their links: + balance: link to nanopool_balance Show current balance + hashrate: link to nanopool_hashrate Show current calculated hashrate + avghashrate: link to nanopool_avghashrate Show average hashrate of last hour + worker: link to nanopool_worker Show worker data + + +Thanks to the authors of other Python munin plugins. I've used some of +them as inspiring example. =head1 VERSION -0.0.1 +1.0.0 =head1 AUTHOR L @@ -29,171 +51,205 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -=head1 CONFIGURATION - - - Copy to /usr/share/munin/plugins - - Create symlinks in /etc/munin/plugins to nanopool_, - e.g. ln -s /usr/share/munin/plugins/nanopool_ /etc/munin/plugins/nanopool_hashrate - - To enable graphs, link to one or more of the graph types available - - Then restart munin-node - -Graph types and their links: - balance: link to nanopool_balance Show current balance - hashrate: link to nanopool_hashrate Show current calculated hashrate - avghashrate: link to nanopool_avghashrate Show average hashrate of last hour - worker: link to nanopool_worker Show worker data - -Configuration parameters: - env.account_address - the address of the account in form "0x
" - -Thanks to the authors of other Python munin plugins. I've used some of -them as inspiring example. - - =head1 MAGIC MARKERS #%# family=contrib -#%# capabilities=autoconf suggest - +#%# capabilities=suggest +=cut """ +from __future__ import print_function import os import sys import json try: - from urllib.request import Request, urlopen # Python 3 + # Python 3 + from urllib.request import Request + from urllib.request import urlopen except: - from urllib2 import Request, urlopen # Python 2 + # Python 2 + from urllib2 import Request + from urllib2 import urlopen + +def define_graph_types(): + graph_types = { + "balance" : [ + { + "title" : "Balance of {0}".format(account_address), + "type" : "GAUGE", + "args" : "--base 1000 -l 0", + "fields" : ["ETH"], + "scale": "no", + "info": "Balance in ETH" + } + ], + "hashrate" : [ + { + "title" : "Hashrate of {0}".format(account_address), + "type" : "GAUGE", + "args" : "--base 1000 -l 0", + "fields" : ["hashrate"], + "info": "Current Calculated Hashrate in Mh/s" + } + ], + "avghashrate" : [ + { + "title" : "Average Hashrate of {0}".format(account_address), + "type" : "GAUGE", + "args" : "--base 1000 -l 0", + "fields" : ["avg_hashrate"], + "info": "Average Hashrate of last hour in Mh/s" - -GRAPH_TYPES = { - "balance" : [ - { - "title" : "Balance", - "type" : "GAUGE", - "args" : "--base 1000 -l 0", - "fields" : ["ETH"], - "scale": "no", - "info": "Balance in ETH" - } - ], - "hashrate" : [ - { - "title" : "Hashrate", - "type" : "GAUGE", - "args" : "--base 1000 -l 0", - "fields" : ["hashrate"], - "info": "Current Calculated Hashrate in Mh/s" - } - ], - "avghashrate" : [ - { - "title" : "Average Hashrate", - "type" : "GAUGE", - "args" : "--base 1000 -l 0", - "fields" : ["avg_hashrate"], - "info": "Average Hashrate of last hour in Mh/s" - - } - ], - "worker" : [ - { - "title" : "Worker" - } - ] -} + } + ], + "worker" : [ + { + "title" : "Worker" + } + ] + } + return graph_types def request_data(): - try: - address = os.environ["account_address"] - except KeyError: - raise Exception("Environment variable account_address not found, please configure!") - - url = 'https://api.nanopool.org/v1/eth/user/' + address + url = "https://api.nanopool.org/v1/eth/user/{0}".format(account_address) req = Request(url) - req.add_header('User-Agent', 'Nozilla/5.0') # this fake is necessary to get values, otherwise the request ends in a 403 error - txt = urlopen(req).read() + # this fake is necessary to get values, otherwise the request ends in a 403 error + req.add_header('User-Agent', 'Nozilla/5.0') + try: + txt = urlopen(req).read() + except Exception as err: + # there could be different exceptions like ValueError, URLError, HTTPError + print("API request error: {0}". format(err), file=sys.stderr) + exit(1) return json.loads(txt.decode("utf-8")) def write_config_worker(): data = request_data() - worker_data = data["data"]["workers"] + worker_data = sorted(data["data"]["workers"], key=lambda element: element["id"]) - print("multigraph worker_hashrate") - print("graph_title Hashrate in Mh/s per worker") + print("multigraph worker_hashrate_{0}".format(account_address)) + print("graph_title Hashrate in Mh/s per worker ({0})".format(account_address)) print("graph_args --base 1000 -l 0") print("graph_vlabel Mh/s") print("graph_category other") - print("graph_width 400") print("graph_scale no") for i, val in enumerate(worker_data): - print("worker" + str(i) + "_hashrate.label " + str(val["id"])) - print("worker" + str(i) + "_hashrate.type GAUGE") - print("worker" + str(i) + "_hashrate.info Hashrate of worker '" + str(val["id"]) + "'") - print("worker" + str(i) + "_hashrate.min 0") - print("worker" + str(i) + "_hashrate.draw LINE1") + worker_name = "_".join(val["id"].split()) + print("worker_{0}_hashrate.label {1}".format(worker_name, str(val["id"]))) + print("worker_{0}_hashrate.type GAUGE".format(worker_name)) + print("worker_{0}_hashrate.info Hashrate of worker '{1}'".format(worker_name, str(val["id"]))) + print("worker_{0}_hashrate.min 0".format(worker_name)) + print("worker_{0}_hashrate.draw LINE1".format(worker_name)) + + for val in worker_data: + print("") + worker_name = "_".join(val["id"].split()) + print("multigraph worker_hashrate_{0}.worker_{1}".format(account_address, worker_name)) + print("graph_title Hashrate in Mh/s of worker {0}".format(worker_name)) + print("graph_args --base 1000 -l 0") + print("graph_vlabel Mh/s") + print("graph_category other") + print("graph_scale no") + print("whashrate.label hashrate") + print("whashrate.type GAUGE") + print("whashrate.info Hashrate of worker {0}".format(str(val["id"]))) + print("whashrate.min 0") + print("whashrate.draw LINE1") print("") - print("multigraph worker_shares") - print("graph_title Number of accepted shares") + print("multigraph worker_shares_{0}".format(account_address)) + print("graph_title Number of accepted shares ({0})".format(account_address)) print("graph_args --base 1000 -l 0") print("graph_vlabel Shares per ${graph_period}") print("graph_category other") - print("graph_width 400") print("graph_scale no") print("graph_period minute") for i, val in enumerate(worker_data): - print("worker" + str(i) + "_shares.label " + str(val["id"])) - print("worker" + str(i) + "_shares.type COUNTER") - print("worker" + str(i) + "_shares.info Accepted shares of worker '" + str(val["id"]) + "'") - print("worker" + str(i) + "_shares.min 0") - print("worker" + str(i) + "_shares.draw LINE1") + worker_name = "_".join(val["id"].split()) + print("worker_{0}_shares.label {1} ".format(worker_name, str(val["id"]))) + print("worker_{0}_shares.type COUNTER".format(worker_name)) + print("worker_{0}_shares.info Accepted shares of worker '{1}'".format(worker_name, str(val["id"]))) + print("worker_{0}_shares.min 0".format(worker_name)) + print("worker_{0}_shares.draw LINE1".format(worker_name)) + + for val in worker_data: + worker_name = "_".join(val["id"].split()) + print("") + print("multigraph worker_shares_{0}.worker_{1}".format(account_address, worker_name)) + print("graph_title Number of accepted shares {0}".format(worker_name)) + print("graph_args --base 1000 -l 0") + print("graph_vlabel Shares per ${graph_period}") + print("graph_category other") + print("graph_scale no") + print("graph_period minute") + print("wshares.label shares") + print("wshares.type COUNTER") + print("wshares.info Accepted shares of worker '{0}'".format(str(val["id"]))) + print("wshares.min 0") + print("wshares.draw LINE1") def write_data_worker(data): - worker_data = data["data"]["workers"] + worker_data = sorted(data["data"]["workers"], key=lambda element: element["id"]) - print("multigraph worker_hashrate") - for i, val in enumerate(worker_data): - print("worker" + str(i) + "_hashrate.value " + str(val["hashrate"])) + print("multigraph worker_hashrate_{0}".format(account_address)) - print - print("multigraph worker_shares") for i, val in enumerate(worker_data): - print("worker" + str(i) + "_shares.value " + str(val["rating"])) + worker_name = "_".join(val["id"].split()) + print("worker_{0}_hashrate.value {1}".format(worker_name, str(val["hashrate"]))) + + for val in worker_data: + print("") + worker_name = "_".join(val["id"].split()) + print("multigraph worker_hashrate_{0}.worker_{1}".format(account_address, worker_name)) + print("whashrate.value {0}".format(str(val["hashrate"]))) + + print("") + print("multigraph worker_shares_{0}".format(account_address)) + for i, val in enumerate(worker_data): + worker_name = "_".join(val["id"].split()) + print("worker_{0}_shares.value {1}".format(worker_name, str(val["rating"]))) + + for val in worker_data: + worker_name = "_".join(val["id"].split()) + print("") + print("multigraph worker_shares_{0}.worker_{1}".format(account_address, worker_name)) + print("wshares.value {0} ".format(str(val["rating"]))) + def write_config(): if graph_type not in GRAPH_TYPES.keys(): - raise Exception("Unknown graph type '%s'" %graph_type) + print("Unknown graph type '{0}'".format(graph_type), file=sys.stderr) + exit(1) if graph_type == "worker": write_config_worker() return params = GRAPH_TYPES[graph_type] for item in params: - print("graph_title %s" % item["title"]) + print("graph_title {0}".format(item["title"])) print("graph_category other") if "info" in item: - print("graph_info %s" % item["info"]) + print("graph_info {0}".format(item["info"])) if "scale" in item: - print("graph_scale %s" % item["scale"]) + print("graph_scale {0}".format(item["scale"])) if "args" in item: - print("graph_args %s" % item["args"]) + print("graph_args {0}".format(item["args"])) for field in item["fields"]: - print("%s.label %s" % (field, field)) - print("%s.type %s" % (field, item["type"])) + print("{0}.label {1}".format(field, field)) + print("{0}.type {1}".format(field, item["type"])) def write_suggest(): for item in GRAPH_TYPES.keys(): @@ -203,32 +259,32 @@ def write_data(): data = request_data() if graph_type == "balance": - print("ETH.value %s" % data['data']['balance']) + print("ETH.value {0}".format(data['data']['balance'])) elif graph_type == "hashrate": - print("hashrate.value %s" % data["data"]["hashrate"]) + print("hashrate.value {0}".format(data["data"]["hashrate"])) elif graph_type == "avghashrate": - print("avg_hashrate.value %s" % data["data"]["avgHashrate"]["h1"]) + print("avg_hashrate.value {0}".format(data["data"]["avgHashrate"]["h1"])) elif graph_type == "worker": write_data_worker(data) + else: + pass -def check_autoconf(): - try: - address = os.environ["account_address"] - print("yes") - except KeyError: - print("no (Environment variable account_address not found, please configure!)") - exit(0) if __name__ == "__main__": program = sys.argv[0] - graph_type = program[program.rfind("_")+1:] + try: + graph_type, account_address = program.split("_")[1:] + except ValueError: + print("Please configure the plugin as described in the configuration section.") + exit(1) - if len(sys.argv) == 2 and sys.argv[1] == "autoconf": - check_autoconf() - elif len(sys.argv) == 2 and sys.argv[1] == "config": + GRAPH_TYPES = define_graph_types() + if len(sys.argv) > 1 and sys.argv[1] == "autoconf": + print("no") + elif len(sys.argv) > 1 and sys.argv[1] == "config": write_config() - elif len(sys.argv) == 2 and sys.argv[1] == "suggest": + elif len(sys.argv) > 1 and sys.argv[1] == "suggest": write_suggest() else: write_data()