Mercurial > libervia-backend
annotate src/core/log.py @ 994:652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
- variable change logs behaviour, so far only level and colors are implemented
- configuration use log_[name], for example you can put log_level=debug in sat.conf (section [DEFAULT]) to see all levels
- environment variables use SAT_LOG_[NAME]: e.g. SAT_LOG_LEVEL=debug
- colors can be true, false or force to force colors even if stdout is not a tty
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 19 Apr 2014 20:11:23 +0200 |
parents | f51a1895275c |
children | b4af31a8a4f2 |
rev | line source |
---|---|
991 | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # SàT: a XMPP client | |
5 # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org) | |
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 published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (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 """High level logging functions""" | |
21 # XXX: this module use standard logging module when possible, but as SàT can work in different cases where logging is not the best choice (twisted, pyjamas, etc), it is necessary to have a dedicated module. In addition additional feature like environment variable and color are also managed. | |
22 | |
23 from sat.core.constants import Const as C | |
24 from sat.core import exceptions | |
25 | |
26 _backend = None | |
27 _loggers = {} | |
28 | |
29 | |
30 class Logger(object): | |
31 """ High level logging class """ | |
32 | |
33 def __init__(self, name): | |
34 self._name = name | |
35 | |
36 def debug(self, msg): | |
37 print msg | |
38 | |
39 def info(self, msg): | |
40 print msg | |
41 | |
42 def warning(self, msg): | |
43 print msg | |
44 | |
45 def error(self, msg): | |
46 print msg | |
47 | |
48 def critical(self, msg): | |
49 print msg | |
50 | |
51 | |
52 def _configureStdLogging(logging, level=None, colors=False, force_colors=False): | |
53 """Configure standard logging module | |
54 @param logging: standard logging module | |
55 @param colors: if True use ANSI colors to show log levels | |
56 @param force_colors: if True ANSI colors are used even if stdout is not a tty | |
57 """ | |
58 FORMAT = '%(message)s' | |
59 if level is None: | |
60 level = logging.DEBUG | |
61 import sys | |
62 with_color = colors & (sys.stdout.isatty() or force_colors) | |
63 if not colors and force_colors: | |
64 raise ValueError("force_colors can't be used if colors is False") | |
65 | |
66 class SatFormatter(logging.Formatter): | |
67 u"""Formatter which manage SàT specificities""" | |
68 | |
69 def __init__(self, fmt=None, datefmt=None): | |
70 super(SatFormatter, self).__init__(fmt, datefmt) | |
71 | |
72 def format(self, record): | |
73 s = super(SatFormatter, self).format(record) | |
74 if with_color: | |
75 if record.levelno == logging.DEBUG: | |
76 fmt = (C.ANSI_FG_CYAN, s, C.ANSI_RESET) | |
77 elif record.levelno == logging.WARNING: | |
78 fmt = (C.ANSI_FG_YELLOW, s, C.ANSI_RESET) | |
79 elif record.levelno == logging.ERROR: | |
80 fmt = (C.ANSI_FG_RED, | |
81 C.ANSI_BLINK, | |
82 r'/!\ ', | |
83 C.ANSI_BLINK_OFF, | |
84 s, | |
85 C.ANSI_RESET) | |
86 elif record.levelno == logging.CRITICAL: | |
87 fmt = (C.ANSI_BOLD, | |
88 C.ANSI_FG_RED, | |
89 'Guru Meditation ', | |
90 C.ANSI_NORMAL_WEIGHT, | |
91 s, | |
92 C.ANSI_RESET) | |
93 else: | |
94 fmt = s | |
95 s = ''.join(fmt) | |
96 | |
97 return s | |
98 | |
99 root_logger = logging.getLogger() | |
100 if len(root_logger.handlers) == 0: | |
101 hdlr = logging.StreamHandler() | |
102 formatter = SatFormatter(FORMAT) | |
103 hdlr.setFormatter(formatter) | |
104 root_logger.addHandler(hdlr) | |
105 root_logger.setLevel(level) | |
106 else: | |
107 root_logger.warning(u"Handler already set on root logger") | |
108 | |
994
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
109 def configure(backend=C.LOG_BACKEND_STANDARD, **options): |
991 | 110 """Configure logging bejaviour |
111 @param backend: can be: | |
112 C.LOG_BACKEND_STANDARD: use standard logging module | |
113 C.LOG_BACKEND_TWISTED: use twisted logging module (with standard logging observer) | |
114 C.LOG_BACKEND_BASIC: use a basic print based logging | |
115 """ | |
116 global _backend | |
117 if _backend is not None: | |
118 raise exceptions.InternalError("Logging can only be configured once") | |
119 _backend = backend | |
120 | |
992
f51a1895275c
core (log): twisted backend use logging methods instead of log.msg
Goffi <goffi@goffi.org>
parents:
991
diff
changeset
|
121 if backend in (C.LOG_BACKEND_TWISTED, C.LOG_BACKEND_STANDARD): |
f51a1895275c
core (log): twisted backend use logging methods instead of log.msg
Goffi <goffi@goffi.org>
parents:
991
diff
changeset
|
122 if backend == C.LOG_BACKEND_TWISTED: |
f51a1895275c
core (log): twisted backend use logging methods instead of log.msg
Goffi <goffi@goffi.org>
parents:
991
diff
changeset
|
123 from twisted.python import log |
f51a1895275c
core (log): twisted backend use logging methods instead of log.msg
Goffi <goffi@goffi.org>
parents:
991
diff
changeset
|
124 observer = log.PythonLoggingObserver() |
f51a1895275c
core (log): twisted backend use logging methods instead of log.msg
Goffi <goffi@goffi.org>
parents:
991
diff
changeset
|
125 observer.start() |
991 | 126 global getLogger |
127 global debug | |
128 global info | |
129 global warning | |
130 global error | |
131 global critical | |
132 import logging | |
994
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
133 _configureStdLogging(logging, **options) |
991 | 134 getLogger = logging.getLogger |
135 debug = logging.debug | |
136 info = logging.info | |
137 warning = logging.warning | |
138 error = logging.error | |
139 critical = logging.critical | |
140 | |
141 elif backend == C.LOG_BACKEND_BASIC: | |
142 pass | |
143 | |
144 else: | |
145 raise ValueError("unknown backend") | |
146 | |
994
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
147 def _parseOptions(options): |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
148 """Parse string options as given in conf or environment variable, and return expected python value |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
149 |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
150 @param options (dict): options with (key: name, value: string value) |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
151 """ |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
152 if 'colors' in options: |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
153 if options['colors'].lower() in ('1', 'true'): |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
154 options['colors'] = True |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
155 elif options['colors'] == 'force': |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
156 options['colors'] = True |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
157 options['force_colors'] = True |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
158 else: |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
159 options['colors'] = False |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
160 if 'level' in options: |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
161 level = options['level'].upper() |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
162 if level not in ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'): |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
163 level = 'INFO' |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
164 options['level'] = level |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
165 |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
166 def satConfigure(backend=C.LOG_BACKEND_TWISTED): |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
167 """Configure logging system for SàT, can be used by frontends |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
168 |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
169 logs conf is read in SàT conf, then in environment variables. It must be done before Memory init |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
170 """ |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
171 import ConfigParser |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
172 import os |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
173 to_get = (C.LOG_OPT_COLORS, C.LOG_OPT_LEVEL) |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
174 log_conf = {} |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
175 config = ConfigParser.SafeConfigParser() |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
176 config.read(C.CONFIG_FILES) |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
177 for opt_name, opt_default in to_get: |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
178 try: |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
179 log_conf[opt_name] = os.environ[''.join((C.ENV_PREFIX, C.LOG_OPT_PREFIX.upper(), opt_name.upper()))] |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
180 except KeyError: |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
181 try: |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
182 log_conf[opt_name] = config.get('DEFAULT', C.LOG_OPT_PREFIX + opt_name) |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
183 except ConfigParser.NoOptionError: |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
184 log_conf[opt_name] = opt_default |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
185 |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
186 _parseOptions(log_conf) |
652c01ca69b1
core (log): configuration and environment variables are now checked for log level and colors:
Goffi <goffi@goffi.org>
parents:
992
diff
changeset
|
187 configure(backend, **log_conf) |
991 | 188 |
189 def getLogger(name=C.LOG_BASE_LOGGER): | |
190 return _loggers.setdefault(name, Logger(name)) | |
191 | |
192 _root_logger = getLogger() | |
193 | |
194 def debug(msg): | |
195 _root_logger.debug(msg) | |
196 | |
197 def info(msg): | |
198 _root_logger.info(msg) | |
199 | |
200 def warning(msg): | |
201 _root_logger.warning(msg) | |
202 | |
203 def error(msg): | |
204 _root_logger.error(msg) | |
205 | |
206 def critical(msg): | |
207 _root_logger.critical(msg) |