## ## logging.py ## Login : ## Started on Mon Jun 13 01:25:07 2011 Uli Fouquet ## $Id$ ## ## Copyright (C) 2011 Uli Fouquet ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## """ Convenience stuff for logging. """ import os import grok import logging from zope.interface import Interface, Attribute marker_ = object() class WAeUPLogger(object): _logger = None def __init__(self, loggername, filename, site=marker_, logdir=marker_, handlers=marker_, formatters=marker_, propagate=False, level=logging.DEBUG): self.loggername = loggername self.filename = filename self.site = site self.sitename = None self.logdir = logdir self.handlers = handlers self.formatters = formatters self.propagate = propagate self.level = level self._logger = None return @property def logger(self): if self._logger is not None: if '__app' in self._logger.name: if getattr(self.site, '__name__', None) is not None: self.setup() return self._logger self.setup() return self._logger def setup(self): if self.site is marker_: self.site = grok.getSite() if '%s' in self.loggername: name = getattr(self.site, '__name__', '__app') self.loggername = self.loggername % (name,) self.logger = logging.getLogger(self.loggername) self.update() return def update(self): if self.site is marker_: self.site = grok.getSite() if self.logdir is marker_: self.logdir = os.path.join(self.site['datacenter'].storage, 'logs') if not os.path.exists(self.logdir): os.mkdir(self.logdir) filename = os.path.join(self.logdir, self.filename) # Create a rotating file handler logger for datacenter. if self.handlers is marker_: self.handlers = [logging.handlers.RotatingFileHandler( filename, maxBytes=5*1024**1, backupCount=5)] if self.formatters is marker_: self.formatters = [logging.Formatter( '%(asctime)s - %(levelname)s - %(message)s')] self.logger.propagate = self.propagate self.logger.setLevel(self.level) for handler, formatter in map(lambda x, y: (x,y), self.handlers, self.formatters): handler.setFormatter(formatter) self.logger.addHandler(handler) return self.logger class ISiteLoggers(Interface): loggers = Attribute("A list or generator of registered WAeUPLoggers") def register(name, filename=None, site=None, **options): """Register a logger `name` which logs to `filename`. If `filename` is not given, logfile will be `name` with ``.log`` as filename extension. """ def unregister(name): """Unregister a once registered logger. """ class SiteLoggers(object): grok.implements(ISiteLoggers) @property def loggers(self): return self._loggers.values() def __init__(self): self._loggers = dict() def getLogger(self, filename): waeup_logger = self._loggers.get(filename, None) return waeup_logger.logger def register(self, loggername, filename=None, site=None, **kw): if loggername in self._loggers.keys(): raise KeyError('Logger "%s" exists already.' % loggername) self._loggers[loggername] = WAeUPLogger( loggername, filename=filename, site=site, **kw) return def unregister(self, name): if name in self._loggers.keys(): del self._loggers[name] return def keys(self): return self._loggers.keys() class ILogger(Interface): """A logger cares for setup, update and restarting of a Python logger. """ logger = Attribute("""A :class:`logging.Logger` instance""") def __init__(name, filename=None, site=None, **options): """Create a WAeUP logger instance. """ pass def setup(): """Create a Python :class:`logging.Logger` instance. The created logger is based on the params given by constructor. """ pass def update(**options): """Update the logger. Updates the logger respecting modified `options` and changed paths. """ class WAeUPLogger(object): grok.implements(ILogger) _logger = None def __init__(self, name, filename=None, site=None, **options): self.name = name self.filename = filename if filename is None: if '.' in name: name = name.rsplit('.', 1)[1] self.filename = "%s.log" % name self.site = site self.max_bytes = options.get('maxBytes', 5 * 1024 ** 2) self.backup_count = options.get('backupCount', 5) self.options = options return @property def logger(self): if self._needSetup(): self._setup() return logging.getLogger(self._loggername) def setup(self): return self._setup() def update(self, **options): self._logger = None # unset to be set up again on next access. # XXX: set options pass def _needSetup(self): if self._logger is None: return True if not '__app' in self._logger.name: return False if getattr(self.site, '__name__', None) is not None: return True return False def _removeHandlers(self): handlers = self._logger.handlers for handler in handlers: self._logger.removeHandler(handler) def _setup(self): if self.site is None: self.site = grok.getSite() self._loggername = self.name if not '.' in self._loggername: self._loggername = 'waeup.sirp.%s.%s' % ('%s', self._loggername) if '%s' in self._loggername: site_name = getattr(self.site, '__name__', '__app') if site_name is None: site_name = '__app' self._loggername = self._loggername % (site_name,) self._logger = logging.getLogger(self._loggername) return self._update() def _update(self): self._removeHandlers() # Remove any old handlers self._logdir = os.path.join(self.site['datacenter'].storage, 'logs') if not os.path.exists(self._logdir): os.mkdir(self._logdir) filename = os.path.join(self._logdir, self.filename) # Create a rotating file handler logger for datacenter. default_handler = logging.handlers.RotatingFileHandler( filename, maxBytes=self.max_bytes, backupCount=self.backup_count) self.handler = self.options.get('handler', default_handler) default_formatter = logging.Formatter( '%(asctime)s - %(levelname)s - %(message)s') formatter = self.options.get('formatter', default_formatter) self.handler.setFormatter(formatter) self._logger.addHandler(self.handler) self._logger.propagate = self.options.get('propagate', False) self._logger.setLevel(self.options.get('level', logging.DEBUG)) return self._logger #: A place where we store seen loggers. SiteLoggersRepository = dict() class SiteLoggersFinder(object): grok.provides(ISiteLoggers) def getLoggers(self, site=None): if site is None: site = grok.getSite() if site not in SiteLoggersRepository.keys(): SiteLoggersRepository[site] = SiteLoggers() return SiteLoggersRepository[site] grok.global_utility(SiteLoggersFinder, provides=ISiteLoggers)