diff options
Diffstat (limited to 'dogtail/logging.py')
-rwxr-xr-x | dogtail/logging.py | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/dogtail/logging.py b/dogtail/logging.py new file mode 100755 index 00000000000..7e73f163b83 --- /dev/null +++ b/dogtail/logging.py @@ -0,0 +1,218 @@ +# -*- coding: utf-8 -*- +""" +Logging facilities + +Authors: Ed Rousseau <rousseau@redhat.com>, Zack Cerza <zcerza@redhat.com, David Malcolm <dmalcolm@redhat.com> +""" + +__author__ = """Ed Rousseau <rousseau@redhat.com>, +Zack Cerza <zcerza@redhat.com, +David Malcolm <dmalcolm@redhat.com> +""" +import os +import sys +import time +from config import config +import codecs + +# Timestamp class for file logs + + +class TimeStamp(object): + + """ + Generates timestamps tempfiles and log entries + """ + + def __init__(self): + self.now = "0" + self.timetup = time.localtime() + + def zeroPad(self, int, width=2): + """ + Pads an integer 'int' with zeroes, up to width 'width'. + + Returns a string. + + It will not truncate. If you call zeroPad(100, 2), '100' will be returned. + """ + if int < 10 ** width: + return ("0" * (width - len(str(int)))) + str(int) + else: + return str(int) + + # file stamper + def fileStamp(self, filename, addTime=True): + """ + Generates a filename stamp in the format of filename_YYYYMMDD-hhmmss. + A format of filename_YYYYMMDD can be used instead by specifying addTime = False. + """ + self.now = filename.strip() + "_" + self.timetup = time.localtime() + + # Should produce rel-eng style filestamps + # format it all pretty by chopping the tuple + fieldCount = 3 + if addTime: + fieldCount = fieldCount + 3 + for i in range(fieldCount): + if i == 3: + self.now = self.now + '-' + self.now = self.now + self.zeroPad(self.timetup[i]) + return self.now + + # Log entry stamper + def entryStamp(self): + """ + Generates a logfile entry stamp of YYYY.MM.DD HH:MM:SS + """ + self.timetup = time.localtime() + + # This will return a log entry formatted string in YYYY.MM.DD HH:MM:SS + for i in range(6): + # put in the year + if i == 0: + self.now = str(self.timetup[i]) + # Format Month and Day + elif i == 1 or i == 2: + self.now = self.now + "." + self.zeroPad(self.timetup[i]) + else: + # make the " " between Day and Hour and put in the hour + if i == 3: + self.now = self.now + " " + self.zeroPad(self.timetup[i]) + # Otherwise Use the ":" divider + else: + self.now = self.now + ":" + self.zeroPad(self.timetup[i]) + return self.now + + +class Logger(object): + + """ + Writes entries to standard out. + """ + stamper = TimeStamp() + + def __init__(self, logName, file=False, stdOut=True): + """ + name: the name of the log + file: The file object to log to. + stdOut: Whether to log to standard out. + """ + self.logName = logName + self.stdOut = stdOut + self.file = file # Handle to the logfile + if not self.file: + return + + scriptName = config.scriptName + if not scriptName: + scriptName = 'log' + self.fileName = scriptName + + # check to see if we can write to the logDir + if os.path.isdir(config.logDir): + self.findUniqueName() + else: + # If path doesn't exist, raise an exception + raise IOError( + "Log path %s does not exist or is not a directory" % config.logDir) + + def findUniqueName(self): + # generate a logfile name and check if it already exists + self.fileName = config.logDir + self.stamper.fileStamp(self.fileName) \ + + '_' + self.logName + i = 0 + while os.path.exists(self.fileName): + # Append the pathname + if i == 0: + self.fileName = self.fileName + "." + str(i) + else: + logsplit = self.fileName.split(".") + logsplit[-1] = str(i) + self.fileName = ".".join(logsplit) + i += 1 + + def createFile(self): + # Try to create the file and write the header info + print("Creating logfile at %s ..." % self.fileName) + self.file = codecs.open(self.fileName, mode='wb', encoding= + 'utf-8') + self.file.write("##### " + os.path.basename(self.fileName) + '\n') + self.file.flush() + + def log(self, message, newline=True, force=False): + """ + Hook used for logging messages. Might eventually be a virtual + function, but nice and simple for now. + + If force is True, log to a file irrespective of config.logDebugToFile. + """ + try: + message = message.decode('utf-8', 'replace') + except UnicodeEncodeError: + pass + + + # Try to open and write the result to the log file. + if isinstance(self.file, bool) and (force or config.logDebugToFile): + self.createFile() + + if force or config.logDebugToFile: + if newline: + self.file.write(message + '\n') + else: + self.file.write(message + ' ') + self.file.flush() + + if self.stdOut and config.logDebugToStdOut: + if newline: + print(message) + else: + print(message) + + +class ResultsLogger(Logger): + + """ + Writes entries into the Dogtail log + """ + + def __init__(self, stdOut=True): + Logger.__init__(self, 'results', file=True, stdOut=stdOut) + + # Writes the result of a test case comparison to the log + def log(self, entry): + """ + Writes the log entry. Requires a 1 {key: value} pair dict for an argument or else it will throw an exception. + """ + # We require a 1 key: value dict + # Strip all leading and trailing witespace from entry dict and convert + # to string for writing + + if len(entry) == 1: + key = entry.keys() + value = entry.values() + key = key[0] + value = value[0] + entry = str(key) + ": " + str(value) + else: + raise ValueError(entry) + print( + "Method argument requires a 1 {key: value} dict. Supplied argument not one {key: value}") + + Logger.log(self, self.stamper.entryStamp() + " " + entry, + force=True) + +debugLogger = Logger('debug', config.logDebugToFile) + +import traceback + + +def exceptionHook(exc, value, tb): # pragma: no cover + tbStringList = traceback.format_exception(exc, value, tb) + tbString = ''.join(tbStringList) + debugLogger.log(tbString) + sys.exc_clear() + +sys.excepthook = exceptionHook |