diff --git a/CHANGES.md b/CHANGES.md index 2ad0768..cde5a40 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,8 +17,6 @@ makes it possible to distinguish between a job that explicitly returned `None` and a job that isn't finished yet (see `status` property). -- Remove `logbook` dependency (in favor of `logging`) - - Custom exception handlers can now be configured in addition to, or to fully replace, moving failed jobs to the failed queue. Relevant documentation [here](http://python-rq.org/docs/exceptions/) and diff --git a/requirements.txt b/requirements.txt index be09e74..18dfe05 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ redis times +logbook argparse diff --git a/rq/scripts/rqworker.py b/rq/scripts/rqworker.py index 0b78d79..c870989 100755 --- a/rq/scripts/rqworker.py +++ b/rq/scripts/rqworker.py @@ -1,44 +1,42 @@ #!/usr/bin/env python import sys import argparse -import logging -import logging.config - +import logbook +from logbook import handlers from rq import Queue, Worker from redis.exceptions import ConnectionError from rq.scripts import add_standard_arguments from rq.scripts import setup_redis -logger = logging.getLogger(__name__) + +def format_colors(record, handler): + from rq.utils import make_colorizer + if record.level == logbook.WARNING: + colorize = make_colorizer('darkyellow') + elif record.level >= logbook.ERROR: + colorize = make_colorizer('darkred') + else: + colorize = lambda x: x + return '%s: %s' % (record.time.strftime('%H:%M:%S'), colorize(record.msg)) def setup_loghandlers(args): - logging.config.dictConfig({ - "version": 1, - "disable_existing_loggers": False, - - "formatters": { - "console": { - "format": "%(asctime)s %(message)s", - "datefmt": "%H:%M:%S", - }, - }, - - "handlers": { - "console": { - "level": "DEBUG", - #"class": "logging.StreamHandler", - "class": "rq.utils.ColorizingStreamHandler", - "formatter": "console", - "exclude": ["%(asctime)s"], - }, - }, - - "root": { - "handlers": ["console"], - "level": "DEBUG" if args.verbose else "INFO" - } - }) + if args.verbose: + loglevel = logbook.DEBUG + formatter = None + else: + loglevel = logbook.INFO + formatter = format_colors + + handlers.NullHandler(bubble=False).push_application() + handler = handlers.StreamHandler(sys.stdout, level=loglevel, bubble=False) + if formatter: + handler.formatter = formatter + handler.push_application() + handler = handlers.StderrHandler(level=logbook.WARNING, bubble=False) + if formatter: + handler.formatter = formatter + handler.push_application() def parse_args(): @@ -83,7 +81,6 @@ def main(): setup_loghandlers(args) setup_redis(args) - try: queues = map(Queue, args.queues) w = Worker(queues, name=args.name) diff --git a/rq/utils.py b/rq/utils.py index f9c4933..2eef8d2 100644 --- a/rq/utils.py +++ b/rq/utils.py @@ -5,7 +5,6 @@ Miscellaneous helper functions. The formatter for ANSI colored console output is heavily based on Pygments terminal colorizing code, originally by Georg Brandl. """ -import logging import os @@ -116,34 +115,3 @@ def make_colorizer(color): def inner(text): return colorizer.colorize(color, text) return inner - - -class ColorizingStreamHandler(logging.StreamHandler): - - levels = { - logging.WARNING: make_colorizer('darkyellow'), - logging.ERROR: make_colorizer('darkred'), - logging.CRITICAL: make_colorizer('darkred'), - } - - def __init__(self, exclude=None, *args, **kwargs): - self.exclude = exclude - super(ColorizingStreamHandler, self).__init__(*args, **kwargs) - - @property - def is_tty(self): - isatty = getattr(self.stream, 'isatty', None) - return isatty and isatty() - - def format(self, record): - message = logging.StreamHandler.format(self, record) - if self.is_tty: - colorize = self.levels.get(record.levelno, lambda x: x) - - # Don't colorize any traceback - parts = message.split('\n', 1) - parts[0] = " ".join([parts[0].split(" ", 1)[0], colorize(parts[0].split(" ", 1)[1])]) - - message = '\n'.join(parts) - - return message diff --git a/rq/worker.py b/rq/worker.py index 4d5c0b4..c936262 100644 --- a/rq/worker.py +++ b/rq/worker.py @@ -11,8 +11,12 @@ except ImportError: import socket import signal import traceback -import logging from cPickle import dumps +try: + from logbook import Logger + Logger = Logger # Does nothing except it shuts up pyflakes annoying error +except ImportError: + from logging import Logger from .queue import Queue, get_failed_queue from .connections import get_current_connection from .job import Status @@ -25,8 +29,6 @@ green = make_colorizer('darkgreen') yellow = make_colorizer('darkyellow') blue = make_colorizer('darkblue') -logger = logging.getLogger(__name__) - class StopRequested(Exception): pass @@ -110,7 +112,7 @@ class Worker(object): self._is_horse = False self._horse_pid = 0 self._stopped = False - self.log = logger + self.log = Logger('worker') self.failed_queue = get_failed_queue(connection=self.connection) # By default, push the "move-to-failed-queue" exception handler onto @@ -370,7 +372,7 @@ class Worker(object): signal.signal(signal.SIGTERM, signal.SIG_DFL) self._is_horse = True - self.log = logger + self.log = Logger('horse') success = self.perform_job(job) diff --git a/setup.cfg b/setup.cfg index 73a42b3..8e76f14 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,2 @@ [bdist_rpm] -requires = redis procname +requires = redis procname logbook diff --git a/setup.py b/setup.py index 6154328..044bf8d 100644 --- a/setup.py +++ b/setup.py @@ -18,6 +18,7 @@ def get_version(): def get_dependencies(): deps = ['redis >= 2.4.0', 'times'] + deps += ['logbook'] # should be soft dependency? if sys.version_info < (2, 7) or \ (sys.version_info >= (3, 0) and sys.version_info < (3, 1)): deps += ['importlib'] diff --git a/tests/__init__.py b/tests/__init__.py index 398d23a..09c4e4b 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,7 +1,6 @@ -import logging import unittest - from redis import Redis +from logbook import NullHandler from rq import push_connection, pop_connection @@ -48,8 +47,9 @@ class RQTestCase(unittest.TestCase): # Store the connection (for sanity checking) cls.testconn = testconn - # Shut up logging - logging.disable("ERROR") + # Shut up logbook + cls.log_handler = NullHandler() + cls.log_handler.push_thread() def setUp(self): # Flush beforewards (we like our hygiene) @@ -66,7 +66,7 @@ class RQTestCase(unittest.TestCase): @classmethod def tearDownClass(cls): - logging.disable(logging.NOTSET) + cls.log_handler.pop_thread() # Pop the connection to Redis testconn = pop_connection()