PageRenderTime 50ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/lcgcmt/pyLCG/python/lcg/aa/checkLogFiles.py

https://github.com/mana-fwk/lcgwaf
Python | 458 lines | 365 code | 70 blank | 23 comment | 108 complexity | 2f9babb8f77dfe6f5f24f0d1c4cbfd6a MD5 | raw file
  1. #!/usr/bin/env python
  2. import os, sys, re, time, socket
  3. import logging, logging.config
  4. spiScriptDir = os.path.abspath( os.path.dirname( sys.argv[0] ) )
  5. #logging.config.fileConfig(os.path.join(spiScriptDir,"loggers"))
  6. log=logging.getLogger("nightlies.console")
  7. if len(log.handlers) == 0:
  8. handler = logging.StreamHandler()
  9. handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
  10. log.addHandler(handler)
  11. log.setLevel(logging.INFO)
  12. class LogChecker(object) :
  13. # --------------------------------------------------------------------------------
  14. def __init__(self,html,file,platform) :
  15. self.htmlOut = None
  16. self.sumLog = None
  17. self.logDir = os.getcwd()+"/www"
  18. if not os.path.exists(os.getcwd()+"/www"):
  19. os.makedirs(os.getcwd()+"/www")
  20. self.errFiles = []
  21. self.htmlOut = html
  22. self.files=file
  23. #self.files.append(file)
  24. self.verbose = 1
  25. self.slot = None
  26. self.plat=platform
  27. return
  28. # --------------------------------------------------------------------------------
  29. def setHtml(self, html) :
  30. self.htmlOut = html
  31. self.verbose = 0
  32. return
  33. # --------------------------------------------------------------------------------
  34. def setSlot(self, slot) :
  35. self.slot = slot
  36. return
  37. # --------------------------------------------------------------------------------
  38. def checkLog(self,file):
  39. pkgName = ""
  40. import re
  41. # on windows we don't start with a "/"
  42. prjAfs = re.compile(".*../../../../LCG_Builders"+"/.*/([A-Za-z].*)/([A-Za-z].*)/logs/(.*)\.log")
  43. prjAfsMatch = prjAfs.match( os.path.abspath(file) )
  44. # set defaults for "any" logfile
  45. pkgName = file
  46. #plat = "unknown"
  47. if prjAfsMatch : # it matches the path, so we can get more info
  48. pkgName = prjAfsMatch.group(2)
  49. plat = prjAfsMatch.group(3)
  50. # ignore logfiles from qmtest
  51. if pkgName.find("-qmtest") != -1 :
  52. nWarn, nErr = self.handleQMTestFile(pkgName)
  53. return nWarn, nErr, 0
  54. htmlFileName = file.split("/")[9]+"-log.html"
  55. if self.verbose > 0 :
  56. log.info("================================================================================")
  57. log.info("checking " + pkgName + " on " + self.plat)
  58. log.info(" file " + os.path.abspath(file))
  59. log.info("================================================================================")
  60. if (self.htmlOut and self.sumLog ) :
  61. self.sumLog.write( '<image src="http://cern.ch/pfeiffer/aaLibrarian/colline.gif" width="90%" height="3"></image>\n')
  62. self.sumLog.write( '<h3>Checking <a href="'+htmlFileName+'"> log file for ' + pkgName + ' on ' + self.plat + '</a></h3>\n' )
  63. self.sumLog.write( '\n' )
  64. self.sumLog.write( "<p>\n")
  65. logFile = open(file, "r")
  66. lines = logFile.readlines()
  67. logFile.close()
  68. shortLog = False
  69. if ( (len(lines) < 200) and
  70. (pkgName.find("LCGCMT") == -1) ):
  71. if (self.htmlOut and self.sumLog ) :
  72. self.sumLog.write( '<font color="#ff0000"><b>Warning:</b> suspiciously short log file!</font>\n')
  73. shortLog = True
  74. reCMTErr = []
  75. reCMTErr.append( re.compile("Cannot read the requirements file") )
  76. matchMkErr1 = re.compile('.*make.*\WError\s*1.*')
  77. matchError = re.compile('.*\Werror[: ].*', re.I)
  78. matchError1 = re.compile('^error .*', re.I)
  79. matchWarn = re.compile('.*warning[: ].*', re.I)
  80. matchFailB = re.compile('\.\.\.failed .*', re.I) # boost's "...failed" messages
  81. matchDiskQ = re.compile('.*isk quota exceeded.*', re.I)
  82. matchConf = re.compile('Configuring Project .*', )
  83. matchBuild = re.compile('Building Project .*', )
  84. matchTest = re.compile('Executing all tests .*', )
  85. matchInst = re.compile('Installing Project .*', )
  86. nErr = 0
  87. nMkErr = 0
  88. nWarn = 0
  89. nCMTErr = 0
  90. errorList = {}
  91. mkErrList = [] # make is "build" :-)
  92. warnList = {}
  93. actualStep = "init"
  94. index = -1
  95. for line in lines:
  96. index += 1
  97. mMk = matchConf.match(line)
  98. if mMk : actualStep = "conf"
  99. mMk = matchBuild.match(line)
  100. if mMk : actualStep = "build"
  101. mMk = matchTest.match(line)
  102. if mMk : actualStep = "test"
  103. mMk = matchInst.match(line)
  104. if mMk : actualStep = "inst"
  105. # count failed make's (by package)
  106. mMkE1 = matchMkErr1.match(line)
  107. if mMkE1 :
  108. nMkErr += 1
  109. mkErrList.append(index)
  110. mErr = matchError.match(line)
  111. mErr1 = matchError1.match(line)
  112. mDskQ = matchDiskQ.match(line)
  113. if mErr or mErr1 or mDskQ : # treat errors and disk quota exceeded basically the same way ...
  114. if mErr or mErr1: # ... but check the following only for real error messages
  115. # ignore compiler flag (this needs more sophistication to not skip real errors)
  116. if line.find("-Wno-error") != -1 : continue
  117. nErr += 1
  118. if actualStep not in errorList.keys() :
  119. errorList[actualStep] = []
  120. errorList[actualStep].append(index)
  121. for reCMT in reCMTErr:
  122. matchCMTErr = reCMT.match(line)
  123. if matchCMTErr :
  124. nCMTErr += 1
  125. nErr += 1
  126. if actualStep not in errorList.keys() :
  127. errorList[actualStep] = []
  128. errorList[actualStep].append(index)
  129. mWarn = matchWarn.match(line)
  130. if mWarn :
  131. # ignore genreflex warnings about not supported references
  132. ignoreWarnings = [
  133. "genreflex: WARNING: References are not supported as data members",
  134. "include/boost-1_34_1/boost/date_time/time_facet.hpp:202: warning: unused parameter 'a_ref'",
  135. "include/boost-1_34_1/boost/date_time/time.hpp:81: warning: unused parameter 'as_offset'",
  136. "include/boost-1_34_1/boost/date_time/time.hpp:88: warning: unused parameter 'as_offset'",
  137. "WARNING >> You should provide a target for",
  138. ]
  139. nWarn += 1
  140. if actualStep not in warnList.keys() :
  141. warnList[actualStep] = []
  142. warnList[actualStep].append(index)
  143. for x in ignoreWarnings:
  144. if line.find(x) != -1:
  145. nWarn -= 1
  146. if actualStep in warnList.keys() and index in warnList[actualStep]:
  147. warnList[actualStep].remove(index)
  148. # ---------- end analysis of logfile, now prepare output
  149. summaryFileName = file.split("/")[9]+"-log.summary"
  150. sumFil = open( os.path.join(self.logDir, summaryFileName), 'w')
  151. now = time.time()
  152. sumFil.write(str(now) + " (" + time.ctime(now) + ") " + " " + pkgName + " " + self.plat + "\n")
  153. if shortLog :
  154. sumFil.write(str(nWarn) + ", " + str(nErr+1) + ", " + str(nMkErr) + ", " + str(nCMTErr) + "\n")
  155. else:
  156. sumFil.write(str(nWarn) + ", " + str(nErr) + ", " + str(nMkErr) + ", " + str(nCMTErr) + "\n")
  157. sumFil.close()
  158. # print "Summary written to :", summaryFileName
  159. if self.htmlOut :
  160. errLines = []
  161. for key, value in errorList.items():
  162. for i in value:
  163. if i not in errLines:
  164. errLines.append(int(i))
  165. warnLines = []
  166. groupedWarnings = []
  167. for key, value in warnList.items():
  168. for i in value:
  169. if i not in warnLines:
  170. warnLines.append(int(i))
  171. if int(i)-1 in warnLines: groupedWarnings.append(int(i))
  172. htmlFile = open(self.logDir + "/" + htmlFileName, 'w')
  173. htmlFile.write("<html>\n<head><title>LogCheck for package " + pkgName + " </title></head>\n<body>\n")
  174. htmlFile.write("<h3>LogCheck for package " + pkgName + " on " + socket.gethostname() +"</h3>\n")
  175. htmlFile.write('<p>\n')
  176. htmlFile.write('Warnings : '+ str(nWarn) +' <br /> ')
  177. htmlFile.write('Errors : '+str(nErr) +' <br /> ')
  178. htmlFile.write('Make Errors: '+str(nMkErr) +' <br /> ')
  179. htmlFile.write('CMT Errors: '+str(nCMTErr)+' <br /> ')
  180. htmlFile.write('</p>\n')
  181. # if there were make errors, list a summary of them
  182. if len(mkErrList) > 0 :
  183. htmlFile.write("<h3>Summary of make errors:</h3>\n")
  184. for index in mkErrList:
  185. if (self.htmlOut and self.sumLog ) :
  186. # htmlFile.write( '<a name="' + pkgName + '"></a>\n')
  187. htmlFile.write( "<hr />\n")
  188. htmlFile.write( '<a href="'+htmlFileName+'#line_' + str(index) + '">\n' )
  189. try:
  190. for delta in range(-2,2) :
  191. if (self.htmlOut and self.sumLog ) :
  192. htmlFile.write( str(index+delta) + " : " + lines[index+delta])
  193. # print " ", index+delta, ":", lines[index+delta],
  194. except IndexError:
  195. pass
  196. if (self.htmlOut and self.sumLog ) :
  197. htmlFile.write( '</a>\n')
  198. htmlFile.write("<hr />\n")
  199. elif len(warnList.keys()) > 0:
  200. htmlFile.write("<h3>Summary of warnings:</h3>\n")
  201. for index in warnList.values()[0]:
  202. if index not in groupedWarnings:
  203. if (self.htmlOut and self.sumLog):
  204. htmlFile.write( "<hr />\n")
  205. htmlFile.write( '<a href="'+htmlFileName+'#line_' + str(index) + '">\n' )
  206. try:
  207. for delta in range(-2,2) :
  208. if (self.htmlOut and self.sumLog ) :
  209. htmlFile.write( str(index+delta) + " : " + lines[index+delta])
  210. # print " ", index+delta, ":", lines[index+delta],
  211. except IndexError:
  212. pass
  213. if (self.htmlOut and self.sumLog ) :
  214. htmlFile.write( '</a>\n')
  215. htmlFile.write("<hr />\n")
  216. htmlFile.write('<pre>\n')
  217. for index in range(len(lines)):
  218. if index in errLines :
  219. htmlFile.write('</pre>\n')
  220. htmlFile.write('<a name="line_' + str(index) + '">')
  221. htmlFile.write('<font color="red" size+=3><b>\n')
  222. htmlFile.write(lines[index])
  223. htmlFile.write('</b></font>')
  224. htmlFile.write('</a> \n')
  225. htmlFile.write('<pre>\n')
  226. elif index in warnLines :
  227. htmlFile.write('</pre>\n')
  228. htmlFile.write('<a name="line_' + str(index) + '">')
  229. htmlFile.write('<font color="blue" size+=3><b>\n')
  230. htmlFile.write(lines[index])
  231. htmlFile.write('</b></font>')
  232. htmlFile.write('</a> \n')
  233. htmlFile.write('<pre>\n')
  234. else:
  235. htmlFile.write(lines[index])
  236. htmlFile.write("</pre>\n</body>\n</html>")
  237. htmlFile.close()
  238. errLimit = False
  239. if len(errorList.items()) > 500 :
  240. if (self.htmlOut and self.sumLog ) :
  241. self.sumLog.write( '<font color="#ff0000"><b>Caution:</b> Too many errors found ("+len(errorList.items())+"), further printout suppressed !!</font>\n')
  242. errLimit = True
  243. if self.verbose > 10 and not errLimit :
  244. for key, value in errorList.items() :
  245. log.debug("++++++++++" + key)
  246. for index in value:
  247. if (self.htmlOut and self.sumLog ) :
  248. self.sumLog.write( '<a name="' + pkgName + '"></a>\n')
  249. self.sumLog.write( "<hr />\n")
  250. self.sumLog.write( '<a href="'+htmlFileName+'#line_' + str(index) + '">\n' )
  251. try:
  252. log.debug("------------------------------------------")
  253. for delta in range(-2,2) :
  254. if (self.htmlOut and self.sumLog ) :
  255. self.sumLog.write( str(index+delta) + " : " + lines[index+delta])
  256. log.debug(" " + str(index+delta) + ":" + lines[index+delta])
  257. except IndexError:
  258. pass
  259. if (self.htmlOut and self.sumLog ) :
  260. self.sumLog.write( '</a>\n')
  261. msg = "In total: "
  262. if (nErr == 0) :
  263. msg += "no errors, "
  264. else:
  265. if (nMkErr > 0) :
  266. msg += str(nMkErr) + " make errors, "
  267. msg += str(nErr) + " errors, "
  268. self.errFiles.append(htmlFileName)
  269. if ( nWarn == 0):
  270. msg += "no warnings"
  271. else:
  272. msg += str(nWarn) + " warnings"
  273. msg += " found in " + str(len(lines)) + " lines."
  274. if self.verbose > 0 :
  275. log.debug(msg)
  276. if (self.htmlOut and self.sumLog ) :
  277. self.sumLog.write( msg + "\n")
  278. self.sumLog.write( '</p>\n' )
  279. if prjAfsMatch :
  280. self.handleQmtestFile(file)
  281. return nMkErr, nErr, nWarn
  282. # --------------------------------------------------------------------------------
  283. def handleQmtestFile(self, file):
  284. log.debug("ignoring qmtest file:" + file)
  285. return 0,0
  286. # --------------------------------------------------------------------------------
  287. def checkFiles(self, fileList=[]) :
  288. import socket
  289. hostName = socket.gethostname().lower()
  290. import time
  291. date = time.ctime()
  292. if self.htmlOut and not self.sumLog :
  293. summaryFileName = self.files.split("/")[9]+"-log.summary"
  294. self.sumLog = open(summaryFileName,'w')
  295. self.sumLog.write("<html>\n<head><title>Summary of logfiles</title></head>\n<body>\n<pre>\n")
  296. self.sumLog.write('<h2>Check of logfiles</h2>\n')
  297. self.sumLog.write( "<p>\n")
  298. self.sumLog.write( "Checking done on " + hostName + " at " + date )
  299. self.sumLog.write( "</p>\n")
  300. self.sumLog.write( "<p>\n")
  301. self.sumLog.write('<a href="#summary">Summary of checks</a>\n')
  302. self.sumLog.write( "</p>\n")
  303. totErr = 0
  304. totMkErr = 0
  305. totWarn = 0
  306. errFiles = []
  307. nFiles = 0
  308. nFilErr = 0
  309. nFilWarn = 0
  310. if self.files :
  311. try:
  312. nMkErr, nErr, nWarn = self.checkLog(self.files)
  313. except IOError:
  314. sys.exit(-1)
  315. nFiles += 1
  316. totMkErr += nMkErr
  317. totErr += nErr
  318. totWarn += nWarn
  319. if nErr > 0 : nFilErr += 1
  320. if nWarn > 0 : nFilWarn += 1
  321. if self.verbose > 0 :
  322. print "\n================================================================================\n"
  323. if nFiles > 0 :
  324. print "Checked a total of ", nFiles, "log files."
  325. print "A total of ", totMkErr," make errors in ", nFilErr, 'files.'
  326. print "A total of ", totErr , "errors in ", nFilErr, 'files.'
  327. print "A total of ", totWarn , "warnings in ", nFilWarn, 'files.'
  328. print "Files with errors: "
  329. for f in self.errFiles:
  330. print "\t", f
  331. print
  332. else:
  333. print "No files found to check"
  334. print ""
  335. if self.htmlOut and self.sumLog :
  336. self.sumLog.write('<a name="summary"></a><hr />\n')
  337. self.sumLog.write("Checked a total of " + str(nFiles) + " log files.\n")
  338. self.sumLog.write("A total of " + str(totErr) + " errors in " + str(nFilErr) + ' files.\n')
  339. self.sumLog.write("A total of " + str(totWarn) + " warnings in " + str(nFilWarn) + ' files.\n')
  340. self.sumLog.write("Files with errors: \n")
  341. self.sumLog.write("<table>\n")
  342. for f in self.errFiles:
  343. self.sumLog.write('<tr><td><a href="#' + f + '">' + f + '</a> </td></tr>\n')
  344. self.sumLog.write("</table>\n")
  345. self.sumLog.write("\n")
  346. self.sumLog.write("</pre>\n</body>\n</html>")
  347. self.sumLog.close()
  348. return
  349. # --------------------------------------------------------------------------------
  350. def usage():
  351. print sys.argv[0],"[--hmtl] <logFile> [<logFile> ...]"
  352. return
  353. # ================================================================================
  354. if __name__ == "__main__" :
  355. import getopt
  356. options = sys.argv[1:]
  357. try:
  358. opts, args = getopt.getopt(options, 'h',
  359. ['help','html','verbose=','topDir='])
  360. except getopt.GetoptError:
  361. usage()
  362. sys.exit(-2)
  363. html = None
  364. verb = 0
  365. slot = None
  366. top = None
  367. for o, a in opts:
  368. if o in ('-h', '--help'):
  369. usage()
  370. sys.exit()
  371. if o in ('--html',):
  372. html = True
  373. if o in ('--verbose',):
  374. verb = a
  375. #if o in ('--slot',):
  376. # slot = a
  377. if o in ('--topDir',):
  378. top = a
  379. checker = LogChecker()
  380. if html : checker.setHtml(html)
  381. if top : checker.topDir = top
  382. #checker.setSlot(slot)
  383. checker.verbose = verb
  384. checker.checkFiles(args)