Projet

Général

Profil

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

root / plugins / currency / nanopool / nanopool_ @ 17f78427

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

1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
# vim: set fileencoding=utf-8
4

    
5
"""
6
=head1 NAME
7

    
8
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

    
33
=head1 VERSION
34
1.0.1
35

    
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
=head1 MAGIC MARKERS
55

    
56
#%# family=contrib
57
#%# capabilities=suggest
58

    
59
=cut
60
"""
61

    
62
from __future__ import print_function
63

    
64
import os
65
import sys
66
import json
67

    
68
try:
69
    # Python 3
70
    from urllib.request import Request
71
    from urllib.request import urlopen
72
    from urllib.request import URLError
73
except:
74
    # Python 2
75
    from urllib2 import Request
76
    from urllib2 import urlopen
77
    from urllib2 import URLError
78

    
79

    
80

    
81
def define_graph_types():
82
    graph_types = {
83
        "balance" : [
84
            {
85
                "title" : "Balance of {0}".format(account_address),
86
                "type" : "GAUGE",
87
                "args" : "--base 1000 -l 0",
88
                "fields" : ["ETH"],
89
                "scale": "no",
90
                "info": "Balance in ETH"
91
            }
92
        ],
93
        "hashrate" : [
94
            {
95
                "title" : "Hashrate of {0}".format(account_address),
96
                "type" : "GAUGE",
97
                "args" : "--base 1000 -l 0",
98
                "fields" : ["hashrate"],
99
                "info": "Current Calculated Hashrate in Mh/s"
100
            }
101
        ],
102
        "avghashrate" : [
103
            {
104
                "title" : "Average Hashrate of {0}".format(account_address),
105
                "type" : "GAUGE",
106
                "args" : "--base 1000 -l 0",
107
                "fields" : ["avg_hashrate"],
108
                "info": "Average Hashrate of last hour in Mh/s"
109

    
110
            }
111
        ],
112
        "worker" : [
113
            {
114
                "title" : "Worker"
115
            }
116
        ]
117
    }
118
    return graph_types
119

    
120

    
121
def request_data():
122

    
123
    url = "https://api.nanopool.org/v1/eth/user/{0}".format(account_address)
124

    
125
    req = Request(url)
126
    # this fake is necessary to get values, otherwise the request ends in a 403 error
127
    req.add_header('User-Agent', 'Nozilla/5.0')
128
    try:
129
        txt = urlopen(req).read()
130
    except URLError as err:
131
        print("API request error: {0}". format(err), file=sys.stderr)
132
        exit(1)
133
    except:
134
        print("Unhandled error:", sys.exc_info()[0])
135
        exit(1)
136
    try:
137
        result = json.loads(txt.decode("utf-8"))
138
    except ValueError as err:
139
        print("Could not decode JSON error: {0}". format(err), file=sys.stderr)
140
        exit(1)
141
    return result
142

    
143
def write_config_worker():
144
    data = request_data()
145
    worker_data = sorted(data["data"]["workers"], key=lambda element: element["id"])
146

    
147
    print("multigraph worker_hashrate_{0}".format(account_address))
148
    print("graph_title Hashrate in Mh/s per worker ({0})".format(account_address))
149
    print("graph_args --base 1000 -l 0")
150
    print("graph_vlabel Mh/s")
151
    print("graph_category htc")
152
    print("graph_scale no")
153

    
154
    for val in worker_data:
155
        worker_name = "_".join(val["id"].split())
156
        print("worker_{0}_hashrate.label {1}".format(worker_name, val["id"]))
157
        print("worker_{0}_hashrate.type GAUGE".format(worker_name))
158
        print("worker_{0}_hashrate.info Hashrate of worker '{1}'".format(worker_name, val["id"]))
159
        print("worker_{0}_hashrate.min 0".format(worker_name))
160
        print("worker_{0}_hashrate.draw LINE1".format(worker_name))
161

    
162
    for val in worker_data:
163
        print("")
164
        worker_name = "_".join(val["id"].split())
165
        print("multigraph worker_hashrate_{0}.worker_{1}".format(account_address, worker_name))
166
        print("graph_title Hashrate in Mh/s of worker {0}".format(worker_name))
167
        print("graph_args --base 1000 -l 0")
168
        print("graph_vlabel Mh/s")
169
        print("graph_category htc")
170
        print("graph_scale no")
171
        print("whashrate.label hashrate")
172
        print("whashrate.type GAUGE")
173
        print("whashrate.info Hashrate of worker {0}".format(val["id"]))
174
        print("whashrate.min 0")
175
        print("whashrate.draw LINE1")
176

    
177
    print("")
178
    print("multigraph worker_shares_{0}".format(account_address))
179
    print("graph_title Number of accepted shares ({0})".format(account_address))
