import logging.handlers
from ganeti import constants
+from ganeti import compat
class _ReopenableLogHandler(logging.handlers.BaseRotatingHandler):
self._reopen = False
- def shouldRollover(self, _): # pylint: disable-msg=C0103
+ def shouldRollover(self, _): # pylint: disable=C0103
"""Determine whether log file should be reopened.
"""
return self._reopen or not self.stream
- def doRollover(self): # pylint: disable-msg=C0103
+ def doRollover(self): # pylint: disable=C0103
"""Reopens the log file.
"""
# TODO: Handle errors?
self.stream = open(self.baseFilename, "a")
+ # Don't reopen on the next message
+ self._reopen = False
+
def RequestReopen(self):
"""Register a request to reopen the file.
This needs to be in a function for unittesting.
"""
- class wrapped(base): # pylint: disable-msg=C0103
+ class wrapped(base): # pylint: disable=C0103
"""Log handler that doesn't fallback to stderr.
When an error occurs while writing on the logfile, logging.FileHandler
assert not hasattr(self, "_console")
self._console = console
- def handleError(self, record): # pylint: disable-msg=C0103
+ def handleError(self, record): # pylint: disable=C0103
"""Handle errors which occur during an emit() call.
Try to handle errors with FileHandler method, if it fails write to
"""
try:
base.handleError(record)
- except Exception: # pylint: disable-msg=W0703
+ except Exception: # pylint: disable=W0703
if self._console:
try:
- # Ignore warning about "self.format", pylint: disable-msg=E1101
+ # Ignore warning about "self.format", pylint: disable=E1101
self._console.write("Cannot log message:\n%s\n" %
self.format(record))
- except Exception: # pylint: disable-msg=W0703
+ except Exception: # pylint: disable=W0703
# Log handler tried everything it could, now just give up
pass
return logging.Formatter("".join(parts))
+def _ReopenLogFiles(handlers):
+ """Wrapper for reopening all log handler's files in a sequence.
+
+ """
+ for handler in handlers:
+ handler.RequestReopen()
+ logging.info("Received request to reopen log files")
+
+
def SetupLogging(logfile, program, debug=0, stderr_logging=False,
multithreaded=False, syslog=constants.SYSLOG_USAGE,
- console_logging=False):
+ console_logging=False, root_logger=None):
"""Configures the logging module.
@type logfile: str
@type console_logging: boolean
@param console_logging: if True, will use a FileHandler which falls back to
the system console if logging fails
+ @type root_logger: logging.Logger
+ @param root_logger: Root logger to use (for unittests)
@raise EnvironmentError: if we can't open the log file and
syslog/stderr logging is disabled
+ @rtype: callable
+ @return: Function reopening all open log files when called
"""
progname = os.path.basename(program)
formatter = _GetLogFormatter(progname, multithreaded, debug, False)
syslog_fmt = _GetLogFormatter(progname, multithreaded, debug, True)
- root_logger = logging.getLogger("")
+ reopen_handlers = []
+
+ if root_logger is None:
+ root_logger = logging.getLogger("")
root_logger.setLevel(logging.NOTSET)
# Remove all previously setup handlers
# exception since otherwise we could run but without any logs at all
try:
if console_logging:
- logfile_handler = _LogHandler(open(constants.DEV_CONSOLE, "a"), logfile)
+ logfile_handler = _LogHandler(open(constants.DEV_CONSOLE, "a"),
+ logfile)
else:
logfile_handler = _ReopenableLogHandler(logfile)
+
+ logfile_handler.setFormatter(formatter)
+ if debug:
+ logfile_handler.setLevel(logging.DEBUG)
+ else:
+ logfile_handler.setLevel(logging.INFO)
+ root_logger.addHandler(logfile_handler)
+ reopen_handlers.append(logfile_handler)
except EnvironmentError:
if stderr_logging or syslog == constants.SYSLOG_YES:
logging.exception("Failed to enable logging to file '%s'", logfile)
# we need to re-raise the exception
raise
- logfile_handler.setFormatter(formatter)
- if debug:
- logfile_handler.setLevel(logging.DEBUG)
- else:
- logfile_handler.setLevel(logging.INFO)
- root_logger.addHandler(logfile_handler)
+ return compat.partial(_ReopenLogFiles, reopen_handlers)