source: main/waeup.sirp/trunk/src/waeup/sirp/utils/logger.py @ 6371

Last change on this file since 6371 was 6371, checked in by uli, 13 years ago

Add some logging-related stuff. This is still experimental and yet hairy stuff. Don't actually use it for now in other components.

File size: 9.9 KB
Line 
1##
2## logging.py
3## Login : <uli@pu.smp.net>
4## Started on  Mon Jun 13 01:25:07 2011 Uli Fouquet
5## $Id$
6##
7## Copyright (C) 2011 Uli Fouquet
8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
12##
13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
22"""
23Convenience stuff for logging.
24"""
25import os
26import grok
27import logging
28
29marker_ = object()
30
31def setup_logger(loggername, filename, site=marker_, logdir=marker_,
32                 handler=marker_, formatter=marker_, propagate=False,
33                 level=logging.DEBUG):
34    """Create a logger.
35    """
36    if site is marker_:
37        site = grok.getSite()
38    if '%s' in loggername:
39        name = getattr(site, '__name__', 'app')
40        loggername = loggername % (name,)
41    logger = logging.getLogger(loggername)
42    update_logger(logger, filename, site=site, logdir=logdir, handler=handler,
43                  formatter=formatter, propagate=propagate, level=level)
44    return logger, loggername
45
46def update_logger(logger, filename, site=marker_, logdir=marker_,
47                  handler=marker_, formatter=marker_, propagate=False,
48                  level=logging.DEBUG):
49    if site is marker_:
50        site = grok.getSite()
51    if logdir is marker_:
52        logdir = os.path.join(site['datacenter'].storage, 'logs')
53    if not os.path.exists(logdir):
54        os.mkdir(logdir)
55    filename = os.path.join(logdir, filename)
56
57    # Create a rotating file handler logger for datacenter.
58    if handler is marker_:
59        handler = logging.handlers.RotatingFileHandler(
60            filename, maxBytes=5*1024**1, backupCount=5)
61    if formatter is marker_:
62        formatter = logging.Formatter(
63            '%(asctime)s - %(levelname)s - %(message)s')
64    handler.setFormatter(formatter)
65
66    logger.propagate = propagate
67    logger.setLevel(level)
68    logger.addHandler(handler)
69    return logger
70
71def get_logger(loggername, filename, site=marker_, **kw):
72    """Get a logger.
73    """
74    if '%s' in loggername:
75        if site is marker_:
76            site = grok.getSite()
77        loggername = loggername % (
78            getattr(site, '__name__', 'app'))
79    logger = logging.getLogger(loggername)
80    if not logger.handlers:
81        kw.update(dict(site=site))
82        logger, loggername = setup_logger(
83            loggername, filename, **kw)
84    return logger
85
86class WAeUPLogger(object):
87
88    _logger = None
89
90    def __init__(self, loggername, filename, site=marker_, logdir=marker_,
91                 handlers=marker_, formatters=marker_, propagate=False,
92                 level=logging.DEBUG):
93        self.loggername = loggername
94        self.filename = filename
95        self.site = site
96        self.sitename = None
97        self.logdir = logdir
98        self.handlers = handlers
99        self.formatters = formatters
100        self.propagate = propagate
101        self.level = level
102        self._logger = None
103        return
104
105
106    @property
107    def logger(self):
108        if self._logger is not None:
109            if '__app' in self._logger.name:
110                if getattr(self.site, '__name__', None) is not None:
111                    self.setup()
112            return self._logger
113        self.setup()
114        return self._logger
115
116    def setup(self):
117        if self.site is marker_:
118            self.site = grok.getSite()
119        if '%s' in loggername:
120            name = getattr(site, '__name__', '__app')
121            loggername = loggername % (name,)
122        self.logger = logging.getLogger(loggername)
123        self.update()
124        return
125
126    def update(self):
127        if self.site is marker_:
128            self.site = grok.getSite()
129        if self.logdir is marker_:
130            self.logdir = os.path.join(site['datacenter'].storage, 'logs')
131        if not os.path.exists(self.logdir):
132            os.mkdir(self.logdir)
133        filename = os.path.join(self.logdir, self.filename)
134
135        # Create a rotating file handler logger for datacenter.
136        if self.handlers is marker_:
137            self.handlers = [logging.handlers.RotatingFileHandler(
138                    filename, maxBytes=5*1024**1, backupCount=5)]
139        if formatters is marker_:
140            formatters = [logging.Formatter(
141                    '%(asctime)s - %(levelname)s - %(message)s')]
142
143        self.logger.propagate = self.propagate
144        self.logger.setLevel(self.level)
145
146        for handler, formatter in map(lambda x, y: (x,y),
147                                     self.handlers, self.formatters):
148            handler.setFormatter(formatter)
149            self.logger.addHandler(handler)
150        return self.logger
151
152
153from zope import schema
154from zope.interface import Interface, Attribute
155
156class ISiteLoggers(Interface):
157
158    loggers = Attribute("A list or generator of registered WAeUPLoggers")
159
160    def register(name, filename=None, site=None, **options):
161        """Register a logger `name` which logs to `filename`.
162
163        If `filename` is not given, logfile will be `name` with
164        ``.log`` as filename extension.
165        """
166
167    def unregister(name):
168        """Unregister a once registered logger.
169        """
170
171class SiteLoggers(object):
172
173    grok.implements(ISiteLoggers)
174
175    @property
176    def loggers(self):
177        return self._loggers.values()
178
179    def __init__(self):
180        self._loggers = dict()
181
182    def getLogger(self, filename):
183        waeup_logger = self._loggers.get(filename, None)
184        return waeup_logger.logger
185
186    def register(self, filename, loggername=None, site=None, **kw):
187        if filename in self._loggers.keys():
188            raise KeyError('Logger "%s" exists already.' % filename)
189        if loggername is None:
190            loggername = filename
191            if '.' in filename:
192                loggername = filename.rplit('.', 1)[0]
193            loggername = 'waeup.sirp.%s.%s' % ('%s', loggername)
194        self._loggers[filename] = WAeUPLogger(
195            loggername, filename=filename, site=site, **kw)
196        return
197
198    def unregister(self, name):
199        if name in self._loggers.keys():
200            del self._loggers[name]
201        return
202
203class ILogger(Interface):
204    """A logger cares for setup, update and restarting of a Python logger.
205    """
206
207    logger = Attribute("""A :class:`logging.Logger` instance""")
208
209
210    def __init__(name, filename=None, site=None, **options):
211        """Create a WAeUP logger instance.
212        """
213        pass
214
215    def setup():
216        """Create a Python :class:`logging.Logger` instance.
217
218        The created logger is based on the params given by constructor.
219        """
220        pass
221
222    def update(**options):
223        """Update the logger.
224
225        Updates the logger respecting modified `options` and changed
226        paths.
227        """
228
229class WAeUPLogger(object):
230
231    grok.implements(ILogger)
232
233    _logger = None
234
235    def __init__(self, name, filename=None, site=None, **options):
236        self.name = name
237        self.filename = filename
238        if filename is None:
239            if '.' in name:
240                name = name.rsplit('.', 1)[1]
241            self.filename = "%s.log" % name
242        self.site = site
243        self.max_bytes = options.get('maxBytes', 5 * 1024 ** 2)
244        self.backup_count = options.get('backupCount', 5)
245        self.options = options
246        return
247
248    @property
249    def logger(self):
250        if self._needSetup():
251            self._setup()
252        return logging.getLogger(self._loggername)
253
254    def setup(self):
255        return self._setup()
256
257    def update(self, **options):
258        self._logger = None # unset to be set up again on next access.
259        # XXX: set options
260        pass
261
262    def _needSetup(self):
263        if self._logger is None:
264            return True
265        if not '__app' in self._logger.name:
266            return False
267        if getattr(self.site, '__name__', None) is not None:
268            return True
269        return False
270
271    def _removeHandlers(self):
272        handlers = self._logger.handlers
273        for handler in handlers:
274            self._logger.removeHandler(handler)
275
276    def _setup(self):
277        if self.site is None:
278            self.site = grok.getSite()
279        self._loggername = self.name
280        if not '.' in self._loggername:
281            self._loggername = 'waeup.sirp.%s.%s' % ('%s', self._loggername)
282        if '%s' in self._loggername:
283            site_name = getattr(self.site, '__name__', '__app')
284            if site_name is None:
285                site_name = '__app'
286            self._loggername = self._loggername % (site_name,)
287        self._logger = logging.getLogger(self._loggername)
288        return self._update()
289
290    def _update(self):
291        self._removeHandlers() # Remove any old handlers
292        self._logdir = os.path.join(self.site['datacenter'].storage, 'logs')
293        if not os.path.exists(self._logdir):
294            os.mkdir(self._logdir)
295        filename = os.path.join(self._logdir, self.filename)
296
297        # Create a rotating file handler logger for datacenter.
298        default_handler = logging.handlers.RotatingFileHandler(
299            filename, maxBytes=self.max_bytes, backupCount=self.backup_count)
300        self.handler = self.options.get('handler', default_handler)
301
302        default_formatter = logging.Formatter(
303            '%(asctime)s - %(levelname)s - %(message)s')
304        formatter = self.options.get('formatter', default_formatter)
305        self.handler.setFormatter(formatter)
306
307        self._logger.addHandler(self.handler)
308        self._logger.propagate = self.options.get('propagate', False)
309        self._logger.setLevel(self.options.get('level', logging.DEBUG))
310        return self._logger
Note: See TracBrowser for help on using the repository browser.