1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
#!/usr/bin/python
# vim:set encoding=utf-8:
###############################################################################
# Generate historical graphs from data stored in RRD
#
# Docs used:
# http://oss.oetiker.ch/rrdtool/doc/rrdgraph.en.html
# http://oss.oetiker.ch/rrdtool/doc/rrdgraph_data.en.html
# http://oss.oetiker.ch/rrdtool/doc/rrdgraph_graph.en.html
# http://oss.oetiker.ch/rrdtool/tut/rrdtutorial.en.html#ITime_to_create_some_graphics
###############################################################################
# Copyright:
# © 2015 Sandro Tosi <morph@debian.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The names of its contributors may not be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
###############################################################################
import rrdtool
import os.path
import os
import itertools
history = ['3 months', '6 months',
'1 year', '5 years', '10 years',
]
tags = {
'A': 'actions to perform',
'C': 'checks successfully done',
'D': 'bugs done',
'E': 'errors',
'I': 'no status',
'M': 'mails sent',
'N': 'not a bts/ignored',
'S': 'SMTP errors (sending mails)',
'T': 'total bugs count',
'U': 'unmatched/unconfigured bts',
'X': 'bugs not existing',
}
tags['elapsed_time'] = 'Elapsed time'
overview = ['A', 'C', 'E', 'T', 'U', 'elapsed_time']
colors = dict(zip(overview,
['00CC00', '009900', 'CC0000', '0066CC', 'FF9900', 'CCCC00']
))
max_ov_tag_length = max(len(tags[x]) for x in overview)
basedir = os.path.dirname(os.path.abspath(__file__))
imgdir = os.path.join(basedir, '../htdocs/img')
rrdfile = os.path.join(basedir, 'bts-link.rrd')
for ds in sorted(tags.keys()):
for start in history:
outfile = os.path.join(imgdir, ds + '_' + start.replace(' ', '') + '.png')
rrdtool.graph(outfile,
"--start", "-%s" % start,
"--width", "600",
"--height", "250",
'--title', '%s in the last %s' % (tags[ds], start),
"DEF:%s=%s:%s:LAST" % (ds, rrdfile, ds),
"LINE:%s#0000FF" % ds,
)
outfile = os.path.join(imgdir, 'overview' + '.png' )
rrdtool.graph(outfile,
"--start", "-1 year",
"--width", "600",
"--height", "250",
"--logarithmic",
'--title', 'bts-link last year executions overview',
# graph() expect to receive the directives one-by-one as arguments, but
# since we want to generate them dinamically, we need to force the expansions
# of the list with *
*(["DEF:%s=%s:%s:LAST" % (x, rrdfile, x) for x in overview]
+
# we can define alle the DEF at once, but LINE and GPRINT for each
# datasource need to be one next to each other
# since we generate a list of tuples, we unpack them using chain() which
# returns a generator, so we list() it
# we pad the Current string taking the max length of a tag in the overview
# and then removing the current string length
list(itertools.chain.from_iterable(
('LINE:%s#%s:%s' % (x, colors[x], tags[x]),
'GPRINT:%s:LAST:%sCurrent\:%%8.2lf %%s' % (x, ' '*(max_ov_tag_length - len(tags[x]))), 'COMMENT:\\n') for x in overview
))
)
)
|