180
    print("graph_args --base 1000 -l 0")
181
    print("graph_vlabel Shares per ${graph_period}")
182
    print("graph_category htc")
183
    print("graph_scale no")
184
    print("graph_period minute")
185

    
186
    for val in worker_data:
187
        worker_name = "_".join(val["id"].split())
188
        print("worker_{0}_shares.label {1} ".format(worker_name, val["id"]))
189
        print("worker_{0}_shares.type COUNTER".format(worker_name))
190
        print("worker_{0}_shares.info Accepted shares of worker '{1}'".format(worker_name, val["id"]))
191
        print("worker_{0}_shares.min 0".format(worker_name))
192
        print("worker_{0}_shares.draw LINE1".format(worker_name))
193

    
194
    for val in worker_data:
195
        worker_name = "_".join(val["id"].split())
196
        print("")
197
        print("multigraph worker_shares_{0}.worker_{1}".format(account_address, worker_name))
198
        print("graph_title Number of accepted shares {0}".format(worker_name))
199
        print("graph_args --base 1000 -l 0")
200
        print("graph_vlabel Shares per ${graph_period}")
201
        print("graph_category htc")
202
        print("graph_scale no")
203
        print("graph_period minute")
204
        print("wshares.label shares")
205
        print("wshares.type COUNTER")
206
        print("wshares.info Accepted shares of worker '{0}'".format(val["id"]))
207
        print("wshares.min 0")
208
        print("wshares.draw LINE1")
209

    
210

    
211
def write_data_worker(data):
212
    worker_data = sorted(data["data"]["workers"], key=lambda element: element["id"])
213

    
214
    print("multigraph worker_hashrate_{0}".format(account_address))
215

    
216
    for val in worker_data:
217
        worker_name = "_".join(val["id"].split())
218
        print("worker_{0}_hashrate.value {1}".format(worker_name, val["hashrate"]))
219

    
220
    for val in worker_data:
221
        print("")
222
        worker_name = "_".join(val["id"].split())
223
        print("multigraph worker_hashrate_{0}.worker_{1}".format(account_address, worker_name))
224
        print("whashrate.value {0}".format(val["hashrate"]))
225

    
226
    print("")
227
    print("multigraph worker_shares_{0}".format(account_address))
228
    for val in worker_data:
229
        worker_name = "_".join(val["id"].split())
230
        print("worker_{0}_shares.value {1}".format(worker_name, val["rating"]))
231

    
232
    for val in worker_data:
233
        worker_name = "_".join(val["id"].split())
234
        print("")
235
        print("multigraph worker_shares_{0}.worker_{1}".format(account_address, worker_name))
236
        print("wshares.value {0} ".format(val["rating"]))
237

    
238

    
239

    
240
def write_config():
241
    if graph_type not in GRAPH_TYPES.keys():
242
        print("Unknown graph type '{0}'".format(graph_type), file=sys.stderr)
243
        exit(1)
244
    if graph_type == "worker":
245
        write_config_worker()
246
        return
247
    params = GRAPH_TYPES[graph_type]
248
    for item in params:
249
        print("graph_title {0}".format(item["title"]))
250
        print("graph_category htc")
251
        if "info" in item:
252
            print("graph_info {0}".format(item["info"]))
253
        if "scale" in item:
254
            print("graph_scale {0}".format(item["scale"]))
255
        if "args" in item:
256
            print("graph_args {0}".format(item["args"]))
257
        for field in item["fields"]:
258
            print("{0}.label {1}".format(field, field))
259
            print("{0}.type {1}".format(field, item["type"]))
260

    
261
def write_suggest():
262
    for item in GRAPH_TYPES.keys():
263
        print(item)
264

    
265
def write_data():
266
    data = request_data()
267

    
268
    if graph_type == "balance":
269
        print("ETH.value {0}".format(data['data']['balance']))
270
    elif graph_type == "hashrate":
271
        print("hashrate.value {0}".format(data["data"]["hashrate"]))
272
    elif graph_type == "avghashrate":
273
        print("avg_hashrate.value {0}".format(data["data"]["avgHashrate"]["h1"]))
274
    elif graph_type == "worker":
275
        write_data_worker(data)
276
    else:
277
        pass
278

    
279

    
280
if __name__ == "__main__":
281

    
282
    program = sys.argv[0]
283
    try:
284
        graph_type, account_address = program.split("_")[1:]
285
    except ValueError:
286
        print("Please configure the plugin as described in the configuration section.")
287
        exit(1)
288

    
289
    GRAPH_TYPES = define_graph_types()
290
    if len(sys.argv) > 1 and sys.argv[1] == "config":
291
        write_config()
292
    elif len(sys.argv) > 1 and sys.argv[1] == "suggest":
293
        write_suggest()
294
    else:
295
        write_data()