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)
|