graph.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #!/usr/bin/env python
  2. """ Produces a set of graphs of NEW/BYHAND/DEFERRED
  3. @contact: Debian FTPMaster <ftpmaster@debian.org>
  4. @copyright: 2011 Paul Wise <pabs@debian.org>
  5. """
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # (at your option) any later version.
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. from __future__ import print_function
  18. import os
  19. import sys
  20. import colorsys
  21. import rrdtool
  22. import apt_pkg
  23. from daklib import utils
  24. from daklib.dak_exceptions import *
  25. Cnf = None
  26. default_names = ["byhand", "new", "deferred"]
  27. ################################################################################
  28. def usage(exit_code=0):
  29. print("""Usage: dak graph
  30. Graphs the number of packages in queue directories (usually new and byhand).
  31. -h, --help show this help and exit.
  32. -r, --rrd=key Directory where rrd files to be updated are stored
  33. -x, --extra-rrd=key File containing extra options to rrdtool graphing
  34. -i, --images=key Directory where image graphs to be updated are stored
  35. -n, --names=key A comma separated list of rrd files to be scanned
  36. """)
  37. sys.exit(exit_code)
  38. ################################################################################
  39. def graph(*args):
  40. if args[2] == "deferred":
  41. graph_deferred(*args)
  42. else:
  43. graph_normal(*args)
  44. def deferred_colours():
  45. colours = [0] * 16
  46. for i in range(0, 16):
  47. colours[i] = colorsys.hsv_to_rgb(i / 16.0, 1.0, 0.5 + i / 32.0)
  48. colours[i] = ''.join(['%02X' % (c * 255) for c in colours[i]])
  49. return colours
  50. colours = deferred_colours()
  51. def graph_deferred(rrd_dir, image_dir, name, extra_args, graph, title, start, year_lines=False):
  52. image_file = os.path.join(image_dir, "%s-%s.png" % (name, graph))
  53. rrd_file = os.path.join(rrd_dir, "%s.rrd" % name)
  54. rrd_args = [image_file, "--start", start]
  55. rrd_args += ("""
  56. --end
  57. now
  58. --width
  59. 600
  60. --height
  61. 150
  62. --vertical-label
  63. changes
  64. --title
  65. %s changes count for the last %s
  66. --lower-limit
  67. 0
  68. -E
  69. """ % (name.upper(), title)).strip().split("\n")
  70. if year_lines:
  71. rrd_args += ["--x-grid", "MONTH:1:YEAR:1:YEAR:1:31536000:%Y"]
  72. for i in range(0, 16):
  73. rrd_args += ("""
  74. DEF:d%i=%s:day%i:AVERAGE
  75. AREA:d%i#%s:%i-day changes count:STACK
  76. VDEF:ld%i=d%i,LAST
  77. VDEF:mind%i=d%i,MINIMUM
  78. VDEF:maxd%i=d%i,MAXIMUM
  79. VDEF:avgd%i=d%i,AVERAGE
  80. GPRINT:ld%i:cur\\: %%.0lf
  81. GPRINT:mind%i:min\\: %%.0lf
  82. GPRINT:maxd%i:max\\: %%.0lf
  83. GPRINT:avgd%i:avg\\: %%.0lf\\j
  84. """ % ((i, rrd_file, i, i, colours[i]) + (i,) * 13)).strip().split("\n")
  85. rrd_args += extra_args
  86. try:
  87. ret = rrdtool.graph(*rrd_args)
  88. except rrdtool.error as e:
  89. print(('warning: graph: rrdtool error, skipping %s-%s.png: %s' % (name, graph, e)))
  90. def graph_normal(rrd_dir, image_dir, name, extra_args, graph, title, start, year_lines=False):
  91. image_file = os.path.join(image_dir, "%s-%s.png" % (name, graph))
  92. rrd_file = os.path.join(rrd_dir, "%s.rrd" % name)
  93. rrd_args = [image_file, "--start", start]
  94. rrd_args += ("""
  95. --end
  96. now
  97. --width
  98. 600
  99. --height
  100. 150
  101. --vertical-label
  102. packages
  103. --title
  104. %s package count for the last %s
  105. --lower-limit
  106. 0
  107. -E
  108. """ % (name.upper(), title)).strip().split("\n")
  109. if year_lines:
  110. rrd_args += ["--x-grid", "MONTH:1:YEAR:1:YEAR:1:31536000:%Y"]
  111. rrd_args += ("""
  112. DEF:ds1=%s:ds1:AVERAGE
  113. LINE2:ds1#D9382B:changes count
  114. VDEF:lds1=ds1,LAST
  115. VDEF:minds1=ds1,MINIMUM
  116. VDEF:maxds1=ds1,MAXIMUM
  117. VDEF:avgds1=ds1,AVERAGE
  118. GPRINT:lds1:cur\\: %%.0lf
  119. GPRINT:minds1:min\\: %%.0lf
  120. GPRINT:maxds1:max\\: %%.0lf
  121. GPRINT:avgds1:avg\\: %%.0lf\\j
  122. DEF:ds0=%s:ds0:AVERAGE
  123. VDEF:lds0=ds0,LAST
  124. VDEF:minds0=ds0,MINIMUM
  125. VDEF:maxds0=ds0,MAXIMUM
  126. VDEF:avgds0=ds0,AVERAGE
  127. LINE2:ds0#3069DA:src pkg count
  128. GPRINT:lds0:cur\\: %%.0lf
  129. GPRINT:minds0:min\\: %%.0lf
  130. GPRINT:maxds0:max\\: %%.0lf
  131. GPRINT:avgds0:avg\\: %%.0lf\\j
  132. """ % (rrd_file, rrd_file)).strip().split("\n")
  133. rrd_args += extra_args
  134. try:
  135. ret = rrdtool.graph(*rrd_args)
  136. except rrdtool.error as e:
  137. print(('warning: graph: rrdtool error, skipping %s-%s.png: %s' % (name, graph, e)))
  138. ################################################################################
  139. def main():
  140. global Cnf
  141. Cnf = utils.get_conf()
  142. Arguments = [('h', "help", "Graph::Options::Help"),
  143. ('x', "extra-rrd", "Graph::Options::Extra-Rrd", "HasArg"),
  144. ('r', "rrd", "Graph::Options::Rrd", "HasArg"),
  145. ('i', "images", "Graph::Options::Images", "HasArg"),
  146. ('n', "names", "Graph::Options::Names", "HasArg")]
  147. for i in ["help"]:
  148. key = "Graph::Options::%s" % i
  149. if key not in Cnf:
  150. Cnf[key] = ""
  151. apt_pkg.parse_commandline(Cnf, Arguments, sys.argv)
  152. Options = Cnf.subtree("Graph::Options")
  153. if Options["Help"]:
  154. usage()
  155. names = []
  156. if "Graph::Options::Names" in Cnf:
  157. for i in Cnf["Graph::Options::Names"].split(","):
  158. names.append(i)
  159. elif "Graph::Names" in Cnf:
  160. names = Cnf.value_list("Graph::Names")
  161. else:
  162. names = default_names
  163. extra_rrdtool_args = []
  164. if "Graph::Options::Extra-Rrd" in Cnf:
  165. for i in Cnf["Graph::Options::Extra-Rrd"].split(","):
  166. f = open(i)
  167. extra_rrdtool_args.extend(f.read().strip().split("\n"))
  168. f.close()
  169. elif "Graph::Extra-Rrd" in Cnf:
  170. for i in Cnf.value_list("Graph::Extra-Rrd"):
  171. f = open(i)
  172. extra_rrdtool_args.extend(f.read().strip().split("\n"))
  173. f.close()
  174. if "Graph::Options::Rrd" in Cnf:
  175. rrd_dir = Cnf["Graph::Options::Rrd"]
  176. elif "Dir::Rrd" in Cnf:
  177. rrd_dir = Cnf["Dir::Rrd"]
  178. else:
  179. print("No directory to read RRD files from\n", file=sys.stderr)
  180. sys.exit(1)
  181. if "Graph::Options::Images" in Cnf:
  182. image_dir = Cnf["Graph::Options::Images"]
  183. else:
  184. print("No directory to write graph images to\n", file=sys.stderr)
  185. sys.exit(1)
  186. for name in names:
  187. stdargs = [rrd_dir, image_dir, name, extra_rrdtool_args]
  188. graph(*(stdargs + ['day', 'day', 'now-1d']))
  189. graph(*(stdargs + ['week', 'week', 'now-1w']))
  190. graph(*(stdargs + ['month', 'month', 'now-1m']))
  191. graph(*(stdargs + ['year', 'year', 'now-1y']))
  192. graph(*(stdargs + ['5years', '5 years', 'now-5y', True]))
  193. graph(*(stdargs + ['10years', '10 years', 'now-10y', True]))
  194. ################################################################################
  195. if __name__ == '__main__':
  196. main()