mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-02 17:29:22 +01:00
Updated to make the formatting strings variable.
This commit is contained in:
parent
fc8da1888c
commit
217799ad1c
181
src/log.py
181
src/log.py
@ -57,6 +57,7 @@ deadlyExceptions = [KeyboardInterrupt, SystemExit]
|
|||||||
testing = False
|
testing = False
|
||||||
|
|
||||||
class Formatter(logging.Formatter):
|
class Formatter(logging.Formatter):
|
||||||
|
_fmtConf = staticmethod(lambda : conf.supybot.log.format())
|
||||||
def formatTime(self, record, datefmt=None):
|
def formatTime(self, record, datefmt=None):
|
||||||
return timestamp(record.created)
|
return timestamp(record.created)
|
||||||
|
|
||||||
@ -66,6 +67,14 @@ class Formatter(logging.Formatter):
|
|||||||
raise
|
raise
|
||||||
return logging.Formatter.formatException(self, (E, e, tb))
|
return logging.Formatter.formatException(self, (E, e, tb))
|
||||||
|
|
||||||
|
def format(self, record):
|
||||||
|
self._fmt = self._fmtConf()
|
||||||
|
return logging.Formatter.format(self, record)
|
||||||
|
|
||||||
|
|
||||||
|
class PluginFormatter(Formatter):
|
||||||
|
_fmtConf = staticmethod(lambda : conf.supybot.log.plugins.format())
|
||||||
|
|
||||||
|
|
||||||
class Logger(logging.Logger):
|
class Logger(logging.Logger):
|
||||||
def exception(self, *args):
|
def exception(self, *args):
|
||||||
@ -97,7 +106,7 @@ class StdoutStreamHandler(logging.StreamHandler):
|
|||||||
if record.levelname != 'ERROR' and conf.supybot.log.stdout.wrap():
|
if record.levelname != 'ERROR' and conf.supybot.log.stdout.wrap():
|
||||||
# We check for ERROR there because otherwise, tracebacks (which are
|
# We check for ERROR there because otherwise, tracebacks (which are
|
||||||
# already wrapped by Python itself) wrap oddly.
|
# already wrapped by Python itself) wrap oddly.
|
||||||
prefixLen = len(record.name) + 2 # ": "
|
prefixLen = len(record.levelname) + 1 # ' '
|
||||||
s = textwrap.fill(s, width=78, subsequent_indent=' '*prefixLen)
|
s = textwrap.fill(s, width=78, subsequent_indent=' '*prefixLen)
|
||||||
s.rstrip('\r\n')
|
s.rstrip('\r\n')
|
||||||
return s
|
return s
|
||||||
@ -129,6 +138,9 @@ class BetterFileHandler(logging.FileHandler):
|
|||||||
|
|
||||||
|
|
||||||
class ColorizedFormatter(Formatter):
|
class ColorizedFormatter(Formatter):
|
||||||
|
# This was necessary because these variables aren't defined until later.
|
||||||
|
# The staticmethod is necessary because they get treated like methods.
|
||||||
|
_fmtConf = staticmethod(lambda : conf.supybot.log.stdout.format())
|
||||||
def formatException(self, (E, e, tb)):
|
def formatException(self, (E, e, tb)):
|
||||||
if conf.supybot.log.stdout.colorized():
|
if conf.supybot.log.stdout.colorized():
|
||||||
return ''.join([ansi.RED,
|
return ''.join([ansi.RED,
|
||||||
@ -156,13 +168,100 @@ class ColorizedFormatter(Formatter):
|
|||||||
return Formatter.format(self, record, *args, **kwargs)
|
return Formatter.format(self, record, *args, **kwargs)
|
||||||
|
|
||||||
# These are public.
|
# These are public.
|
||||||
formatter = Formatter('%(levelname)s %(asctime)s %(message)s')
|
formatter = Formatter('NEVER SEEN')
|
||||||
pluginFormatter = Formatter('%(levelname)s %(asctime)s %(name)s %(message)s')
|
pluginFormatter = PluginFormatter('NEVER SEEN')
|
||||||
|
|
||||||
# These are not.
|
# These are not.
|
||||||
logging.setLoggerClass(Logger)
|
logging.setLoggerClass(Logger)
|
||||||
_logger = logging.getLogger('supybot')
|
_logger = logging.getLogger('supybot')
|
||||||
|
|
||||||
|
class ValidLogLevel(registry.String):
|
||||||
|
"""Invalid log level."""
|
||||||
|
minimumLevel = -1
|
||||||
|
def set(self, s):
|
||||||
|
s = s.upper()
|
||||||
|
try:
|
||||||
|
level = getattr(logging, s)
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
level = int(s)
|
||||||
|
except ValueError:
|
||||||
|
self.error()
|
||||||
|
if level < self.minimumLevel:
|
||||||
|
self.error()
|
||||||
|
self.setValue(level)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
level = logging.getLevelName(self.value)
|
||||||
|
if level.startswith('Level'):
|
||||||
|
level = level.split()[-1]
|
||||||
|
return level
|
||||||
|
|
||||||
|
class LogLevel(ValidLogLevel):
|
||||||
|
"""Invalid log level. Value must be either DEBUG, INFO, WARNING, ERROR,
|
||||||
|
or CRITICAL."""
|
||||||
|
def setValue(self, v):
|
||||||
|
ValidLogLevel.setValue(self, v)
|
||||||
|
_logger.setLevel(self.value) # _logger defined later.
|
||||||
|
|
||||||
|
conf.registerGlobalValue(conf.supybot.directories, 'log',
|
||||||
|
conf.Directory('logs', """Determines what directory the bot will store its
|
||||||
|
logfiles in."""))
|
||||||
|
|
||||||
|
conf.registerGroup(conf.supybot, 'log')
|
||||||
|
conf.registerGlobalValue(conf.supybot.log, 'format',
|
||||||
|
registry.String('%(levelname)s %(asctime)s %(name)s %(message)s',
|
||||||
|
"""Determines what the bot's logging format will be. The relevant
|
||||||
|
documentation on the available formattings is Python's documentation on
|
||||||
|
its logging module."""))
|
||||||
|
conf.registerGlobalValue(conf.supybot.log, 'level',
|
||||||
|
LogLevel(logging.INFO, """Determines what the minimum priority level logged
|
||||||
|
will be. Valid values are DEBUG, INFO, WARNING, ERROR, and CRITICAL, in
|
||||||
|
order of increasing priority."""))
|
||||||
|
conf.registerGlobalValue(conf.supybot.log, 'statistics',
|
||||||
|
ValidLogLevel(logging.DEBUG, """Determines what level statistics reporting
|
||||||
|
is to be logged at. Mostly, this just includes, for instance, the time it
|
||||||
|
took to parse a message, process a command, etc. You probably don't care
|
||||||
|
about this."""))
|
||||||
|
conf.registerGlobalValue(conf.supybot.log, 'timestampFormat',
|
||||||
|
registry.String('[%d-%b-%Y %H:%M:%S]', """Determines the format string for
|
||||||
|
timestamps in logfiles. Refer to the Python documentation for the time
|
||||||
|
module to see what formats are accepted. If you set this variable to the
|
||||||
|
empty string, times will be logged in a simple seconds-since-epoch
|
||||||
|
format."""))
|
||||||
|
|
||||||
|
class BooleanRequiredFalseOnWindows(registry.Boolean):
|
||||||
|
def set(self, s):
|
||||||
|
registry.Boolean.set(self, s)
|
||||||
|
if self.value and os.name == 'nt':
|
||||||
|
raise InvalidRegistryValue, 'Value cannot be true on Windows.'
|
||||||
|
|
||||||
|
conf.registerGlobalValue(conf.supybot.log, 'stdout',
|
||||||
|
registry.Boolean(True, """Determines whether the bot will log to
|
||||||
|
stdout."""))
|
||||||
|
conf.registerGlobalValue(conf.supybot.log.stdout, 'colorized',
|
||||||
|
BooleanRequiredFalseOnWindows(False, """Determines whether the bot's logs
|
||||||
|
to stdout (if enabled) will be colorized with ANSI color."""))
|
||||||
|
conf.registerGlobalValue(conf.supybot.log.stdout, 'wrap',
|
||||||
|
registry.Boolean(True, """Determines whether the bot will wrap its logs
|
||||||
|
when they're output to stdout."""))
|
||||||
|
conf.registerGlobalValue(conf.supybot.log.stdout, 'format',
|
||||||
|
registry.String('%(levelname)s %(asctime)s %(message)s',
|
||||||
|
"""Determines what the bot's logging format will be. The relevant
|
||||||
|
documentation on the available formattings is Python's documentation on
|
||||||
|
its logging module."""))
|
||||||
|
|
||||||
|
conf.registerGroup(conf.supybot.log, 'plugins')
|
||||||
|
conf.registerGlobalValue(conf.supybot.log.plugins, 'individualLogfiles',
|
||||||
|
registry.Boolean(False, """Determines whether the bot will separate plugin
|
||||||
|
logs into their own individual logfiles."""))
|
||||||
|
conf.registerGlobalValue(conf.supybot.log.plugins, 'format',
|
||||||
|
registry.String('%(levelname)s %(asctime)s %(message)s',
|
||||||
|
"""Determines what the bot's logging format will be. The relevant
|
||||||
|
documentation on the available formattings is Python's documentation on
|
||||||
|
its logging module."""))
|
||||||
|
|
||||||
|
|
||||||
# These just make things easier.
|
# These just make things easier.
|
||||||
debug = _logger.debug
|
debug = _logger.debug
|
||||||
info = _logger.info
|
info = _logger.info
|
||||||
@ -183,7 +282,7 @@ atexit.register(logging.shutdown)
|
|||||||
ircutils.debug = debug
|
ircutils.debug = debug
|
||||||
|
|
||||||
def getPluginLogger(name):
|
def getPluginLogger(name):
|
||||||
if not conf.supybot.log.individualPluginLogfiles():
|
if not conf.supybot.log.plugins.individualLogfiles():
|
||||||
return _logger
|
return _logger
|
||||||
log = logging.getLogger('supybot.plugins.%s' % name)
|
log = logging.getLogger('supybot.plugins.%s' % name)
|
||||||
if not log.handlers:
|
if not log.handlers:
|
||||||
@ -260,77 +359,6 @@ class MetaFirewall(type):
|
|||||||
#return type.__new__(cls, name, bases, dict)
|
#return type.__new__(cls, name, bases, dict)
|
||||||
|
|
||||||
|
|
||||||
class ValidLogLevel(registry.String):
|
|
||||||
"""Invalid log level."""
|
|
||||||
minimumLevel = -1
|
|
||||||
def set(self, s):
|
|
||||||
s = s.upper()
|
|
||||||
try:
|
|
||||||
level = getattr(logging, s)
|
|
||||||
except AttributeError:
|
|
||||||
try:
|
|
||||||
level = int(s)
|
|
||||||
except ValueError:
|
|
||||||
self.error()
|
|
||||||
if level < self.minimumLevel:
|
|
||||||
self.error()
|
|
||||||
self.setValue(level)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
level = logging.getLevelName(self.value)
|
|
||||||
if level.startswith('Level'):
|
|
||||||
level = level.split()[-1]
|
|
||||||
return level
|
|
||||||
|
|
||||||
class LogLevel(ValidLogLevel):
|
|
||||||
"""Invalid log level. Value must be either DEBUG, INFO, WARNING, ERROR,
|
|
||||||
or CRITICAL."""
|
|
||||||
def setValue(self, v):
|
|
||||||
ValidLogLevel.setValue(self, v)
|
|
||||||
_logger.setLevel(self.value) # _logger defined later.
|
|
||||||
|
|
||||||
conf.registerGlobalValue(conf.supybot.directories, 'log',
|
|
||||||
conf.Directory('logs', """Determines what directory the bot will store its
|
|
||||||
logfiles in."""))
|
|
||||||
|
|
||||||
conf.registerGroup(conf.supybot, 'log')
|
|
||||||
conf.registerGlobalValue(conf.supybot.log, 'level',
|
|
||||||
LogLevel(logging.INFO, """Determines what the minimum priority level logged
|
|
||||||
will be. Valid values are DEBUG, INFO, WARNING, ERROR, and CRITICAL, in
|
|
||||||
order of increasing priority."""))
|
|
||||||
conf.registerGlobalValue(conf.supybot.log, 'statistics',
|
|
||||||
ValidLogLevel(logging.DEBUG, """Determines what level statistics reporting
|
|
||||||
is to be logged at. Mostly, this just includes, for instance, the time it
|
|
||||||
took to parse a message, process a command, etc. You probably don't care
|
|
||||||
about this."""))
|
|
||||||
conf.registerGlobalValue(conf.supybot.log, 'stdout',
|
|
||||||
registry.Boolean(True, """Determines whether the bot will log to
|
|
||||||
stdout."""))
|
|
||||||
conf.registerGlobalValue(conf.supybot.log, 'individualPluginLogfiles',
|
|
||||||
registry.Boolean(False, """Determines whether the bot will separate plugin
|
|
||||||
logs into their own individual logfiles."""))
|
|
||||||
|
|
||||||
class BooleanRequiredFalseOnWindows(registry.Boolean):
|
|
||||||
def set(self, s):
|
|
||||||
registry.Boolean.set(self, s)
|
|
||||||
if self.value and os.name == 'nt':
|
|
||||||
raise InvalidRegistryValue, 'Value cannot be true on Windows.'
|
|
||||||
|
|
||||||
conf.registerGlobalValue(conf.supybot.log.stdout, 'colorized',
|
|
||||||
BooleanRequiredFalseOnWindows(False, """Determines whether the bot's logs
|
|
||||||
to stdout (if enabled) will be colorized with ANSI color."""))
|
|
||||||
|
|
||||||
conf.registerGlobalValue(conf.supybot.log.stdout, 'wrap',
|
|
||||||
registry.Boolean(True, """Determines whether the bot will wrap its logs
|
|
||||||
when they're output to stdout."""))
|
|
||||||
|
|
||||||
conf.registerGlobalValue(conf.supybot.log, 'timestampFormat',
|
|
||||||
registry.String('[%d-%b-%Y %H:%M:%S]', """Determines the format string for
|
|
||||||
timestamps in logfiles. Refer to the Python documentation for the time
|
|
||||||
module to see what formats are accepted. If you set this variable to the
|
|
||||||
empty string, times will be logged in a simple seconds-since-epoch
|
|
||||||
format."""))
|
|
||||||
|
|
||||||
_logDir = conf.supybot.directories.log()
|
_logDir = conf.supybot.directories.log()
|
||||||
if not os.path.exists(_logDir):
|
if not os.path.exists(_logDir):
|
||||||
os.mkdir(_logDir, 0755)
|
os.mkdir(_logDir, 0755)
|
||||||
@ -348,8 +376,7 @@ _logger.setLevel(conf.supybot.log.level())
|
|||||||
|
|
||||||
if not conf.daemonized:
|
if not conf.daemonized:
|
||||||
_stdoutHandler = StdoutStreamHandler(sys.stdout)
|
_stdoutHandler = StdoutStreamHandler(sys.stdout)
|
||||||
_formatString = '%(name)s: %(levelname)s %(message)s'
|
_stdoutFormatter = ColorizedFormatter('YOU SHOULD NEVER SEE THIS!')
|
||||||
_stdoutFormatter = ColorizedFormatter(_formatString)
|
|
||||||
_stdoutHandler.setFormatter(_stdoutFormatter)
|
_stdoutHandler.setFormatter(_stdoutFormatter)
|
||||||
_stdoutHandler.setLevel(-1)
|
_stdoutHandler.setLevel(-1)
|
||||||
_logger.addHandler(_stdoutHandler)
|
_logger.addHandler(_stdoutHandler)
|
||||||
|
Loading…
Reference in New Issue
Block a user