Skip to content

Commit

Permalink
Resolved Issue #162
Browse files Browse the repository at this point in the history
  • Loading branch information
BJ Dierkes committed Aug 21, 2012
1 parent 8f41060 commit 576f6e6
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 58 deletions.
18 changes: 15 additions & 3 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,23 @@ is available online at:
2.1.1 - development (will be released as 2.1.2 dev)
------------------------------------------------------------------------------

This is a branch of the 2.0.x stable code base. Maintenance releases will
still be made for the 2.0.x code base, however forward feature development
will happen here under as 2.1.x.
This is a branch of the 2.0.x stable code base. Maintenance releases for
2.0.x will happen under the stable/2.0.x git branch, while forward feature
development will happen here under as 2.1.x under the git master branch.

Bugs:

* :issue:`162` - Unable to set log 'level' by config

Features:

* None

Incompatible Changes:

* None


2.0.0 - Fri Aug 03, 2012
------------------------------------------------------------------------------

Expand Down
26 changes: 15 additions & 11 deletions cement/core/foundation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ..core import output, extension, arg, controller, meta, cache
from ..ext import ext_configparser, ext_argparse, ext_logging
from ..ext import ext_nulloutput, ext_plugin
from ..utils.misc import is_true

if sys.version_info[0] >= 3:
from imp import reload # pragma: nocover
Expand Down Expand Up @@ -107,12 +108,8 @@ class Meta:

debug = False
"""
Toggles debug output. By default, this setting is also overridden
by the '[base] -> debug' config setting parsed in any
of the application configuration files (where [base] is the
base configuration section of the application which is determined
by Meta.config_section but defaults to Meta.label).
"""
Used internally, and should not be used by developers. This is set
to `True` if `--debug` is passed at command line."""

config_files = None
"""
Expand Down Expand Up @@ -302,7 +299,7 @@ class Meta:
"""

core_meta_override = [
'debug',
'debug',
'plugin_config_dir',
'plugin_dir'
]
Expand Down Expand Up @@ -347,6 +344,10 @@ def __init__(self, label=None, **kw):
# setup argv... this has to happen before lay_cement()
if self._meta.argv is None:
self._meta.argv = list(sys.argv[1:])

# hack for command line --debug
if '--debug' in self.argv:
self._meta.debug = True

# setup the cement framework
self._lay_cement()
Expand Down Expand Up @@ -514,12 +515,14 @@ def _lay_cement(self):
"""Initialize the framework."""
LOG.debug("laying cement for the '%s' application" % \
self._meta.label)

# hacks to suppress console output
### overrides via command line
suppress_output = False

if '--debug' in self._meta.argv:
self._meta.debug = True
else:
# the following are hacks to suppress console output
for flag in ['--quiet', '--json', '--yaml']:
if flag in self._meta.argv:
suppress_output = True
Expand Down Expand Up @@ -654,16 +657,17 @@ def _setup_config_handler(self):
for _file in self._meta.config_files:
self.config.parse_file(_file)

# override select Meta via config
base_dict = self.config.get_section_dict(self._meta.config_section)
for key in base_dict:
if key in self._meta.core_meta_override or \
key in self._meta.meta_override:
setattr(self._meta, key, base_dict[key])

def _setup_log_handler(self):
LOG.debug("setting up %s.log handler" % self._meta.label)
self.log = self._resolve_handler('log', self._meta.log_handler)

def _setup_plugin_handler(self):
LOG.debug("setting up %s.plugin handler" % self._meta.label)

Expand Down
59 changes: 30 additions & 29 deletions cement/ext/ext_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
from ..core import exc, log, handler
from ..utils.misc import is_true
from ..utils import fs

class LoggingLogHandler(log.CementLogHandler):
"""
Expand All @@ -15,7 +16,7 @@ class LoggingLogHandler(log.CementLogHandler):
The following configuration options are recognized in this class:
<app_label>.debug
log.level
log.file
Expand All @@ -31,10 +32,7 @@ class LoggingLogHandler(log.CementLogHandler):
A sample config section (in any config file) might look like:
.. code-block:: text
[myapp]
debug = True
[log]
file = /path/to/config/file
level = info
Expand Down Expand Up @@ -102,34 +100,33 @@ def __init__(self, *args, **kw):

def _setup(self, app_obj):
super(LoggingLogHandler, self)._setup(app_obj)
self._meta._merge(self.app.config.get_section_dict('log'))

if self._meta.namespace is None:
self._meta.namespace = self.app._meta.label

self.backend = logging.getLogger(self._meta.namespace)

# the king trumps all
if is_true(self.app._meta.debug):
self._meta.level = 'DEBUG'
# hack for application debugging
if self.app._meta.debug is True:
self.app.config.set('log', 'level', 'DEBUG')

self.set_level(self._meta.level)
self.set_level(self.app.config.get('log', 'level'))

# clear loggers?
if is_true(self._meta.clear_loggers):
self.clear_loggers()

# console
if is_true(self._meta.to_console):
if is_true(self.app.config.get('log', 'to_console')):
self._setup_console_log()

# file
if self._meta.file:
if self.app.config.get('log', 'file'):
self._setup_file_log()



self.debug("logging initialized for '%s' using LoggingLogHandler" % \
self._meta.namespace)

