Repository: klen/graphite-beacon

Issue:
Logging configuration only works in Python 2.7+
Hi,

The way log level is set in [`Reactor`](https://github.com/klen/graphite-beacon/blob/develop/graphite_beacon/core.py#L59) requires that textual log levels ("INFO", "WARN") are converted to the numeric log levels by the `logging.Logger.setLevel` method. This is only the case in Python 2.7.

You can see the change between 2.6 and 2.7 here:

2.6 - https://github.com/python/cpython/blob/2.6/Lib/logging/__init__.py#L1032
2.7 - https://github.com/python/cpython/blob/2.7/Lib/logging/__init__.py#L1136

I'll submit a pull request shortly. Thanks!

Discussion:

Patch:
diff --git a/graphite_beacon/core.py b/graphite_beacon/core.py
index 88fadfa..adef419 100644
--- a/graphite_beacon/core.py
+++ b/graphite_beacon/core.py
@@ -2,6 +2,7 @@ import os
 from re import compile as re, M
 
 import json
+import logging
 from tornado import ioloop, log
 
 from .alerts import BaseAlert
@@ -56,7 +57,7 @@ class Reactor(object):
         for config in self.options.pop('include', []):
             self.include_config(config)
 
-        LOGGER.setLevel(self.options.get('logging', 'info').upper())
+        LOGGER.setLevel(_get_numeric_log_level(self.options.get('logging', 'info')))
         registry.clean()
 
         self.handlers = {'warning': set(), 'critical': set(), 'normal': set()}
@@ -123,3 +124,33 @@ class Reactor(object):
 
         for handler in self.handlers.get(level, []):
             handler.notify(level, alert, value, target=target, ntype=ntype, rule=rule)
+
+
+_LOG_LEVELS = {
+    'DEBUG': logging.DEBUG,
+    'INFO': logging.INFO,
+    'WARN': logging.WARN,
+    'WARNING': logging.WARNING,
+    'ERROR': logging.ERROR,
+    'CRITICAL': logging.CRITICAL
+}
+
+
+def _get_numeric_log_level(name):
+    """Convert a textual log level to the numeric constants expected by the
+    :meth:`logging.Logger.setLevel` method.
+
+    This is required for compatibility with Python 2.6 where there is no conversion
+    performed by the ``setLevel`` method. In Python 2.7 textual names are converted
+    to numeric constants automatically.
+
+    :param basestring name: Textual log level name
+    :return: Numeric log level constant
+    :rtype: int
+    """
+    name = str(name).upper()
+
+    try:
+        return _LOG_LEVELS[name]
+    except KeyError:
+        raise ValueError("Unknown level: %s" % name)


Test patch:
diff --git a/tests.py b/tests.py
index 7bcd15a..9d5458a 100644
--- a/tests.py
+++ b/tests.py
@@ -1,5 +1,6 @@
 """ TODO: Implement the tests. """
 
+import logging
 import pytest
 import mock
 
@@ -24,6 +25,28 @@ def test_reactor():
     assert len(rr.alerts) == 2
 
 
+def test_convert_config_log_level():
+    from graphite_beacon.core import _get_numeric_log_level
+
+    assert logging.DEBUG == _get_numeric_log_level('debug')
+    assert logging.DEBUG == _get_numeric_log_level('DEBUG')
+
+    assert logging.INFO == _get_numeric_log_level('info')
+    assert logging.INFO == _get_numeric_log_level('INFO')
+
+    assert logging.WARN == _get_numeric_log_level('warn')
+    assert logging.WARN == _get_numeric_log_level('WARN')
+
+    assert logging.WARNING == _get_numeric_log_level('warning')
+    assert logging.WARNING == _get_numeric_log_level('WARNING')
+
+    assert logging.ERROR == _get_numeric_log_level('error')
+    assert logging.ERROR == _get_numeric_log_level('ERROR')
+
+    assert logging.CRITICAL == _get_numeric_log_level('critical')
+    assert logging.CRITICAL == _get_numeric_log_level('CRITICAL')
+
+
 def test_alert(reactor):
     from graphite_beacon.alerts import BaseAlert, GraphiteAlert, URLAlert