Revision 1ae4c5a1 lib/utils/__init__.py
b/lib/utils/__init__.py | ||
---|---|---|
42 | 42 |
import fcntl |
43 | 43 |
import resource |
44 | 44 |
import logging |
45 |
import logging.handlers |
|
46 | 45 |
import signal |
47 | 46 |
import OpenSSL |
48 | 47 |
import datetime |
... | ... | |
59 | 58 |
from ganeti.utils.retry import * # pylint: disable-msg=W0401 |
60 | 59 |
from ganeti.utils.text import * # pylint: disable-msg=W0401 |
61 | 60 |
from ganeti.utils.mlock import * # pylint: disable-msg=W0401 |
61 |
from ganeti.utils.log import * # pylint: disable-msg=W0401 |
|
62 | 62 |
|
63 | 63 |
_locksheld = [] |
64 | 64 |
|
... | ... | |
2276 | 2276 |
return float(seconds) + (float(microseconds) * 0.000001) |
2277 | 2277 |
|
2278 | 2278 |
|
2279 |
class LogFileHandler(logging.FileHandler): |
|
2280 |
"""Log handler that doesn't fallback to stderr. |
|
2281 |
|
|
2282 |
When an error occurs while writing on the logfile, logging.FileHandler tries |
|
2283 |
to log on stderr. This doesn't work in ganeti since stderr is redirected to |
|
2284 |
the logfile. This class avoids failures reporting errors to /dev/console. |
|
2285 |
|
|
2286 |
""" |
|
2287 |
def __init__(self, filename, mode="a", encoding=None): |
|
2288 |
"""Open the specified file and use it as the stream for logging. |
|
2289 |
|
|
2290 |
Also open /dev/console to report errors while logging. |
|
2291 |
|
|
2292 |
""" |
|
2293 |
logging.FileHandler.__init__(self, filename, mode, encoding) |
|
2294 |
self.console = open(constants.DEV_CONSOLE, "a") |
|
2295 |
|
|
2296 |
def handleError(self, record): # pylint: disable-msg=C0103 |
|
2297 |
"""Handle errors which occur during an emit() call. |
|
2298 |
|
|
2299 |
Try to handle errors with FileHandler method, if it fails write to |
|
2300 |
/dev/console. |
|
2301 |
|
|
2302 |
""" |
|
2303 |
try: |
|
2304 |
logging.FileHandler.handleError(self, record) |
|
2305 |
except Exception: # pylint: disable-msg=W0703 |
|
2306 |
try: |
|
2307 |
self.console.write("Cannot log message:\n%s\n" % self.format(record)) |
|
2308 |
except Exception: # pylint: disable-msg=W0703 |
|
2309 |
# Log handler tried everything it could, now just give up |
|
2310 |
pass |
|
2311 |
|
|
2312 |
|
|
2313 |
def SetupLogging(logfile, debug=0, stderr_logging=False, program="", |
|
2314 |
multithreaded=False, syslog=constants.SYSLOG_USAGE, |
|
2315 |
console_logging=False): |
|
2316 |
"""Configures the logging module. |
|
2317 |
|
|
2318 |
@type logfile: str |
|
2319 |
@param logfile: the filename to which we should log |
|
2320 |
@type debug: integer |
|
2321 |
@param debug: if greater than zero, enable debug messages, otherwise |
|
2322 |
only those at C{INFO} and above level |
|
2323 |
@type stderr_logging: boolean |
|
2324 |
@param stderr_logging: whether we should also log to the standard error |
|
2325 |
@type program: str |
|
2326 |
@param program: the name under which we should log messages |
|
2327 |
@type multithreaded: boolean |
|
2328 |
@param multithreaded: if True, will add the thread name to the log file |
|
2329 |
@type syslog: string |
|
2330 |
@param syslog: one of 'no', 'yes', 'only': |
|
2331 |
- if no, syslog is not used |
|
2332 |
- if yes, syslog is used (in addition to file-logging) |
|
2333 |
- if only, only syslog is used |
|
2334 |
@type console_logging: boolean |
|
2335 |
@param console_logging: if True, will use a FileHandler which falls back to |
|
2336 |
the system console if logging fails |
|
2337 |
@raise EnvironmentError: if we can't open the log file and |
|
2338 |
syslog/stderr logging is disabled |
|
2339 |
|
|
2340 |
""" |
|
2341 |
fmt = "%(asctime)s: " + program + " pid=%(process)d" |
|
2342 |
sft = program + "[%(process)d]:" |
|
2343 |
if multithreaded: |
|
2344 |
fmt += "/%(threadName)s" |
|
2345 |
sft += " (%(threadName)s)" |
|
2346 |
if debug: |
|
2347 |
fmt += " %(module)s:%(lineno)s" |
|
2348 |
# no debug info for syslog loggers |
|
2349 |
fmt += " %(levelname)s %(message)s" |
|
2350 |
# yes, we do want the textual level, as remote syslog will probably |
|
2351 |
# lose the error level, and it's easier to grep for it |
|
2352 |
sft += " %(levelname)s %(message)s" |
|
2353 |
formatter = logging.Formatter(fmt) |
|
2354 |
sys_fmt = logging.Formatter(sft) |
|
2355 |
|
|
2356 |
root_logger = logging.getLogger("") |
|
2357 |
root_logger.setLevel(logging.NOTSET) |
|
2358 |
|
|
2359 |
# Remove all previously setup handlers |
|
2360 |
for handler in root_logger.handlers: |
|
2361 |
handler.close() |
|
2362 |
root_logger.removeHandler(handler) |
|
2363 |
|
|
2364 |
if stderr_logging: |
|
2365 |
stderr_handler = logging.StreamHandler() |
|
2366 |
stderr_handler.setFormatter(formatter) |
|
2367 |
if debug: |
|
2368 |
stderr_handler.setLevel(logging.NOTSET) |
|
2369 |
else: |
|
2370 |
stderr_handler.setLevel(logging.CRITICAL) |
|
2371 |
root_logger.addHandler(stderr_handler) |
|
2372 |
|
|
2373 |
if syslog in (constants.SYSLOG_YES, constants.SYSLOG_ONLY): |
|
2374 |
facility = logging.handlers.SysLogHandler.LOG_DAEMON |
|
2375 |
syslog_handler = logging.handlers.SysLogHandler(constants.SYSLOG_SOCKET, |
|
2376 |
facility) |
|
2377 |
syslog_handler.setFormatter(sys_fmt) |
|
2378 |
# Never enable debug over syslog |
|
2379 |
syslog_handler.setLevel(logging.INFO) |
|
2380 |
root_logger.addHandler(syslog_handler) |
|
2381 |
|
|
2382 |
if syslog != constants.SYSLOG_ONLY: |
|
2383 |
# this can fail, if the logging directories are not setup or we have |
|
2384 |
# a permisssion problem; in this case, it's best to log but ignore |
|
2385 |
# the error if stderr_logging is True, and if false we re-raise the |
|
2386 |
# exception since otherwise we could run but without any logs at all |
|
2387 |
try: |
|
2388 |
if console_logging: |
|
2389 |
logfile_handler = LogFileHandler(logfile) |
|
2390 |
else: |
|
2391 |
logfile_handler = logging.FileHandler(logfile) |
|
2392 |
logfile_handler.setFormatter(formatter) |
|
2393 |
if debug: |
|
2394 |
logfile_handler.setLevel(logging.DEBUG) |
|
2395 |
else: |
|
2396 |
logfile_handler.setLevel(logging.INFO) |
|
2397 |
root_logger.addHandler(logfile_handler) |
|
2398 |
except EnvironmentError: |
|
2399 |
if stderr_logging or syslog == constants.SYSLOG_YES: |
|
2400 |
logging.exception("Failed to enable logging to file '%s'", logfile) |
|
2401 |
else: |
|
2402 |
# we need to re-raise the exception |
|
2403 |
raise |
|
2404 |
|
|
2405 |
|
|
2406 | 2279 |
def IsNormAbsPath(path): |
2407 | 2280 |
"""Check whether a path is absolute and also normalized |
2408 | 2281 |
|
Also available in: Unified diff