Revision 2a2060ff lib/logger.py
b/lib/logger.py | ||
---|---|---|
23 | 23 |
|
24 | 24 |
This module abstracts the logging handling away from the rest of the |
25 | 25 |
Ganeti code. It offers some utility functions for easy logging. |
26 |
|
|
26 | 27 |
""" |
27 | 28 |
|
28 | 29 |
# pylint: disable-msg=W0603,C0103 |
... | ... | |
33 | 34 |
|
34 | 35 |
from ganeti import constants |
35 | 36 |
|
36 |
_program = '(unknown)' |
|
37 |
_errlog = None |
|
38 |
_inflog = None |
|
39 |
_dbglog = None |
|
40 |
_stdout = None |
|
41 |
_stderr = None |
|
42 |
_debug = False |
|
43 |
|
|
44 |
|
|
45 |
def _SetDestination(name, filename, stream=None): |
|
46 |
"""Configure the destination for a given logger |
|
47 |
|
|
48 |
This function configures the logging destination for a given loger. |
|
49 |
Parameters: |
|
50 |
- name: the logger name |
|
51 |
- filename: if not empty, log messages will be written (also) to this file |
|
52 |
- stream: if not none, log messages will be output (also) to this stream |
|
53 |
|
|
54 |
Returns: |
|
55 |
- the logger identified by the `name` argument |
|
56 |
""" |
|
57 |
ret = logging.getLogger(name) |
|
58 |
|
|
59 |
if filename: |
|
60 |
fmtr = logging.Formatter('%(asctime)s %(message)s') |
|
61 |
|
|
62 |
hdlr = logging.FileHandler(filename) |
|
63 |
hdlr.setFormatter(fmtr) |
|
64 |
ret.addHandler(hdlr) |
|
65 |
|
|
66 |
if stream: |
|
67 |
if name in ('error', 'info', 'debug'): |
|
68 |
fmtr = logging.Formatter('%(asctime)s %(message)s') |
|
69 |
else: |
|
70 |
fmtr = logging.Formatter('%(message)s') |
|
71 |
hdlr = logging.StreamHandler(stream) |
|
72 |
hdlr.setFormatter(fmtr) |
|
73 |
ret.addHandler(hdlr) |
|
74 |
|
|
75 |
ret.setLevel(logging.INFO) |
|
76 |
|
|
77 |
return ret |
|
78 | 37 |
|
38 |
def _CreateFileHandler(name): |
|
39 |
return logging.FileHandler(os.path.join(constants.LOG_DIR, name)) |
|
79 | 40 |
|
80 |
def _GenericSetup(program, errfile, inffile, dbgfile, |
|
81 |
twisted_workaround=False): |
|
82 |
"""Configure logging based on arguments |
|
83 | 41 |
|
84 |
Arguments: |
|
85 |
- name of program |
|
86 |
- error log filename |
|
87 |
- info log filename |
|
88 |
- debug log filename |
|
89 |
- twisted_workaround: if true, emit all messages to stderr |
|
90 |
""" |
|
91 |
global _program |
|
92 |
global _errlog |
|
93 |
global _inflog |
|
94 |
global _dbglog |
|
95 |
global _stdout |
|
96 |
global _stderr |
|
97 |
|
|
98 |
_program = program |
|
99 |
if twisted_workaround: |
|
100 |
_errlog = _SetDestination('error', None, sys.stderr) |
|
101 |
_inflog = _SetDestination('info', None, sys.stderr) |
|
102 |
_dbglog = _SetDestination('debug', None, sys.stderr) |
|
103 |
else: |
|
104 |
_errlog = _SetDestination('error', errfile) |
|
105 |
_inflog = _SetDestination('info', inffile) |
|
106 |
_dbglog = _SetDestination('debug', dbgfile) |
|
107 |
|
|
108 |
_stdout = _SetDestination('user', None, sys.stdout) |
|
109 |
_stderr = _SetDestination('stderr', None, sys.stderr) |
|
110 |
|
|
111 |
|
|
112 |
def SetupLogging(twisted_workaround=False, debug=False, program='ganeti'): |
|
42 |
def SetupLogging(program='ganeti', debug=False): |
|
113 | 43 |
"""Setup logging for ganeti |
114 | 44 |
|
115 | 45 |
On failure, a check is made whether process is run by root or not, |
116 | 46 |
and an appropriate error message is printed on stderr, then process |
117 | 47 |
exits. |
118 | 48 |
|
119 |
This function is just a wraper over `_GenericSetup()` using specific |
|
120 |
arguments. |
|
121 |
|
|
122 |
Parameter: |
|
123 |
twisted_workaround: passed to `_GenericSetup()` |
|
49 |
Args: |
|
50 |
debug: Whether to enable verbose logging |
|
51 |
program: Program name |
|
124 | 52 |
|
125 | 53 |
""" |
126 |
try: |
|
127 |
_GenericSetup(program, |
|
128 |
os.path.join(constants.LOG_DIR, "errors"), |
|
129 |
os.path.join(constants.LOG_DIR, "info"), |
|
130 |
os.path.join(constants.LOG_DIR, "debug"), |
|
131 |
twisted_workaround) |
|
132 |
except IOError: |
|
133 |
# The major reason to end up here is that we're being run as a |
|
134 |
# non-root user. We might also get here if xen has not been |
|
135 |
# installed properly. This is not the correct place to enforce |
|
136 |
# being run by root; nevertheless, here makes sense because here |
|
137 |
# is where we first notice it. |
|
138 |
if os.getuid() != 0: |
|
139 |
sys.stderr.write('This program must be run by the superuser.\n') |
|
140 |
else: |
|
141 |
sys.stderr.write('Unable to open log files. Incomplete system?\n') |
|
142 |
|
|
143 |
sys.exit(2) |
|
144 |
|
|
145 |
global _debug |
|
146 |
_debug = debug |
|
147 |
|
|
148 |
|
|
149 |
def _WriteEntry(log, txt): |
|
150 |
""" |
|
151 |
Write a message to a given log. |
|
152 |
Splits multi-line messages up into a series of log writes, to |
|
153 |
keep consistent format on lines in file. |
|
54 |
fmt = "%(asctime)s " + program + ": %(message)s" |
|
55 |
formatter = logging.Formatter(fmt) |
|
154 | 56 |
|
155 |
Parameters:
|
|
156 |
- log: the destination log
|
|
157 |
- txt: the message
|
|
57 |
info_file = _CreateFileHandler("info")
|
|
58 |
info_file.setLevel(logging.INFO)
|
|
59 |
info_file.setFormatter(formatter)
|
|
158 | 60 |
|
159 |
""" |
|
160 |
if log is None: |
|
161 |
sys.stderr.write("Logging system not initialized while processing" |
|
162 |
" message:\n") |
|
163 |
sys.stderr.write("%s\n" % txt) |
|
164 |
return |
|
61 |
errors_file = _CreateFileHandler("errors") |
|
62 |
errors_file.setLevel(logging.ERROR) |
|
63 |
errors_file.setFormatter(formatter) |
|
165 | 64 |
|
166 |
lines = txt.split('\n') |
|
65 |
debug_file = _CreateFileHandler("debug") |
|
66 |
debug_file.setLevel(logging.DEBUG) |
|
67 |
debug_file.setFormatter(formatter) |
|
167 | 68 |
|
168 |
spaces = ' ' * len(_program) + '| ' |
|
69 |
stderr_file = logging.StreamHandler() |
|
70 |
if debug: |
|
71 |
stderr_file.setLevel(logging.NOTSET) |
|
72 |
else: |
|
73 |
stderr_file.setLevel(logging.ERROR) |
|
169 | 74 |
|
170 |
lines = ([ _program + ': ' + lines[0] ] + |
|
171 |
map(lambda a: spaces + a, lines[1:])) |
|
75 |
root_logger = logging.getLogger("") |
|
76 |
root_logger.setLevel(logging.NOTSET) |
|
77 |
root_logger.addHandler(info_file) |
|
78 |
root_logger.addHandler(errors_file) |
|
79 |
root_logger.addHandler(debug_file) |
|
80 |
root_logger.addHandler(stderr_file) |
|
172 | 81 |
|
173 |
for line in lines: |
|
174 |
log.log(logging.INFO, line) |
|
82 |
|
|
83 |
# Backwards compatibility |
|
84 |
Error = logging.error |
|
85 |
Info = logging.info |
|
86 |
Debug = logging.debug |
|
175 | 87 |
|
176 | 88 |
|
177 | 89 |
def ToStdout(txt): |
... | ... | |
194 | 106 |
""" |
195 | 107 |
sys.stderr.write(txt + '\n') |
196 | 108 |
sys.stderr.flush() |
197 |
|
|
198 |
|
|
199 |
def Error(txt): |
|
200 |
"""Write a message to our error log |
|
201 |
|
|
202 |
Parameters: |
|
203 |
- dbg: if true, the message will also be output to stderr |
|
204 |
- txt: the log message |
|
205 |
|
|
206 |
""" |
|
207 |
_WriteEntry(_errlog, txt) |
|
208 |
sys.stderr.write(txt + '\n') |
|
209 |
|
|
210 |
|
|
211 |
def Info(txt): |
|
212 |
"""Write a message to our general messages log |
|
213 |
|
|
214 |
If the global debug flag is true, the log message will also be |
|
215 |
output to stderr. |
|
216 |
|
|
217 |
Parameters: |
|
218 |
- txt: the log message |
|
219 |
|
|
220 |
""" |
|
221 |
_WriteEntry(_inflog, txt) |
|
222 |
if _debug: |
|
223 |
_WriteEntry(_stderr, txt) |
|
224 |
|
|
225 |
|
|
226 |
def Debug(txt): |
|
227 |
"""Write a message to the debug log |
|
228 |
|
|
229 |
If the global debug flag is true, the log message will also be |
|
230 |
output to stderr. |
|
231 |
|
|
232 |
Parameters: |
|
233 |
- txt: the log message |
|
234 |
|
|
235 |
""" |
|
236 |
_WriteEntry(_dbglog, txt) |
|
237 |
if _debug: |
|
238 |
_WriteEntry(_stderr, txt) |
Also available in: Unified diff