diff --git a/gunicorn/arbiter.py b/gunicorn/arbiter.py index 0bd59172..4c68c461 100644 --- a/gunicorn/arbiter.py +++ b/gunicorn/arbiter.py @@ -14,7 +14,6 @@ import time import traceback -from gunicorn.glogging import Logger from gunicorn.errors import HaltServer from gunicorn.pidfile import Pidfile from gunicorn.sock import create_socket @@ -85,7 +84,7 @@ class Arbiter(object): def setup(self, app): self.app = app self.cfg = app.cfg - self.log = Logger(app.cfg) + self.log = self.cfg.logger_class(app.cfg) if 'GUNICORN_FD' in os.environ: self.log.reopen_files() diff --git a/gunicorn/config.py b/gunicorn/config.py index 75e46ce7..c90eeefd 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -72,7 +72,7 @@ class Config(object): @property def worker_class(self): uri = self.settings['worker_class'].get() - worker_class = util.load_worker_class(uri) + worker_class = util.load_class(uri) if hasattr(worker_class, "setup"): worker_class.setup() return worker_class @@ -101,6 +101,17 @@ class Config(object): return pn else: return self.settings['default_proc_name'].get() + + @property + def logger_class(self): + uri = self.settings['logger_class'].get() + logger_class = util.load_class(uri, default="simple", + section="gunicorn.loggers") + + if hasattr(logger_class, "install"): + logger_class.install() + return logger_class + class SettingMeta(type): def __new__(cls, name, bases, attrs): @@ -617,6 +628,25 @@ class Loglevel(Setting): * critical """ +class LoggerClass(Setting): + name = "logger_class" + section = "Logging" + cli = ["--logger-class"] + meta = "STRING" + validator = validate_string + default = "simple" + desc = """\ + The logger you want to use to log events in gunicorn. + + The default class (``gunicorn.glogging.Logger``) handle most of + normal usages in logging. It provides error and access logging. + + You can provide your own worker by giving gunicorn a + python path to a subclass like gunicorn.glogging.Logger. + Alternatively the syntax can also load the Logger class + with ``egg:gunicorn#simple` + """ + class Procname(Setting): name = "proc_name" section = "Process Naming" diff --git a/gunicorn/util.py b/gunicorn/util.py index 344296b7..a6fe2ad5 100644 --- a/gunicorn/util.py +++ b/gunicorn/util.py @@ -64,7 +64,7 @@ except ImportError: def _setproctitle(title): return -def load_worker_class(uri): +def load_class(uri, default="sync", section="gunicorn.workers"): if uri.startswith("egg:"): # uses entry points entry_str = uri.split("egg:")[1] @@ -72,19 +72,20 @@ def load_worker_class(uri): dist, name = entry_str.rsplit("#",1) except ValueError: dist = entry_str - name = "sync" + name = default - return pkg_resources.load_entry_point(dist, "gunicorn.workers", name) + return pkg_resources.load_entry_point(dist, section, name) else: components = uri.split('.') if len(components) == 1: try: if uri.startswith("#"): uri = uri[1:] + return pkg_resources.load_entry_point("gunicorn", - "gunicorn.workers", uri) + section, uri) except ImportError: - raise RuntimeError("arbiter uri invalid or not found") + raise RuntimeError("class uri invalid or not found") klass = components.pop(-1) mod = __import__('.'.join(components)) for comp in components[1:]: diff --git a/setup.py b/setup.py index 9ac7fa9c..8d2f24d9 100644 --- a/setup.py +++ b/setup.py @@ -61,6 +61,9 @@ setup( gevent_pywsgi=gunicorn.workers.ggevent:GeventPyWSGIWorker tornado=gunicorn.workers.gtornado:TornadoWorker + [gunicorn.loggers] + simple=gunicorn.glogging:Logger + [paste.server_runner] main=gunicorn.app.pasterapp:paste_server """,