Permalink
Browse files

Improvements & Documentation

- Document all the functions
- Add proper exceptions
- Automatically connect the publisher to redis
  • Loading branch information...
1 parent 3cc412f commit 32a421bd821d8580bc845c8f2eb1663bfa61632b @Rafiot committed Sep 18, 2012
Showing with 111 additions and 7 deletions.
  1. +13 −0 pubsublogger/exceptions.py
  2. +60 −6 pubsublogger/publisher.py
  3. +38 −0 pubsublogger/subscriber.py
  4. +0 −1 test/test_publisher.py
View
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+"Core exceptions raised by the PubSub module"
+
+class PubSubError(Exception):
+ pass
+
+class InvalidErrorLevel(PubSubError):
+ pass
+
+class NoChannelError(PubSubError):
+ pass
View
@@ -1,35 +1,89 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+:mod:`publisher` -- Publish logging messages on a redis channel
+
+To use this module, you have to define at least a channel name.
+
+.. note::
+ The channel name should represent the area of the program you want
+ to log. It can be whatever you want.
+
+
+"""
+
import redis
+from pubsublogger.exceptions import InvalidErrorLevel, NoChannelError
+
hostname = 'localhost'
port = 6379
channel = None
redis_instance = None
-def connect():
+__error_levels = ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
+
+
+def __connect():
+ """
+ Connect to a redis instance.
+ """
global redis_instance
redis_instance = redis.StrictRedis(host=hostname, port=port)
+
def log(level, message):
- if redis_instance is not None and channel is not None:
- c = '{channel}.{level}'.format(channel = channel, level = level)
- redis_instance.publish(c, message)
- else:
- raise Exception('Not connected to redis and/or no channel set')
+ """
+ Publish `message` with the `level` the redis `channel`.
+
+ :param level: the level of the message
+ :param message: the message you want to log
+ """
+ if redis_instance is None:
+ __connect()
+
+ if level not in __error_levels:
+ raise InvalidErrorLevel('You have used an invalid error level. \
+ Please choose in: ' + ', '.join(__error_levels))
+ if channel is None:
+ raise NoChannelError('Please set a channel.')
+ c = '{channel}.{level}'.format(channel=channel, level=level)
+ redis_instance.publish(c, message)
+
def debug(message):
+ """
+ Publush a DEBUG `message`
+ """
log('DEBUG', message)
+
def info(message):
+ """
+ Publush an INFO `message`
+ """
log('INFO', message)
+
def warning(message):
+ """
+ Publush a WARNING `message`
+ """
log('WARNING', message)
+
def error(message):
+ """
+ Publush an ERROR `message`
+ """
log('ERROR', message)
+
def critical(message):
+ """
+ Publush a CRITICAL `message`
+ """
log('CRITICAL', message)
+
+
View
@@ -1,6 +1,13 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+"""
+:mod:`subscriber` -- Subscribe to a redis channel and gather logging messages.
+
+To use this module, you have to define at least a channel name.
+"""
+
+
import redis
from logbook import Logger
import ConfigParser
@@ -20,6 +27,15 @@
src_server = None
def setup(name, path = 'log', enable_debug = False):
+ """
+ Prepare a NestedSetup.
+
+ :param name: the channel name
+ :param path: the path where the logs will be written
+ :param enable_debug: do we want to save the message at the DEBUG level
+
+ :return a nested Setup
+ """
path_tmpl = os.path.join(path, '{name}_{level}.log')
info = path_tmpl.format(name = name, level = 'info')
warn = path_tmpl.format(name = name, level = 'warn')
@@ -55,6 +71,11 @@ def setup(name, path = 'log', enable_debug = False):
return NestedSetup(setup)
def mail_setup(path):
+ """
+ Set the variables to be able to send emails.
+
+ :param path: path to the config file
+ """
global dest_mails
global smtp_server
global smtp_port
@@ -67,6 +88,16 @@ def mail_setup(path):
src_server = config.get('mail', 'src_server')
def run(log_name, path, debug = False, mail = None):
+ """
+ Run a subscriber and pass the messages to the logbook setup.
+ Stays alive as long as the pubsub instance listen to something.
+
+ :param log_name: the channel to listen to
+ :param path: the path where the log files will be written
+ :param debug: True if you want to save the debug messages too
+ :param mail: Path to the config file for the mails
+
+ """
global pubsub
global channel
channel = log_name
@@ -77,6 +108,10 @@ def run(log_name, path, debug = False, mail = None):
logger = Logger(channel)
if mail is not None:
mail_setup(mail)
+ if os.path.exists(path) and not os.path.isdir(path):
+ raise Exception("The path you want to use to save the file is invalid (not a directory).")
+ if not os.path.exists(path):
+ os.mkdir(path)
with setup(channel, path, debug):
for msg in pubsub.listen():
if msg['type'] == 'pmessage':
@@ -86,4 +121,7 @@ def run(log_name, path, debug = False, mail = None):
def stop():
+ """
+ Unsubscribe to the channel, stop the script.
+ """
pubsub.punsubscribe(channel + '.*')
View
@@ -19,7 +19,6 @@
publisher.hostname = args.hostname
publisher.port = args.port
- publisher.connect()
for i in range(0,21):
if i%2 == 0 :
publisher.info('test' + str(i))

0 comments on commit 32a421b

Please sign in to comment.