logs.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #!/usr/bin/python
  2. # (c) 2008 Thomas Viehmann
  3. # Free software licensed under the GPL version 2 or later
  4. from __future__ import print_function
  5. import os
  6. import re
  7. import datetime
  8. import sys
  9. import tempfile
  10. ITEMS_TO_KEEP = 20
  11. CACHE_FILE = '/srv/ftp-master.debian.org/misc/dinstall_time_cache'
  12. GRAPH_DIR = '/srv/ftp.debian.org/web/stat'
  13. LINE = re.compile(r'(?:|.*/)dinstall_(\d{4})\.(\d{2})\.(\d{2})-(\d{2}):(\d{2}):(\d{2})\.log(?:\.bz2)?:' +
  14. r'Archive maintenance timestamp \(([^\)]*)\): (\d{2}):(\d{2}):(\d{2})$')
  15. UNSAFE = re.compile(r'[^a-zA-Z/\._:0-9\- ]')
  16. graphs = {"dinstall1": {"keystolist": ["pg_dump1", "i18n 1", "accepted", "dominate", "generate-filelist", "apt-ftparchive",
  17. "pdiff", "release files", "w-b", "i18n 2", "apt-ftparchive cleanup"],
  18. "showothers": True},
  19. "dinstall2": {"keystolist": ['External Updates', 'p-u-new', 'o-p-u-new', 'cruft', 'import-keyring', 'overrides', 'cleanup', 'scripts', 'mirror hardlinks', 'stats', 'compress', "pkg-file-mapping"],
  20. "showothers": False},
  21. "totals": {"keystolist": ["apt-ftparchive", "apt-ftparchive cleanup"], "showothers": True}}
  22. #'mirror hardlinks', 'apt-ftparchive', 'logremove', 'startup', 'import-keyring', 'release files', 'accepted', 'stats', 'o-p-u-new', 'i18n 2', 'locked part finished', 'i18n 1', 'cruft', 'pdiff', 'init', 'cleanup', , 'p-u-new', 'run-parts', 'compress', 'scripts', 'expire_dumps', 'removed', 'make-suite-file-list', 'pg_dump1', 'pg_dump2', 'overrides', 'reports', 'merkel projectb push', 'buildd', 'apt-ftparchive cleanup', 'w-b'
  23. wantkeys = set()
  24. for tmp in graphs.values():
  25. wantkeys |= set(tmp["keystolist"])
  26. d = {}
  27. kl = []
  28. ks = set()
  29. if os.path.exists(CACHE_FILE):
  30. for l in open(CACHE_FILE):
  31. dt, l = l.split('\t', 1)
  32. l = map(lambda x: (lambda y: (y[0], float(y[1])))(x.split(':', 1)), l.split('\t'))
  33. newk = [x[0] for x in l if x[0] not in ks]
  34. kl += newk
  35. ks |= set(newk)
  36. d[dt] = dict(l)
  37. olddt = None
  38. args = sys.argv[1:]
  39. m = UNSAFE.search(' '.join(args))
  40. if m:
  41. raise Exception("I don't like command line arguments including char '%s'" % m.group(0))
  42. if args:
  43. for l in os.popen('bzgrep -H "^Archive maintenance timestamp" "' + '" "'.join(args) + '"'):
  44. m = LINE.match(l)
  45. if not m:
  46. raise Exception("woops '%s'" % l)
  47. g = map(lambda x: (not x.isdigit() and x) or int(x), m.groups())
  48. dt = datetime.datetime(*g[:6])
  49. if olddt != dt:
  50. oldsecs = 0
  51. olddt = dt
  52. dt2 = datetime.datetime(*(g[:3] + g[-3:]))
  53. secs = (dt2 - dt).seconds
  54. assert secs >= 0 # should add 24*60*60
  55. k = g[6]
  56. d.setdefault(str(dt), {})[k] = (secs - oldsecs) / 60.0
  57. oldsecs = secs
  58. if k not in ks:
  59. ks.add(k)
  60. kl.append(k)
  61. if (wantkeys - ks):
  62. print("warning, requested keys not found in any log: " + ' '.join(wantkeys - ks), file=sys.stderr)
  63. datakeys = d.keys()
  64. datakeys.sort()
  65. f = open(CACHE_FILE + ".tmp", "w")
  66. for dk in datakeys:
  67. print(dk + '\t' + '\t'.join(
  68. ["%s:%s" % (k, str(d[dk][k])) for k in kl if k in d[dk]]), file=f)
  69. f.close()
  70. os.rename(CACHE_FILE + ".tmp", CACHE_FILE)
  71. datakeys = datakeys[-ITEMS_TO_KEEP:]
  72. def dump_file(outfn, keystolist, showothers):
  73. showothers = (showothers and 1) or 0
  74. # careful, outfn is NOT ESCAPED
  75. f = tempfile.NamedTemporaryFile()
  76. otherkeys = ks - set(keystolist)
  77. print('\t'.join(keystolist + showothers * ['other']), file=f)
  78. for k in datakeys:
  79. v = d[k]
  80. others = sum(map(lambda x: v.get(x, 0), otherkeys))
  81. print(k + '\t' + '\t'.join(map(lambda x: str(v.get(x, 0)), keystolist) + showothers * [str(others)]), file=f)
  82. f.flush()
  83. n = f.name
  84. p = os.popen("R --vanilla --slave > /dev/null", "w")
  85. p.write("""
  86. d = read.table("%(datafile)s", sep = "\t")
  87. #d[["ts"]] <- as.POSIXct(d[["timestamp"]])
  88. k = setdiff(names(d),c("ts","timestamp"))
  89. #palette(rainbow(max(length(k),2)))
  90. palette(c("midnightblue", "gold", "turquoise", "plum4", "palegreen1", "OrangeRed", "green4", "blue",
  91. "magenta", "darkgoldenrod3", "tomato4", "violetred2","thistle4", "steelblue2", "springgreen4", "salmon","gray"))
  92. #plot(d[["runtime"]],d[["compress"]],type="l",col="blue")
  93. #lines(d[["runtime"]],d[["logremove"]],type="l",col="red")
  94. #legend(as.POSIXct("2008-12-05"),9500,"logremove",col="red",lty=1)
  95. bitmap(file = "%(outfile)s", type="png16m",width=16.9,height=11.8)
  96. #plot(d[["ts"]],d[["compress"]],type="l",col="blue")
  97. #lines(d[["ts"]],d[["logremove"]],type="l",col="red")
  98. barplot(t(d[,k]), col=palette(), xlab="date",ylab="time/minutes"
  99. )
  100. par(xpd = TRUE)
  101. legend(xinch(-1.2),par("usr")[4]+yinch(1),legend=k,
  102. ncol=3,fill=1:15) #,xjust=1,yjust=1)
  103. text(xinch(10),par("usr")[4]+yinch(.5),"%(title)s", cex=2)
  104. dev.off()
  105. q()
  106. """ % {'datafile': n, 'outfile': outfn,
  107. 'title': ((not showothers) * "partial ") + "dinstall times"})
  108. p.flush()
  109. assert not p.close()
  110. for afn, params in graphs.items():
  111. dump_file(os.path.join(GRAPH_DIR, afn + '.png'), **params)