Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / currency / nanopool / nanopool_ @ 09b88141

Historique | Voir | Annoter | Télécharger (9,77 ko)

1 8dcd1caa Ralf Geschke
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
# vim: set fileencoding=utf-8
4
5
"""
6
=head1 NAME
7
8 58b1c1ec Ralf Geschke
nanopool_ - Munin plugin to monitor nanopool ethereum user data.
9
10
11
=head1 CONFIGURATION
12
13
[nanopool_*]
14
15
        - Copy to /usr/share/munin/plugins
16
        - Create symlinks in /etc/munin/plugins to nanopool_<graph type>_<account_address>,
17
          e.g. ln -s /usr/share/munin/plugins/nanopool_ /etc/munin/plugins/nanopool_hashrate_0x1234567890abcdef1234567890
18
          Please use the account address in the format "0x<address>".
19
20
        - To enable graphs, link to one or more of the graph types available
21
        - Then restart munin-node
22
23
Graph types and their links:
24
        balance: link to nanopool_balance           Show current balance
25
        hashrate: link to nanopool_hashrate         Show current calculated hashrate
26
        avghashrate: link to nanopool_avghashrate   Show average hashrate of last hour
27
        worker: link to nanopool_worker             Show worker data
28
29
30
Thanks to the authors of other Python munin plugins. I've used some of
31
them as inspiring example.
32 8dcd1caa Ralf Geschke
33
=head1 VERSION
34 e8ff8cf4 Ralf Geschke
1.0.1
35 8dcd1caa Ralf Geschke
36
=head1 AUTHOR
37
L<Ralf Geschke|https://github.com/geschke>
38
39
=head1 LICENSE
40
41
This program is free software: you can redistribute it and/or modify
42
it under the terms of the GNU General Public License as published by
43
the Free Software Foundation, either version 3 of the License, or
44
(at your option) any later version.
45
46
This program is distributed in the hope that it will be useful,
47
but WITHOUT ANY WARRANTY; without even the implied warranty of
48
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
49
GNU General Public License for more details.
50
51
You should have received a copy of the GNU General Public License
52
along with this program.  If not, see <http://www.gnu.org/licenses/>.
53
54 09b88141 Lars Kruse
SPDX-License-Identifier: GPL-3.0-or-later
55
56 8dcd1caa Ralf Geschke
=head1 MAGIC MARKERS
57
58 09b88141 Lars Kruse
 #%# family=contrib
59
 #%# capabilities=suggest
60 8dcd1caa Ralf Geschke
61 58b1c1ec Ralf Geschke
=cut
62 8dcd1caa Ralf Geschke
"""
63
64 58b1c1ec Ralf Geschke
from __future__ import print_function
65 8dcd1caa Ralf Geschke
66
import os
67
import sys
68
import json
69
70
try:
71 58b1c1ec Ralf Geschke
    # Python 3
72
    from urllib.request import Request
73
    from urllib.request import urlopen
74 e8ff8cf4 Ralf Geschke
    from urllib.request import URLError
75 8dcd1caa Ralf Geschke
except:
76 58b1c1ec Ralf Geschke
    # Python 2
77
    from urllib2 import Request
78
    from urllib2 import urlopen
79 e8ff8cf4 Ralf Geschke
    from urllib2 import URLError
80 17f78427 Lars Kruse
81 58b1c1ec Ralf Geschke
82
83
def define_graph_types():
84
    graph_types = {
85
        "balance" : [
86
            {
87
                "title" : "Balance of {0}".format(account_address),
88
                "type" : "GAUGE",
89
                "args" : "--base 1000 -l 0",
90
                "fields" : ["ETH"],
91
                "scale": "no",
92
                "info": "Balance in ETH"
93
            }
94
        ],
95
        "hashrate" : [
96
            {
97
                "title" : "Hashrate of {0}".format(account_address),
98
                "type" : "GAUGE",
99
                "args" : "--base 1000 -l 0",
100
                "fields" : ["hashrate"],
101
                "info": "Current Calculated Hashrate in Mh/s"
102
            }
103
        ],
104
        "avghashrate" : [
105
            {
106
                "title" : "Average Hashrate of {0}".format(account_address),
107
                "type" : "GAUGE",
108
                "args" : "--base 1000 -l 0",
109
                "fields" : ["avg_hashrate"],
110
                "info": "Average Hashrate of last hour in Mh/s"
111
112
            }
113
        ],
114
        "worker" : [
115
            {
116
                "title" : "Worker"
117
            }
118
        ]
119
    }
120
    return graph_types
121 8dcd1caa Ralf Geschke
122
123
def request_data():
124
125 58b1c1ec Ralf Geschke
    url = "https://api.nanopool.org/v1/eth/user/{0}".format(account_address)
126 8dcd1caa Ralf Geschke
127
    req = Request(url)
128 58b1c1ec Ralf Geschke
    # this fake is necessary to get values, otherwise the request ends in a 403 error
129
    req.add_header('User-Agent', 'Nozilla/5.0')
130
    try:
131
        txt = urlopen(req).read()
132 e8ff8cf4 Ralf Geschke
    except URLError as err:
133 58b1c1ec Ralf Geschke
        print("API request error: {0}". format(err), file=sys.stderr)
134
        exit(1)
135 e8ff8cf4 Ralf Geschke
    except:
136 17f78427 Lars Kruse
        print("Unhandled error:", sys.exc_info()[0])
137 e8ff8cf4 Ralf Geschke
        exit(1)
138
    try:
139
        result = json.loads(txt.decode("utf-8"))
140
    except ValueError as err:
141
        print("Could not decode JSON error: {0}". format(err), file=sys.stderr)
142
        exit(1)
143
    return result
144 8dcd1caa Ralf Geschke
145
def write_config_worker():
146
    data = request_data()
147 58b1c1ec Ralf Geschke
    worker_data = sorted(data["data"]["workers"], key=lambda element: element["id"])
148 8dcd1caa Ralf Geschke
149 58b1c1ec Ralf Geschke
    print("multigraph worker_hashrate_{0}".format(account_address))
150
    print("graph_title Hashrate in Mh/s per worker ({0})".format(account_address))
151 8dcd1caa Ralf Geschke
    print("graph_args --base 1000 -l 0")
152
    print("graph_vlabel Mh/s")
153 5a45d497 Lars Kruse
    print("graph_category htc")
154 8dcd1caa Ralf Geschke
    print("graph_scale no")
155
156 e8ff8cf4 Ralf Geschke
    for val in worker_data:
157 58b1c1ec Ralf Geschke
        worker_name = "_".join(val["id"].split())
158 e8ff8cf4 Ralf Geschke
        print("worker_{0}_hashrate.label {1}".format(worker_name, val["id"]))
159 58b1c1ec Ralf Geschke
        print("worker_{0}_hashrate.type GAUGE".format(worker_name))
160 e8ff8cf4 Ralf Geschke
        print("worker_{0}_hashrate.info Hashrate of worker '{1}'".format(worker_name, val["id"]))
161 58b1c1ec Ralf Geschke
        print("worker_{0}_hashrate.min 0".format(worker_name))
162
        print("worker_{0}_hashrate.draw LINE1".format(worker_name))
163 17f78427 Lars Kruse
164 58b1c1ec Ralf Geschke
    for val in worker_data:
165
        print("")
166
        worker_name = "_".join(val["id"].split())
167
        print("multigraph worker_hashrate_{0}.worker_{1}".format(account_address, worker_name))
168
        print("graph_title Hashrate in Mh/s of worker {0}".format(worker_name))
169
        print("graph_args --base 1000 -l 0")
170
        print("graph_vlabel Mh/s")
171 5a45d497 Lars Kruse
        print("graph_category htc")
172 58b1c1ec Ralf Geschke
        print("graph_scale no")
173
        print("whashrate.label hashrate")
174
        print("whashrate.type GAUGE")
175 e8ff8cf4 Ralf Geschke
        print("whashrate.info Hashrate of worker {0}".format(val["id"]))
176 58b1c1ec Ralf Geschke
        print("whashrate.min 0")
177
        print("whashrate.draw LINE1")
178 8dcd1caa Ralf Geschke
179
    print("")
180 58b1c1ec Ralf Geschke
    print("multigraph worker_shares_{0}".format(account_address))
181
    print("graph_title Number of accepted shares ({0})".format(account_address))
182 8dcd1caa Ralf Geschke
    print("graph_args --base 1000 -l 0")
183
    print("graph_vlabel Shares per ${graph_period}")
184 5a45d497 Lars Kruse
    print("graph_category htc")
185 8dcd1caa Ralf Geschke
    print("graph_scale no")
186
    print("graph_period minute")
187
188 e8ff8cf4 Ralf Geschke
    for val in worker_data:
189 58b1c1ec Ralf Geschke
        worker_name = "_".join(val["id"].split())
190 e8ff8cf4 Ralf Geschke
        print("worker_{0}_shares.label {1} ".format(worker_name, val["id"]))
191 58b1c1ec Ralf Geschke
        print("worker_{0}_shares.type COUNTER".format(worker_name))
192 e8ff8cf4 Ralf Geschke
        print("worker_{0}_shares.info Accepted shares of worker '{1}'".format(worker_name, val["id"]))
193 58b1c1ec Ralf Geschke
        print("worker_{0}_shares.min 0".format(worker_name))
194
        print("worker_{0}_shares.draw LINE1".format(worker_name))
195
196
    for val in worker_data:
197
        worker_name = "_".join(val["id"].split())
198
        print("")
199
        print("multigraph worker_shares_{0}.worker_{1}".format(account_address, worker_name))
200
        print("graph_title Number of accepted shares {0}".format(worker_name))
201
        print("graph_args --base 1000 -l 0")
202
        print("graph_vlabel Shares per ${graph_period}")
203 5a45d497 Lars Kruse
        print("graph_category htc")
204 58b1c1ec Ralf Geschke
        print("graph_scale no")
205
        print("graph_period minute")
206
        print("wshares.label shares")
207
        print("wshares.type COUNTER")
208 e8ff8cf4 Ralf Geschke
        print("wshares.info Accepted shares of worker '{0}'".format(val["id"]))
