Source code for mosaic.utilities.mosaicLogging

# -*- coding: utf-8 -*-
"""
	An implementation of Python logging heavily adapted from `<http://stackoverflow.com/questions/15727420/using-python-logging-in-multiple-modules>`_.

	:Created:	5/29/2016
	:Author: 	Arvind Balijepalli <arvind.balijepalli@nist.gov>
	:License:	See LICENSE.TXT
	:ChangeLog:
	.. line-block::
		5/30/16 	AB 	Strip whitespace from rotating file handler messages.
		5/29/16		AB	Initial version
"""
import sys
import os
import logging
import logging.handlers
import mosaic
from mosaic.utilities.mosaicLogHandlers import sqliteHandler
from mosaic.utilities.resource_path import format_path

__all__=["mosaicLogging", "metaSingleton", "MessageFormatter", "mosaicExceptionHandler"]

def mosaicExceptionHandler(extype, exvalue, extb):
	if issubclass(extype, KeyboardInterrupt):
		sys.__excepthook__(extype, exvalue, extb)
		return

	logger=mosaicLogging().getLogger(__name__)
	handler = logging.StreamHandler(stream=sys.stderr)
	logger.addHandler(handler)
	logger.critical("", exc_info=(extype, exvalue, extb))


class metaSingleton(type):
	_instances = {}

	def __call__(cls, *args, **kwargs):
		if cls not in list(cls._instances.keys()):
			cls._instances[cls] = super(metaSingleton, cls).__call__(*args, **kwargs)
		return cls._instances[cls]

[docs]class MessageFormatter(logging.Formatter):
[docs] def format(self, record): try: record.msg = record.msg.strip() except: pass return super(MessageFormatter, self).format(record)
[docs]class mosaicLogging(object, metaclass=metaSingleton): """ A custom logging class that uses the Python logging facility. Logs are automatically saved to a metaMDIO instance, and to a file log when DeveloperMode is active. """ _loggers = {} log=logging.getLogger() log.setLevel(logging.DEBUG) formatstr=MessageFormatter("%(asctime)-8s %(levelname)-8s %(name)-12s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S") # Rotating File Handler try: logdir=mosaic.LogLocation log.info("Logs will be saved to: {0}".format(logdir)) except AttributeError as err: if sys.platform.startswith('darwin'): logdir=format_path(os.path.expanduser('~')+"/Library/Logs/MOSAIC") if not os.path.exists(logdir): os.mkdir(logdir) elif sys.platform.startswith('linux'): if os.getuid()==0: logdir="/var/log/" else: log.info("MOSAIC log will be saved to ~/mosaic.log. Run MOSAIC with sudo to save logs to '/var/log/.") logdir=os.path.expanduser("~") else: logdir=os.path.expanduser("~") logname=format_path(logdir+"/mosaic.log") rfh=logging.handlers.RotatingFileHandler(filename=logname, maxBytes=mosaic.LogSizeBytes, backupCount=5) rfh.setFormatter(formatstr) if mosaic.DeveloperMode: rfh.setLevel(logging.DEBUG) else: rfh.setLevel(logging.INFO) log.addHandler(rfh) sh=None def __init__(self, *args, **kwargs): pass
[docs] @staticmethod def getLogger(name=None, dbHnd=None): """ Get a logger instance. :Parameters: - `name` : Logger name - `dbHnd` : MetaMDIO handle to allow logs to be saved to the database. :Usage: In this example, we get an instance of a logger with the module name and log a debug message. .. code-block:: python logger=mosaicLogging().getLogger(__name__) logger.debug("Test debug message") """ if not name: logger=logging.getLogger() elif name not in list(mosaicLogging._loggers.keys()): logger=logging.getLogger(str(name)) mosaicLogging._loggers[name]=logger else: logger=mosaicLogging._loggers[name] if dbHnd: # if a db handle is set, update all loggers with the new handle mosaicLogging.sh=sqliteHandler(dbHnd) mosaicLogging.sh.setLevel(logging.INFO) mosaicLogging.sh.setFormatter(logging.Formatter("%(message)s\n")) for name in list(mosaicLogging._loggers.keys()): l=mosaicLogging._loggers[name] for h in l.handlers: if isinstance(h, sqliteHandler): l.removeHandler(h) l.addHandler(mosaicLogging.sh) return logger
if __name__ == '__main__': logger=mosaicLogging().getLogger(__name__) logger.debug("Test debug message")