diff --git a/Tools/PyJobTransforms/python/trfExe.py b/Tools/PyJobTransforms/python/trfExe.py index 45080afca4585173ef7df2fcb680850860e4c582..43a9df2838f6ba133e90c5461976db4a84e2443d 100755 --- a/Tools/PyJobTransforms/python/trfExe.py +++ b/Tools/PyJobTransforms/python/trfExe.py @@ -1078,8 +1078,9 @@ class athenaExecutor(scriptExecutor): ignorePatterns = trfValidation.ignorePatterns(files = athenaExecutor._defaultIgnorePatternFile, extraSearch=igPat) # Now actually scan my logfile - msg.info('Scanning logfile {0} for errors'.format(self._logFileName)) - self._logScan = trfValidation.athenaLogFileReport(logfile = self._logFileName, ignoreList = ignorePatterns) + msg.info('Scanning logfile {0} for errors in substep {1}'.format(self._logFileName, self._substep)) + self._logScan = trfValidation.athenaLogFileReport(logfile=self._logFileName, substepName=self._substep, + ignoreList=ignorePatterns) worstError = self._logScan.worstError() self._dbMonitor = self._logScan.dbMonitor() diff --git a/Tools/PyJobTransforms/python/trfUtils.py b/Tools/PyJobTransforms/python/trfUtils.py index c4bfac7aa464cea3694b9db58bf91f67f8b0f265..9b9f0a5ce2b65815f736a9c480cf30a706d87a67 100644 --- a/Tools/PyJobTransforms/python/trfUtils.py +++ b/Tools/PyJobTransforms/python/trfUtils.py @@ -302,14 +302,19 @@ def shQuoteStrings(strArray = sys.argv): ## @brief Generator to return lines and line count from a file # @param filename: Filename to open and deliver lines from # @param strip: If lines get stripped before being returned (default @c True) +# @param removeTimestamp: Removes timestamp from left.(default @c True) Since strings are removed only from left, +# this option requires explicit removal of substepName. +# @param substepName: Removes substepName from left, if it's value is provided. (default @c None) # @note This is useful so that multiple parts of code can co-operatively take lines from the file -def lineByLine(filename, strip = True, removeTimestamp = True): +def lineByLine(filename, strip=True, removeTimestamp=True, substepName=None): linecounter = 0 f = open(filename, 'r') for line in f: linecounter += 1 + if substepName and isinstance(substepName, str): # Remove substepName only if caller provides that string. + line = line.lstrip(substepName) if removeTimestamp: - line = line.lstrip('0123456789:-, ') # Remove timestamps in both serial and MP mode. + line = line.lstrip('0123456789:-, ') # Remove timestamps in both serial and MP mode. if strip: line = line.strip() yield line, linecounter diff --git a/Tools/PyJobTransforms/python/trfValidation.py b/Tools/PyJobTransforms/python/trfValidation.py index 36131827fa7f805e690ee397f5b0307aef41f62a..06e87ce9e96612e53f2b3bd6f803dad7c8315716 100644 --- a/Tools/PyJobTransforms/python/trfValidation.py +++ b/Tools/PyJobTransforms/python/trfValidation.py @@ -213,8 +213,9 @@ class logFileReport(object): class athenaLogFileReport(logFileReport): ## @brief Class constructor # @param logfile Logfile (or list of logfiles) to scan + # @param substepName Name of the substep executor, that has requested this log scan # @param msgLimit The number of messages in each category on which a - def __init__(self, logfile, msgLimit=10, msgDetailLevel=stdLogLevels['ERROR'], ignoreList=None): + def __init__(self, logfile, substepName=None, msgLimit=10, msgDetailLevel=stdLogLevels['ERROR'], ignoreList=None): if ignoreList: self._ignoreList = ignoreList else: @@ -229,6 +230,7 @@ class athenaLogFileReport(logFileReport): self._metaPat = re.compile(r"MetaData:\s+(.*?)\s*=\s*(.*)$") self._metaData = {} + self._substepName = substepName self._msgLimit = msgLimit self.resetReport() @@ -261,7 +263,6 @@ class athenaLogFileReport(logFileReport): self._dbbytes = 0 self._dbtime = 0.0 - def scanLogFile(self, resetReport=False): if resetReport: self.resetReport() @@ -270,7 +271,7 @@ class athenaLogFileReport(logFileReport): msg.debug('Now scanning logfile {0}'.format(log)) # N.B. Use the generator so that lines can be grabbed by subroutines, e.g., core dump svc reporter try: - myGen = trfUtils.lineByLine(log) + myGen = trfUtils.lineByLine(log, substepName=self._substepName) except IOError, e: msg.error('Failed to open transform logfile {0}: {1:s}'.format(log, e)) # Return this as a small report @@ -382,6 +383,7 @@ class athenaLogFileReport(logFileReport): self._dbbytes += int(a.group('bytes')) self._dbtime += float(a.group('time')) + ## Return data volume and time spend to retrieve information from the database def dbMonitor(self): return {'bytes' : self._dbbytes, 'time' : self._dbtime} if self._dbbytes > 0 or self._dbtime > 0 else None diff --git a/Tools/PyJobTransforms/test/test_trfValidation.py b/Tools/PyJobTransforms/test/test_trfValidation.py index 7581d488322ad19965497b2b80dca6bd3332d7b9..76364aad5546f6bc76d8b7adbef82fe3bd1597e2 100755 --- a/Tools/PyJobTransforms/test/test_trfValidation.py +++ b/Tools/PyJobTransforms/test/test_trfValidation.py @@ -178,7 +178,7 @@ class eventCheckTests(unittest.TestCase): 'maxEvents': None, 'evAccEff': 0.99}) self.assertRaises(trfExceptions.TransformValidationException, evmatch.decide) - + def test_inputGlobWithFail(self): evmatch = eventMatch(executor=None) evmatch.configureCheck(override={'inEventDict': {'NTUP_ZEE': 100}, @@ -540,7 +540,8 @@ class athenaLogFileReportTests(unittest.TestCase): self.myFileReport10 = athenaLogFileReport('file10') def tearDown(self): - for f in 'file1', 'file2', 'file3', 'file4', 'file5', 'file6', 'file7', 'file8', 'file9', 'file10': + for f in 'file1', 'file2', 'file3', 'file4', 'file5', 'file6', 'file7', 'file8', 'file9', 'file10',\ + 'logWithSubstepNameSerial', 'logWithSubstepNameMP': try: os.unlink(f) except OSError: @@ -569,6 +570,44 @@ class athenaLogFileReportTests(unittest.TestCase): 'firstError': {'count': 1, 'firstLine': 9, 'message': 'DRAW_TOPSLMUKernel ERROR Incompatible vectors - different length'},}) + def test_logscanErrorWithSubstepNameSerial(self): + testLogERRORwithSubstepNameSerial = ''' +RAWtoALL 22:21:40 ToolSvc.TileROD_Decoder INFO ROD 540007 has unexpected data size +RAWtoALL 22:21:40 ToolSvc.TileROD_Decoder WARNING Frag has unexpected size ignoring 6 words to end of ROD frag +RAWtoALL 22:21:40 ToolSvc.TileROD_Decoder ERROR ROB 540007 ROD 540007 has unexpected data size +RAWtoALL 22:21:40 AlgErrorAuditor ERROR Illegal Return Code: Algorithm ManagedAthenaTileMon reported an \ +ERROR, but returned a StatusCode "SUCCESS"''' + + logFileName = 'logWithSubstepNameSerial' + with open(logFileName, 'w') as logFile: + print >> logFile, testLogERRORwithSubstepNameSerial + + logFileReportSerial = athenaLogFileReport(logfile=logFileName, substepName='RAWtoALL') + expectedError = dict(level='ERROR', nLevel=logging.ERROR, + firstError=dict(count=1, firstLine=4, message='ToolSvc.TileROD_Decoder ERROR ROB 54' + '0007 ROD 540007 has unexpected data size')) + self.assertEqual(logFileReportSerial.worstError(), expectedError) + + def test_logscanErrorWithSubstepNameMP(self): + testLogERRORwithSubstepNameMP = ''' +RAWtoALL 22:21:40 2017-07-13 19:23:38,171 ToolSvc.TileROD_Decoder INFO ROD 540007 has unexpected data size +RAWtoALL 22:21:40 2017-07-13 19:23:38,171 ToolSvc.TileROD_Decoder WARNING Frag 0x40f has unexpected size ignoring \ +6 words till the end of ROD frag +RAWtoALL 22:21:40 2017-07-13 19:23:38,171 ToolSvc.TileROD_Decoder ERROR ROB 540007 ROD 540007 has unexpected \ +data size +RAWtoALL 22:21:40 2017-07-13 19:23:38,184 AlgErrorAuditor ERROR Illegal Return Code: Algorithm \ +ManagedAthenaTileMon reported an ERROR, but returned a StatusCode "SUCCESS"''' + + logFileName = 'logWithSubstepNameMP' + with open(logFileName, 'w') as logFile: + print >> logFile, testLogERRORwithSubstepNameMP + + logFileReportMP = athenaLogFileReport(logfile=logFileName, substepName='RAWtoALL') + expectedError = dict(level='ERROR', nLevel=logging.ERROR, + firstError=dict(count=1, firstLine=4, message='ToolSvc.TileROD_Decoder ERROR ROB ' + '540007 ROD 540007 has unexpected data size')) + self.assertEqual(logFileReportMP.worstError(), expectedError) + def test_badAlloc(self): self.assertEqual(self.myFileReport4.worstError(), {'level': 'CATASTROPHE', 'nLevel': stdLogLevels['CATASTROPHE'], 'firstError': {'count': 1, 'firstLine': 11,