| # This Source Code Form is subject to the terms of the Mozilla Public |
| # License, v. 2.0. If a copy of the MPL was not distributed with this file, |
| # You can obtain one at http://mozilla.org/MPL/2.0/. |
| |
| from logging import getLogger as getSysLogger |
| from logging import * |
| # Some of the build slave environments don't see the following when doing |
| # 'from logging import *' |
| # see https://bugzilla.mozilla.org/show_bug.cgi?id=700415#c35 |
| from logging import getLoggerClass, addLevelName, setLoggerClass, shutdown |
| |
| _default_level = INFO |
| _LoggerClass = getLoggerClass() |
| |
| # Define mozlog specific log levels |
| START = _default_level + 1 |
| END = _default_level + 2 |
| PASS = _default_level + 3 |
| KNOWN_FAIL = _default_level + 4 |
| FAIL = _default_level + 5 |
| # Define associated text of log levels |
| addLevelName(START, 'TEST-START') |
| addLevelName(END, 'TEST-END') |
| addLevelName(PASS, 'TEST-PASS') |
| addLevelName(KNOWN_FAIL, 'TEST-KNOWN-FAIL') |
| addLevelName(FAIL, 'TEST-UNEXPECTED-FAIL') |
| |
| class _MozLogger(_LoggerClass): |
| """ |
| MozLogger class which adds three convenience log levels |
| related to automated testing in Mozilla |
| """ |
| def testStart(self, message, *args, **kwargs): |
| self.log(START, message, *args, **kwargs) |
| |
| def testEnd(self, message, *args, **kwargs): |
| self.log(END, message, *args, **kwargs) |
| |
| def testPass(self, message, *args, **kwargs): |
| self.log(PASS, message, *args, **kwargs) |
| |
| def testFail(self, message, *args, **kwargs): |
| self.log(FAIL, message, *args, **kwargs) |
| |
| def testKnownFail(self, message, *args, **kwargs): |
| self.log(KNOWN_FAIL, message, *args, **kwargs) |
| |
| class _MozFormatter(Formatter): |
| """ |
| MozFormatter class used to standardize formatting |
| If a different format is desired, this can be explicitly |
| overriden with the log handler's setFormatter() method |
| """ |
| level_length = 0 |
| max_level_length = len('TEST-START') |
| |
| def __init__(self): |
| """ |
| Formatter.__init__ has fmt and datefmt parameters that won't have |
| any affect on a MozFormatter instance. Bypass it to avoid confusion. |
| """ |
| |
| def format(self, record): |
| record.message = record.getMessage() |
| |
| # Handles padding so record levels align nicely |
| if len(record.levelname) > self.level_length: |
| pad = 0 |
| if len(record.levelname) <= self.max_level_length: |
| self.level_length = len(record.levelname) |
| else: |
| pad = self.level_length - len(record.levelname) + 1 |
| sep = '|'.rjust(pad) |
| fmt = '%(name)s %(levelname)s ' + sep + ' %(message)s' |
| return fmt % record.__dict__ |
| |
| def getLogger(name, logfile=None): |
| """ |
| Returns the logger with the specified name. |
| If the logger doesn't exist, it is created. |
| |
| name - The name of the logger to retrieve |
| [filePath] - If specified, the logger will log to the specified filePath |
| Otherwise, the logger logs to stdout |
| This parameter only has an effect if the logger doesn't exist |
| """ |
| setLoggerClass(_MozLogger) |
| |
| if name in Logger.manager.loggerDict: |
| return getSysLogger(name) |
| |
| logger = getSysLogger(name) |
| logger.setLevel(_default_level) |
| |
| if logfile: |
| handler = FileHandler(logfile) |
| else: |
| handler = StreamHandler() |
| handler.setFormatter(_MozFormatter()) |
| logger.addHandler(handler) |
| return logger |
| |