# -*- coding: utf8 -*-
"""
****************************
``helpers/customlogging.py``
****************************
`BSD`_ © 2018-2019 Science and Technology Facilities Council & contributors
.. _BSD: _static/LICENSE
``customlogging.py`` is a helpers module provided to define and configure consistent logging. The logging
configuration is handled via ``../logging.yml`` YAML file and uses ``colorlog`` for console output.
A rolling system is used for outputting to files.
"""
import os
import sys
import yaml
import logging
import logging.config
[docs]def setup_logging(logr_settings='../logging.yml', default_level=logging.INFO):
"""Setup logging configuration from a YAML file
Args:
logr_settings (str, optional): Defines the relative location of the logging configuration file,
from the root module. Default value: ``logging.yml``
default_level (logging attr, optional): Sets the default logging level. Default value: logging.INFO
Returns:
None
"""
logr_settings = os.path.abspath(os.path.join(os.path.dirname(__file__), logr_settings))
if os.path.isfile(logr_settings):
with open(logr_settings, 'rt') as f:
config = yaml.safe_load(f.read())
logging.config.dictConfig(config)
else:
logging.basicConfig(level=default_level)
logger = logging.getLogger(__name__)
setup_logging(logr_settings='../logging.yml', default_level=logging.INFO)
[docs]def constant(f):
"""setters and getters for constants used throughout
Prevents setting of existing objects. Raises a TypeError.
Return:
property
Raises:
TypeError: On setter.
"""
def fset(value):
raise TypeError
def fget():
return f()
return property(fget, fset)
[docs]class LogLevelsConsts(object):
"""Logger level equivalent strings as constants, used to pass log level to helpers functions.
Attributes:
DEBUG (str): String matching DEBUG logger level.
INFO (str): String matching INFO logger level.
WARNING (str): String matching WARNING logger level.
CRITICAL (str): String matching CRITICAL logger level.
ERROR (str): String matching ERROR logger level.
"""
@constant
def DEBUG(self):
return 'DEBUG'
@constant
def INFO(self):
return 'INFO'
@constant
def WARNING(self):
return 'WARNING'
@constant
def CRITICAL(self):
return 'CRITICAL'
@constant
def ERROR(self):
return 'ERROR'
[docs]def config_logger(name, class_name=None):
"""Allows a logger to be set up and/or configured in all modules/module classes
Args:
name (str): Name of the logger.
class_name (str, optional): Name of the class to which the logger is associated. Default value: None
Returns:
logging (obj): A configured logger object.
"""
if class_name is None:
logr = logging.getLogger('{}'
.format(name))
setup_logging(logr_settings='../logging.yml', default_level=logging.INFO)
else:
logr = logging.getLogger('{}.{}'
.format(name, class_name))
return logr
[docs]def sect_break(logr, level=LogLevelsConsts.INFO):
"""Inserts a section break in the logger output.
Args:
logr (obj): A logger object to pass the section break to.
level (attr of LogLevelsConsts obj, optional): Logger level of the section break.
Default value: LogLevelsConsts.INFO
Returns:
None
"""
delimit = '*' * 80
try:
if level == LogLevelsConsts.DEBUG:
logr.debug(delimit)
elif level == LogLevelsConsts.INFO:
logr.info(delimit)
elif level == LogLevelsConsts.WARNING:
logr.warning(delimit)
elif level == LogLevelsConsts.CRITICAL:
logr.critical(delimit)
elif level == LogLevelsConsts.ERROR:
logr.error(delimit)
else:
logr.info(delimit)
except AttributeError as e:
logr.error('{}'
.format(__name__))
logr.error('\t{}'
.format(e))
[docs]def errorexit(logr):
"""Inserts a exit on error message in the logger output and performs a ``sys.exit(-1)``
Args:
logr (obj): A logger object to pass the exit on error message to.
Returns:
None
"""
logr.error('')
logr.error('Exiting...')
sys.exit(-1)
[docs]def mand_missing(obj, field):
"""Inserts a mandatory field missing error message in the logger output and calls ``errorexit()``
Args:
logr (obj): A logger object to pass the error message to.
field (str): field to report in the error message.
Returns:
None
"""
obj.logger.error('Missing Mandatory Field in: {obj.settings_file}'
.format(obj=obj))
obj.logger.error('{obj.category}'
.format(obj=obj))
obj.logger.error(' {field}: <VALUE>'
.format(field=field))
errorexit(obj.logger)
[docs]def path_missing(obj, name, path):
"""Inserts a path missing error message in the logger output and calls ``errorexit()``
Args:
logr (obj): A logger object to pass the error message to.
name (str): Name of processing element which caused the error message.
path (str): Missing Path which caused the error message.
Returns:
None
"""
obj.logger.error('Processing: {name}'
.format(name=name))
obj.logger.error('Path Missing on File-System: {path}'
.format(path=path))
errorexit(obj.logger)
def disable_logger(log_obj, term):
# svn logger DEBUG messages contain plain text passwords passed to svn and git.
# To prevent the svn logger from writing DEBUG level messages in the log file disable all 'term'
# related loggers:
for name, logr in log_obj.logging.root.manager.loggerDict.iteritems():
if term in name:
logr.disabled = True
# Logging is required to be setup and configured prior to loading version modules
import version as my_version
rev = filter(str.isdigit, "$Rev$") # Do Not Modify this Line
version = my_version.Version(0, 5, 0, svn_rev=rev, disable_svn_logging=True)
__version__ = version.get_version()
__str__ = my_version.about(__name__, __version__, version.revision)