209 58b1c1ec Ralf Geschke
        print("wshares.min 0")
210
        print("wshares.draw LINE1")
211 8dcd1caa Ralf Geschke
212
213
def write_data_worker(data):
214 58b1c1ec Ralf Geschke
    worker_data = sorted(data["data"]["workers"], key=lambda element: element["id"])
215
216
    print("multigraph worker_hashrate_{0}".format(account_address))
217 8dcd1caa Ralf Geschke
218 e8ff8cf4 Ralf Geschke
    for val in worker_data:
219 58b1c1ec Ralf Geschke
        worker_name = "_".join(val["id"].split())
220 e8ff8cf4 Ralf Geschke
        print("worker_{0}_hashrate.value {1}".format(worker_name, val["hashrate"]))
221 8dcd1caa Ralf Geschke
222 58b1c1ec Ralf Geschke
    for val in worker_data:
223
        print("")
224
        worker_name = "_".join(val["id"].split())
225
        print("multigraph worker_hashrate_{0}.worker_{1}".format(account_address, worker_name))
226 e8ff8cf4 Ralf Geschke
        print("whashrate.value {0}".format(val["hashrate"]))
227 58b1c1ec Ralf Geschke
228
    print("")
229
    print("multigraph worker_shares_{0}".format(account_address))
230 e8ff8cf4 Ralf Geschke
    for val in worker_data:
231 58b1c1ec Ralf Geschke
        worker_name = "_".join(val["id"].split())
232 e8ff8cf4 Ralf Geschke
        print("worker_{0}_shares.value {1}".format(worker_name, val["rating"]))
233 58b1c1ec Ralf Geschke
234
    for val in worker_data:
235
        worker_name = "_".join(val["id"].split())
236
        print("")
237
        print("multigraph worker_shares_{0}.worker_{1}".format(account_address, worker_name))
238 e8ff8cf4 Ralf Geschke
        print("wshares.value {0} ".format(val["rating"]))
239 17f78427 Lars Kruse
240 8dcd1caa Ralf Geschke
241
242
def write_config():
243
    if graph_type not in GRAPH_TYPES.keys():
244 58b1c1ec Ralf Geschke
        print("Unknown graph type '{0}'".format(graph_type), file=sys.stderr)
245
        exit(1)
246 8dcd1caa Ralf Geschke
    if graph_type == "worker":
247
        write_config_worker()
248
        return
249
    params = GRAPH_TYPES[graph_type]
250
    for item in params:
251 58b1c1ec Ralf Geschke
        print("graph_title {0}".format(item["title"]))
252 5a45d497 Lars Kruse
        print("graph_category htc")
253 8dcd1caa Ralf Geschke
        if "info" in item:
254 58b1c1ec Ralf Geschke
            print("graph_info {0}".format(item["info"]))
255 8dcd1caa Ralf Geschke
        if "scale" in item:
256 58b1c1ec Ralf Geschke
            print("graph_scale {0}".format(item["scale"]))
257 8dcd1caa Ralf Geschke
        if "args" in item:
258 58b1c1ec Ralf Geschke
            print("graph_args {0}".format(item["args"]))
259 8dcd1caa Ralf Geschke
        for field in item["fields"]:
260 58b1c1ec Ralf Geschke
            print("{0}.label {1}".format(field, field))
261
            print("{0}.type {1}".format(field, item["type"]))
262 8dcd1caa Ralf Geschke
263
def write_suggest():
264
    for item in GRAPH_TYPES.keys():
265
        print(item)
266
267
def write_data():
268
    data = request_data()
269
270
    if graph_type == "balance":
271 58b1c1ec Ralf Geschke
        print("ETH.value {0}".format(data['data']['balance']))
272 8dcd1caa Ralf Geschke
    elif graph_type == "hashrate":
273 58b1c1ec Ralf Geschke
        print("hashrate.value {0}".format(data["data"]["hashrate"]))
274 8dcd1caa Ralf Geschke
    elif graph_type == "avghashrate":
275 58b1c1ec Ralf Geschke
        print("avg_hashrate.value {0}".format(data["data"]["avgHashrate"]["h1"]))
276 8dcd1caa Ralf Geschke
    elif graph_type == "worker":
277
        write_data_worker(data)
278 58b1c1ec Ralf Geschke
    else:
279
        pass
280 8dcd1caa Ralf Geschke
281
282
if __name__ == "__main__":
283
284
    program = sys.argv[0]
285 58b1c1ec Ralf Geschke
    try:
286
        graph_type, account_address = program.split("_")[1:]
287
    except ValueError:
288
        print("Please configure the plugin as described in the configuration section.")
289
        exit(1)
290
291
    GRAPH_TYPES = define_graph_types()
292 e8ff8cf4 Ralf Geschke
    if len(sys.argv) > 1 and sys.argv[1] == "config":
293 8dcd1caa Ralf Geschke
        write_config()
294 58b1c1ec Ralf Geschke
    elif len(sys.argv) > 1 and sys.argv[1] == "suggest":
295 8dcd1caa Ralf Geschke
        write_suggest()
296
    else:
297
        write_data()