def set_level(self, level):
"""
Set the log level. Must be one of the log levels configured in
Expand All @@ -138,6 +135,7 @@ def set_level(self, level):
:param level: The log level to set.
"""
level = level.upper()
if level not in self.levels:
level = 'INFO'
level = getattr(logging, level.upper())
Expand All @@ -146,7 +144,7 @@ def set_level(self, level):

for handler in logging.getLogger(self._meta.namespace).handlers:
handler.setLevel(level)

def get_level(self):
"""Returns the current log level."""
return logging.getLevelName(self.backend.level)
Expand All @@ -170,35 +168,38 @@ def _setup_console_log(self):
format = logging.Formatter(self._meta.debug_format)
else:
format = logging.Formatter(self._meta.console_format)

console_handler.setFormatter(format)
console_handler.setLevel(getattr(logging, self.get_level()))
self._console_handler = console_handler
self.backend.addHandler(console_handler)

def _setup_file_log(self):
"""Add a file log handler."""

file = os.path.abspath(os.path.expanduser(self._meta.file))
log_dir = os.path.dirname(file)
file_path = fs.abspath(self.app.config.get('log', 'file'))
log_dir = os.path.dirname(file_path)
if not os.path.exists(log_dir):
os.makedirs(log_dir)

if self._meta.rotate:
if self.app.config.get('log', 'rotate'):
from logging.handlers import RotatingFileHandler
file_handler = RotatingFileHandler(
file,
maxBytes=int(self._meta.max_bytes),
backupCount=int(self._meta.max_files),
file_path,
maxBytes=int(self.app.config.get('log', 'max_bytes')),
backupCount=int(self.app.config.get('log', 'max_files')),
)
else:
from logging import FileHandler
file_handler = FileHandler(file)
file_handler = FileHandler(file_path)

if self.get_level() == logging.getLevelName(logging.DEBUG):
format = logging.Formatter(self._meta.debug_format)
else:
format = logging.Formatter(self._meta.file_format)
file_handler.setFormatter(format)
file_handler.setLevel(getattr(logging, self.get_level()))

self._file_handler = file_handler
self.backend.addHandler(file_handler)

def _get_logging_kwargs(self, namespace, **kw):
Expand Down Expand Up @@ -227,7 +228,7 @@ def info(self, msg, namespace=None, **kw):
"""
kwargs = self._get_logging_kwargs(namespace, **kw)
self.backend.info(msg, kwargs)
self.backend.info(msg, **kwargs)

def warn(self, msg, namespace=None, **kw):
"""
Expand All @@ -242,7 +243,7 @@ def warn(self, msg, namespace=None, **kw):
"""
kwargs = self._get_logging_kwargs(namespace, **kw)
self.backend.warn(msg, kwargs)
self.backend.warn(msg, **kwargs)

def error(self, msg, namespace=None, **kw):
"""
Expand All @@ -257,7 +258,7 @@ def error(self, msg, namespace=None, **kw):
"""
kwargs = self._get_logging_kwargs(namespace, **kw)
self.backend.error(msg, kwargs)
self.backend.error(msg, **kwargs)

def fatal(self, msg, namespace=None, **kw):
"""
Expand All @@ -272,7 +273,7 @@ def fatal(self, msg, namespace=None, **kw):
"""
kwargs = self._get_logging_kwargs(namespace, **kw)
self.backend.fatal(msg, kwargs)
self.backend.fatal(msg, **kwargs)

def debug(self, msg, namespace=None, **kw):
"""
Expand Down
4 changes: 2 additions & 2 deletions doc/source/api/index.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
API Documentation
=================
API Reference
=============

Cement Core Modules
-------------------
Expand Down
28 changes: 15 additions & 13 deletions tests/ext/logging_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,11 @@ def __init__(self, *args, **kw):
super(MyLog, self).__init__(*args, **kw)

class LoggingExtTestCase(test.CementTestCase):
def test_rotate(self):
defaults = backend.defaults()
defaults['base']['debug'] = True
defaults['log'] = dict(
file='/dev/null',
rotate=True,
to_console=True
)
app = self.make_app(config_defaults=defaults)
app.setup()

def test_alternate_namespaces(self):
defaults = backend.defaults('myapp', 'log')
defaults['log']['to_console'] = False
defaults['log']['file'] = '/dev/null'
defaults['log']['level'] = 'debug'
app = self.make_app(config_defaults=defaults)
app.setup()
app.log.info('TEST', extra=dict(namespace=__name__))
Expand Down Expand Up @@ -66,15 +57,26 @@ def test_clear_loggers(self):
Log.clear_loggers()

def test_rotate(self):
log_file = mkstemp()[1]
defaults = backend.defaults()
defaults['log'] = dict(
file=mkstemp()[1],
file=log_file,
level='DEBUG',
rotate=True,
max_bytes=10,
max_files=2,
)
app = self.make_app(config_defaults=defaults)
app.setup()
app.log.info('test log message')

# check that a second file was created, because this log is over 12
# bytes.
self.ok(os.path.exists("%s.1" % log_file))
self.ok(os.path.exists("%s.2" % log_file))

# FIX ME: Actually check rotation here
# this file should exist because of max files
self.eq(os.path.exists("%s.3" % log_file), False)

def test_missing_log_dir(self):
_, tmp_path = mkstemp()
Expand Down

0 comments on commit 576f6e6

Please sign in to comment.