Merge remote-tracking branch 'odoo/7.0' into 7.0
[odoo/odoo.git] / openerp / loglevels.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 import sys
23 import logging
24
25 LOG_NOTSET = 'notset'
26 LOG_DEBUG = 'debug'
27 LOG_TEST = 'test'
28 LOG_INFO = 'info'
29 LOG_WARNING = 'warn'
30 LOG_ERROR = 'error'
31 LOG_CRITICAL = 'critical'
32
33 logging.TEST = logging.INFO - 5
34 logging.addLevelName(logging.TEST, 'TEST')
35
36 _logger = logging.getLogger(__name__)
37
38 class Logger(object):
39     def __init__(self):
40         _logger.warning(
41             "The netsvc.Logger API shouldn't be used anymore, please "
42             "use the standard `logging.getLogger` API instead.")
43         super(Logger, self).__init__()
44
45     def notifyChannel(self, name, level, msg):
46         _logger.warning(
47             "notifyChannel API shouldn't be used anymore, please use "
48             "the standard `logging` module instead.")
49         from service.web_services import common
50
51         log = logging.getLogger(__name__ + '.deprecated.' + ustr(name))
52
53         if level in [LOG_TEST] and not hasattr(log, level):
54             fct = lambda msg, *args, **kwargs: log.log(getattr(logging, level.upper()), msg, *args, **kwargs)
55             setattr(log, level, fct)
56
57
58         level_method = getattr(log, level)
59
60         if isinstance(msg, Exception):
61             msg = exception_to_unicode(msg)
62
63         try:
64             msg = ustr(msg).strip()
65             if level in (LOG_ERROR, LOG_CRITICAL): # and tools.config.get_misc('debug','env_info',False):
66                 msg = common().exp_get_server_environment() + "\n" + msg
67
68             result = msg.split('\n')
69         except UnicodeDecodeError:
70             result = msg.strip().split('\n')
71         try:
72             if len(result)>1:
73                 for idx, s in enumerate(result):
74                     level_method('[%02d]: %s' % (idx+1, s,))
75             elif result:
76                 level_method(result[0])
77         except IOError:
78             # TODO: perhaps reset the logger streams?
79             #if logrotate closes our files, we end up here..
80             pass
81         except Exception:
82             # better ignore the exception and carry on..
83             pass
84
85     def set_loglevel(self, level, logger=None):
86         if logger is not None:
87             log = logging.getLogger(str(logger))
88         else:
89             log = logging.getLogger()
90         log.setLevel(logging.INFO) # make sure next msg is printed
91         log.info("Log level changed to %s" % logging.getLevelName(level))
92         log.setLevel(level)
93
94     def shutdown(self):
95         logging.shutdown()
96
97 # TODO get_encodings, ustr and exception_to_unicode were originally from tools.misc.
98 # There are here until we refactor tools so that this module doesn't depends on tools.
99
100 def get_encodings(hint_encoding='utf-8'):
101     fallbacks = {
102         'latin1': 'latin9',
103         'iso-8859-1': 'iso8859-15',
104         'cp1252': '1252',
105     }
106     if hint_encoding:
107         yield hint_encoding
108         if hint_encoding.lower() in fallbacks:
109             yield fallbacks[hint_encoding.lower()]
110
111     # some defaults (also taking care of pure ASCII)
112     for charset in ['utf8','latin1']:
113         if not hint_encoding or (charset.lower() != hint_encoding.lower()):
114             yield charset
115
116     from locale import getpreferredencoding
117     prefenc = getpreferredencoding()
118     if prefenc and prefenc.lower() != 'utf-8':
119         yield prefenc
120         prefenc = fallbacks.get(prefenc.lower())
121         if prefenc:
122             yield prefenc
123
124 def ustr(value, hint_encoding='utf-8', errors='strict'):
125     """This method is similar to the builtin `unicode`, except
126     that it may try multiple encodings to find one that works
127     for decoding `value`, and defaults to 'utf-8' first.
128
129     :param: value: the value to convert
130     :param: hint_encoding: an optional encoding that was detecte
131         upstream and should be tried first to decode ``value``.
132     :param str errors: optional `errors` flag to pass to the unicode
133         built-in to indicate how illegal character values should be
134         treated when converting a string: 'strict', 'ignore' or 'replace'
135         (see ``unicode()`` constructor).
136         Passing anything other than 'strict' means that the first
137         encoding tried will be used, even if it's not the correct
138         one to use, so be careful! Ignored if value is not a string/unicode.
139     :raise: UnicodeError if value cannot be coerced to unicode
140     :return: unicode string representing the given value
141     """
142     if isinstance(value, Exception):
143         return exception_to_unicode(value)
144
145     if isinstance(value, unicode):
146         return value
147
148     if not isinstance(value, basestring):
149         try:
150             return unicode(value)
151         except Exception:
152             raise UnicodeError('unable to convert %r' % (value,))
153
154     for ln in get_encodings(hint_encoding):
155         try:
156             return unicode(value, ln, errors=errors)
157         except Exception:
158             pass
159     raise UnicodeError('unable to convert %r' % (value,))
160
161
162 def exception_to_unicode(e):
163     if (sys.version_info[:2] < (2,6)) and hasattr(e, 'message'):
164         return ustr(e.message)
165     if hasattr(e, 'args'):
166         return "\n".join((ustr(a) for a in e.args))
167     try:
168         return unicode(e)
169     except Exception:
170         return u"Unknown message"
171
172 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: