|
1 from rrdweb import rrd |
|
2 |
|
3 import operator |
|
4 |
|
5 def host_def (idx, name, dir, ds_in, ds_out, cf) : |
|
6 """ |
|
7 VDEFs for given host, giving its avg/max values: |
|
8 |
|
9 DEF:in/out_{idx} |
|
10 CDEFtraf_{idx} |
|
11 VDEF:avg/max_{idx} |
|
12 PRINT:{idx} avg/max {value} |
|
13 """ |
|
14 |
|
15 params = dict( |
|
16 dir=dir, ds_in=ds_in, ds_out=ds_out, cf=cf, |
|
17 idx=idx, rrd='%s/%s.rrd' % (dir, name) |
|
18 ) |
|
19 |
|
20 return [ |
|
21 # in/out bandwidth in bytes/s |
|
22 'DEF:in_%(idx)d=%(rrd)s:%(ds_in)s:%(cf)s' % params, |
|
23 'DEF:out_%(idx)d=%(rrd)s:%(ds_out)s:%(cf)s' % params, |
|
24 |
|
25 # total traffic in bits/s |
|
26 'CDEF:traf_%(idx)d=in_%(idx)d,out_%(idx)d,+,8,*' % params, |
|
27 |
|
28 # average + maximum values |
|
29 'VDEF:avg_%(idx)d=traf_%(idx)d,AVERAGE' % params, |
|
30 'VDEF:max_%(idx)d=traf_%(idx)d,MAXIMUM' % params, |
|
31 |
|
32 # output |
|
33 'PRINT:avg_%(idx)d:%(idx)d avg %%lf' % params, |
|
34 'PRINT:max_%(idx)d:%(idx)d max %%lf' % params, |
|
35 ] |
|
36 |
|
37 def parse_report (rrds, lines) : |
|
38 """ |
|
39 Parse the report output into a [ (name, avg, max) ] list |
|
40 """ |
|
41 |
|
42 # idx values by type |
|
43 data = { |
|
44 'avg': {}, |
|
45 'max': {}, |
|
46 } |
|
47 |
|
48 # interpret output |
|
49 for line in lines : |
|
50 # parse |
|
51 idx, type, value = line.split() |
|
52 |
|
53 # convert |
|
54 idx = int(idx) |
|
55 value = float(value) |
|
56 |
|
57 # store |
|
58 data[type][idx] = value |
|
59 |
|
60 # build into name : (values) dict |
|
61 return [ |
|
62 ( |
|
63 (name, data['avg'][idx], data['max'][idx]) |
|
64 ) for idx, name in enumerate(rrds) |
|
65 ] |
|
66 |
|
67 def calc_top_hosts (dir, rrds, ds_in, ds_out, period='15m', count=5, cf='AVERAGE') : |
|
68 """ |
|
69 Return the list of top-N rrd's in the given dir, sorted by total in/out bandwidth average over the given period. |
|
70 """ |
|
71 |
|
72 # vdefs for hosts, avg/max_<idx> in bits/s + prints |
|
73 defs = [stmt for idx, name in enumerate(rrds) for stmt in host_def(idx, name, dir, ds_in, ds_out, cf)] |
|
74 |
|
75 # execute |
|
76 _, _, output, _ = rrd.graph(False, *defs, start=('-%s' % period)) |
|
77 |
|
78 # parse |
|
79 data = parse_report(rrds, output) |
|
80 |
|
81 # sort for top-N avg |
|
82 data.sort(key=operator.itemgetter(1)) |
|
83 top_avg = data[:count] |
|
84 |
|
85 # sort for top-N max |
|
86 data.sort(key=operator.itemgetter(2)) |
|
87 top_max = data[:count] |
|
88 |
|
89 # merge hosts (we lose sorting order) |
|
90 return set(host for host, avg, max in top_avg + top_max) |
|
91 |
|
92 |