210 lines
4.5 KiB
Python
210 lines
4.5 KiB
Python
'''Simple logging module'''
|
|
|
|
import sys
|
|
|
|
from os import environ as env
|
|
from datetime import datetime
|
|
|
|
|
|
stdout = sys.stdout
|
|
|
|
|
|
class Log():
|
|
def __init__(self, config=dict()):
|
|
'''setup the logger'''
|
|
if not isinstance(config, dict):
|
|
raise TypeError(f'config is not a dict')
|
|
|
|
self.levels = {
|
|
'CRIT': 60,
|
|
'ERROR': 50,
|
|
'WARN': 40,
|
|
'INFO': 30,
|
|
'VERB': 20,
|
|
'DEBUG': 10,
|
|
'MERP': 0
|
|
}
|
|
|
|
self.long_levels = {
|
|
'CRITICAL': 'CRIT',
|
|
'ERROR': 'ERROR',
|
|
'WARNING': 'WARN',
|
|
'INFO': 'INFO',
|
|
'VERBOSE': 'VERB',
|
|
'DEBUG': 'DEBUG',
|
|
'MERP': 'MERP'
|
|
}
|
|
|
|
self.config = {'windows': sys.executable.endswith('pythonw.exe')}
|
|
self.setConfig(self._parseConfig(config))
|
|
|
|
|
|
def _lvlCheck(self, level):
|
|
'''make sure the minimum logging level is an int'''
|
|
try:
|
|
value = int(level)
|
|
|
|
except ValueError:
|
|
level = self.long_levels.get(level.upper(), level)
|
|
value = self.levels.get(level)
|
|
|
|
if value not in self.levels.values():
|
|
raise InvalidLevel(f'Invalid logging level: {level}')
|
|
|
|
return value
|
|
|
|
|
|
def _getLevelName(self, level):
|
|
for name, num in self.levels.items():
|
|
if level == num:
|
|
return name
|
|
|
|
raise InvalidLevel(f'Invalid logging level: {level}')
|
|
|
|
|
|
def _parseConfig(self, config):
|
|
'''parse the new config and update the old values'''
|
|
date = config.get('date', self.config.get('date',True))
|
|
systemd = config.get('systemd', self.config.get('systemd,', True))
|
|
windows = config.get('windows', self.config.get('windows', False))
|
|
|
|
if not isinstance(date, bool):
|
|
raise TypeError(f'value for "date" is not a boolean: {date}')
|
|
|
|
if not isinstance(systemd, bool):
|
|
raise TypeError(f'value for "systemd" is not a boolean: {date}')
|
|
|
|
level_num = self._lvlCheck(config.get('level', self.config.get('level', 'INFO')))
|
|
|
|
newconfig = {
|
|
'level': self._getLevelName(level_num),
|
|
'levelnum': level_num,
|
|
'datefmt': config.get('datefmt', self.config.get('datefmt', '%Y-%m-%d %H:%M:%S')),
|
|
'date': date,
|
|
'systemd': systemd,
|
|
'windows': windows,
|
|
'systemnotif': config.get('systemnotif', None)
|
|
}
|
|
|
|
return newconfig
|
|
|
|
|
|
def setConfig(self, config):
|
|
'''set the config'''
|
|
self.config = self._parseConfig(config)
|
|
|
|
|
|
def getConfig(self, key=None):
|
|
'''return the current config'''
|
|
if key:
|
|
if self.config.get(key):
|
|
return self.config.get(key)
|
|
else:
|
|
raise ValueError(f'Invalid config option: {key}')
|
|
return self.config
|
|
|
|
|
|
def printConfig(self):
|
|
for k,v in self.config.items():
|
|
stdout.write(f'{k}: {v}\n')
|
|
|
|
stdout.flush()
|
|
|
|
|
|
def setLevel(self, level):
|
|
self.minimum = self._lvlCheck(level)
|
|
|
|
|
|
def log(self, level, *msg):
|
|
if self.config['windows']:
|
|
return
|
|
|
|
'''log to the console'''
|
|
levelNum = self._lvlCheck(level)
|
|
|
|
if type(level) == int:
|
|
level = _getLevelName(level)
|
|
|
|
if levelNum < self.config['levelnum']:
|
|
return
|
|
|
|
message = ' '.join([str(message) for message in msg])
|
|
output = f'{level}: {message}\n'
|
|
|
|
if self.config['systemnotif']:
|
|
self.config['systemnotif'].New(level, message)
|
|
|
|
if self.config['date'] and (self.config['systemd'] and not env.get('INVOCATION_ID')):
|
|
'''only show date when not running in systemd and date var is True'''
|
|
date = datetime.now().strftime(self.config['datefmt'])
|
|
output = f'{date} {output}'
|
|
|
|
stdout.write(output)
|
|
stdout.flush()
|
|
|
|
|
|
def critical(self, *msg):
|
|
self.log('CRIT', *msg)
|
|
|
|
def error(self, *msg):
|
|
self.log('ERROR', *msg)
|
|
|
|
def warning(self, *msg):
|
|
self.log('WARN', *msg)
|
|
|
|
def info(self, *msg):
|
|
self.log('INFO', *msg)
|
|
|
|
def verbose(self, *msg):
|
|
self.log('VERB', *msg)
|
|
|
|
def debug(self, *msg):
|
|
self.log('DEBUG', *msg)
|
|
|
|
def merp(self, *msg):
|
|
self.log('MERP', *msg)
|
|
|
|
|
|
def getLogger(loginst, config=None):
|
|
'''get a logging instance and create one if it doesn't exist'''
|
|
Logger = logger.get(loginst)
|
|
|
|
if not Logger:
|
|
if config:
|
|
logger[loginst] = Log(config)
|
|
|
|
else:
|
|
raise InvalidLogger(f'logger "{loginst}" doesn\'t exist')
|
|
|
|
return logger[loginst]
|
|
|
|
class InvalidLevel(Exception):
|
|
'''Raise when an invalid logging level was specified'''
|
|
|
|
class InvalidLogger(Exception):
|
|
'''Raise when the specified logger doesn't exist'''
|
|
|
|
|
|
'''create a default logger'''
|
|
logger = {
|
|
'default': Log()
|
|
}
|
|
|
|
DefaultLog = logger['default']
|
|
|
|
|
|
'''aliases for default logger's log output functions'''
|
|
critical = DefaultLog.critical
|
|
error = DefaultLog.error
|
|
warning = DefaultLog.warning
|
|
info = DefaultLog.info
|
|
verbose = DefaultLog.verbose
|
|
debug = DefaultLog.debug
|
|
merp = DefaultLog.merp
|
|
|
|
'''aliases for the default logger's config functions'''
|
|
setConfig = DefaultLog.setConfig
|
|
getConfig = DefaultLog.getConfig
|
|
setLevel = DefaultLog.setLevel
|
|
printConfig = DefaultLog.printConfig
|