| 1 | # This program is free software; you can redistribute it and/or modify it under |
|---|
| 2 | # the terms of the GNU General Public License as published by the Free Software |
|---|
| 3 | # Foundation; either version 2 of the License, or (at your option) any later |
|---|
| 4 | # version. |
|---|
| 5 | # |
|---|
| 6 | # This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|---|
| 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
|---|
| 9 | # |
|---|
| 10 | # You should have received a copy of the GNU General Public License along with |
|---|
| 11 | # this program; if not, write to the Free Software Foundation, Inc., |
|---|
| 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 13 | """ Copyright (c) 2002-2003 LOGILAB S.A. (Paris, FRANCE). |
|---|
| 14 | http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|---|
| 15 | |
|---|
| 16 | Define a logger interface and two concrete loggers : one which prints |
|---|
| 17 | everything on stdout, the other using syslog. |
|---|
| 18 | """ |
|---|
| 19 | |
|---|
| 20 | from warnings import warn |
|---|
| 21 | warn('logger module is deprecated and will disappear in a near release. \ |
|---|
| 22 | use logging module instead.', |
|---|
| 23 | DeprecationWarning, stacklevel=1) |
|---|
| 24 | |
|---|
| 25 | __revision__ = "$Id: logger.py,v 1.18 2006-02-03 14:17:42 adim Exp $" |
|---|
| 26 | |
|---|
| 27 | |
|---|
| 28 | import sys |
|---|
| 29 | import traceback |
|---|
| 30 | import time |
|---|
| 31 | |
|---|
| 32 | |
|---|
| 33 | LOG_EMERG = 0 |
|---|
| 34 | LOG_ALERT = 1 |
|---|
| 35 | LOG_CRIT = 2 |
|---|
| 36 | LOG_ERR = 3 |
|---|
| 37 | LOG_WARN = 4 |
|---|
| 38 | LOG_NOTICE = 5 |
|---|
| 39 | LOG_INFO = 6 |
|---|
| 40 | LOG_DEBUG = 7 |
|---|
| 41 | |
|---|
| 42 | INDICATORS = ['emergency', 'alert', 'critical', 'error', |
|---|
| 43 | 'warning', 'notice', 'info', 'debug'] |
|---|
| 44 | |
|---|
| 45 | |
|---|
| 46 | def make_logger(method='print', threshold=LOG_DEBUG, sid=None, output=None): |
|---|
| 47 | """return a logger for the given method |
|---|
| 48 | |
|---|
| 49 | known methods are 'print', 'eprint' and syslog' |
|---|
| 50 | """ |
|---|
| 51 | if method == 'print': |
|---|
| 52 | if output is None: |
|---|
| 53 | output = sys.stdout |
|---|
| 54 | return PrintLogger(threshold, output, sid=sid) |
|---|
| 55 | elif method == 'eprint': |
|---|
| 56 | return PrintLogger(threshold, sys.stderr, sid=sid) |
|---|
| 57 | elif method == 'syslog': |
|---|
| 58 | return SysLogger(threshold, sid) |
|---|
| 59 | elif method == 'file': |
|---|
| 60 | if not output: |
|---|
| 61 | raise ValueError('No logfile specified') |
|---|
| 62 | else: |
|---|
| 63 | logfile = open(output, 'a') |
|---|
| 64 | return PrintLogger(threshold, logfile, sid=sid) |
|---|
| 65 | else: |
|---|
| 66 | raise ValueError('Unknown logger method: %r' % method) |
|---|
| 67 | |
|---|
| 68 | |
|---|
| 69 | class AbstractLogger: |
|---|
| 70 | """logger interface. |
|---|
| 71 | Priorities allow to filter on the importance of events |
|---|
| 72 | An event gets logged if it's priority is lower than the threshold""" |
|---|
| 73 | |
|---|
| 74 | def __init__(self, threshold=LOG_DEBUG, priority_indicator=1): |
|---|
| 75 | self.threshold = threshold |
|---|
| 76 | self.priority_indicator = priority_indicator |
|---|
| 77 | |
|---|
| 78 | def log(self, priority=LOG_DEBUG, message='', substs=None): |
|---|
| 79 | """log a message with priority <priority> |
|---|
| 80 | substs are optional substrings |
|---|
| 81 | """ |
|---|
| 82 | #print 'LOG', self, priority, self.threshold, message |
|---|
| 83 | if priority <= self.threshold : |
|---|
| 84 | if substs is not None: |
|---|
| 85 | message = message % substs |
|---|
| 86 | if self.priority_indicator: |
|---|
| 87 | message = '[%s] %s' % (INDICATORS[priority], message) |
|---|
| 88 | self._writelog(priority, message) |
|---|
| 89 | |
|---|
| 90 | def _writelog(self, priority, message): |
|---|
| 91 | """Override this method in concrete class """ |
|---|
| 92 | raise NotImplementedError() |
|---|
| 93 | |
|---|
| 94 | def log_traceback(self, priority=LOG_ERR, tb_info=None): |
|---|
| 95 | """log traceback information with priority <priority> |
|---|
| 96 | """ |
|---|
| 97 | assert tb_info is not None |
|---|
| 98 | e_type, value, tbck = tb_info |
|---|
| 99 | stacktb = traceback.extract_tb(tbck) |
|---|
| 100 | l = ['Traceback (most recent call last):'] |
|---|
| 101 | for stackentry in stacktb : |
|---|
| 102 | if stackentry[3]: |
|---|
| 103 | plus = '\n %s' % stackentry[3] |
|---|
| 104 | else: |
|---|
| 105 | plus = '' |
|---|
| 106 | l.append('filename="%s" line_number="%s" function_name="%s"%s' % |
|---|
| 107 | (stackentry[0], stackentry[1], stackentry[2], plus)) |
|---|
| 108 | try: |
|---|
| 109 | l.append(str(e_type) + ': ' + value.__str__()) |
|---|
| 110 | except UnicodeError: |
|---|
| 111 | l.append(str(e_type) + ' (message can\'t be displayed)') |
|---|
| 112 | |
|---|
| 113 | self.log(priority, '\n'.join(l)) |
|---|
| 114 | |
|---|
| 115 | |
|---|
| 116 | class PrintLogger(AbstractLogger): |
|---|
| 117 | """logger implementation |
|---|
| 118 | |
|---|
| 119 | log everything to a file, using the standard output by default |
|---|
| 120 | """ |
|---|
| 121 | |
|---|
| 122 | def __init__(self, threshold, output=sys.stdout, sid=None, |
|---|
| 123 | encoding='UTF-8'): |
|---|
| 124 | AbstractLogger.__init__(self, threshold) |
|---|
| 125 | self.output = output |
|---|
| 126 | self.sid = sid |
|---|
| 127 | self.encoding = encoding |
|---|
| 128 | |
|---|
| 129 | def _writelog(self, priority, message): |
|---|
| 130 | """overridden from AbstractLogger""" |
|---|
| 131 | if isinstance(message, unicode): |
|---|
| 132 | message = message.encode(self.encoding, 'replace') |
|---|
| 133 | if self.sid is not None: |
|---|
| 134 | self.output.write('[%s] [%s] %s\n' % (time.asctime(), self.sid, |
|---|
| 135 | message)) |
|---|
| 136 | else: |
|---|
| 137 | self.output.write('[%s] %s\n' % (time.asctime(), message)) |
|---|
| 138 | self.output.flush() |
|---|
| 139 | |
|---|
| 140 | class SysLogger(AbstractLogger): |
|---|
| 141 | """ logger implementation |
|---|
| 142 | |
|---|
| 143 | log everything to syslog daemon |
|---|
| 144 | use the LOCAL_7 facility |
|---|
| 145 | """ |
|---|
| 146 | |
|---|
| 147 | def __init__(self, threshold, sid=None, encoding='UTF-8'): |
|---|
| 148 | import syslog |
|---|
| 149 | AbstractLogger.__init__(self, threshold) |
|---|
| 150 | if sid is None: |
|---|
| 151 | sid = 'syslog' |
|---|
| 152 | self.encoding = encoding |
|---|
| 153 | syslog.openlog(sid, syslog.LOG_PID) |
|---|
| 154 | |
|---|
| 155 | def _writelog(self, priority, message): |
|---|
| 156 | """overridden from AbstractLogger""" |
|---|
| 157 | import syslog |
|---|
| 158 | if isinstance(message, unicode): |
|---|
| 159 | message = message.encode(self.encoding, 'replace') |
|---|
| 160 | syslog.syslog(priority | syslog.LOG_LOCAL7, message) |
|---|