diff --git a/logging b/logging index b237214..be03f84 100644 --- a/logging +++ b/logging @@ -39,7 +39,7 @@ handlers = console,file # Console handler class = StreamHandler level = INFO -args = (sys.stdout,) +args = (sys.stderr,) formatter = simple [handler_file] diff --git a/radicale/__init__.py b/radicale/__init__.py index e11ffc8..b8fed35 100644 --- a/radicale/__init__.py +++ b/radicale/__init__.py @@ -28,6 +28,7 @@ should have been included in this package. import base64 import contextlib +import io import itertools import os import posixpath @@ -131,6 +132,18 @@ class ThreadedHTTPSServer(socketserver.ThreadingMixIn, HTTPSServer): class RequestHandler(wsgiref.simple_server.WSGIRequestHandler): """HTTP requests handler.""" + + # These class attributes must be set before creating instance + logger = None + + def __init__(self, *args, **kwargs): + # Store exception for logging + self.error_stream = io.StringIO() + super().__init__(*args, **kwargs) + + def get_stderr(self): + return self.error_stream + def log_message(self, *args, **kwargs): """Disable inner logging management.""" @@ -140,6 +153,14 @@ class RequestHandler(wsgiref.simple_server.WSGIRequestHandler): env["PATH_INFO"] = urllib.parse.unquote(self.path.split("?", 1)[0]) return env + def handle(self): + super().handle() + # Log exception + error = self.error_stream.getvalue().strip("\n") + if error: + self.logger.error( + "An exception occurred during request:\n%s" % error) + class Application: """WSGI application managing collections.""" diff --git a/radicale/__main__.py b/radicale/__main__.py index c76acca..4236607 100644 --- a/radicale/__main__.py +++ b/radicale/__main__.py @@ -104,7 +104,11 @@ def run(): if not configuration_found: logger.warning("Configuration file '%s' not found" % options.config) - serve(configuration, logger) + try: + serve(configuration, logger) + except Exception: + logger.exception("An exception occurred during server startup:") + exit(1) def serve(configuration, logger): @@ -175,6 +179,7 @@ def serve(configuration, logger): server_class.max_connections = configuration.getint( "server", "max_connections") + RequestHandler.logger = logger if not configuration.getboolean("server", "dns_lookup"): RequestHandler.address_string = lambda self: self.client_address[0] diff --git a/radicale/log.py b/radicale/log.py index 308e2a4..34d4e4c 100644 --- a/radicale/log.py +++ b/radicale/log.py @@ -29,8 +29,8 @@ import signal import sys -def configure_from_file(filename, debug, logger): - logging.config.fileConfig(filename) +def configure_from_file(logger, filename, debug): + logging.config.fileConfig(filename, disable_existing_loggers=False) if debug: logger.setLevel(logging.DEBUG) for handler in logger.handlers: @@ -46,18 +46,16 @@ def start(name="radicale", filename=None, debug=False): configure_from_file(logger, filename, debug) # Reload config on SIGHUP (UNIX only) if hasattr(signal, "SIGHUP"): - def handler_generator(logger, filename, debug): - def handler(signum, frame): - configure_from_file(logger, filename, debug) - handler = handler_generator(logger, filename, debug) + def handler(signum, frame): + configure_from_file(logger, filename, debug) signal.signal(signal.SIGHUP, handler) else: # Default configuration, standard output if filename: logger.warning( - "Logging configuration file '%s' not found, using stdout." % + "Logging configuration file '%s' not found, using stderr." % filename) - handler = logging.StreamHandler(sys.stdout) + handler = logging.StreamHandler(sys.stderr) handler.setFormatter(logging.Formatter("%(message)s")) logger.addHandler(handler) if debug: