Logging
Cement defines the Log Interface, as well as the default LoggingLogHandler that implements the interface. This handler is built on top of the Logging module which is included in the Python standard library.
Cement often includes multiple handler implementations of an interface that may or may not have additional features or functionality than the interface requires. The documentation below only references usage based on the interface and default handler (not the full capabilities of an implementation).
Cement Extensions That Provide Log Handlers
API References:
Option | Description |
log_handler | The handler that implements the log interface. |
The following shows logging to each of the defined log levels.
Example: Log Levels
from cement import App
with App('myapp') as app:
app.run()
# log messages to different levels
app.log.debug('This is a debug message.')
app.log.info('This is an info message.')
app.log.warning('This is a warning message.')
app.log.error('This is an error message.')
app.log.fatal('This is a fatal message.')
The above is displayed in order of severity. If the log level is set to
INFO
, you will receive all info messages and above including WARNING
, ERROR
, and FATAL
. However, you will not receive DEBUG
level messages. The same goes for a log level of WARNING
, where you will receive WARNING
, ERROR
, and FATAL
but you will not receive INFO, or DEBUG
level messages.The log level defaults to
INFO
, but can be set via LoggingLogHandler.Meta.config_defaults
or setting the level
under the log handlers section of the application configuration:Example: Changing Log Level
myapp.py
from cement import App, init_defaults
CONFIG = init_defaults('myapp', 'log.logging')
CONFIG['log.logging']['level'] = 'WARNING'
class MyApp(App):
class Meta:
label = 'myapp'
config_defaults = CONFIG
~/.myapp.conf
[myapp]
# ...
[log.logging]
level = WARNING
Cement also includes a
--debug
command line option by default. This triggers App.Meta.debug
and sets the log level to DEBUG
.The default log handler configuration enables logging messages to console.
Example: Logging to Console
cli
from cement import App
with App('myapp') as app:
app.run()
# log messages to different levels
app.log.debug('This is a debug message')
app.log.info('This is an info message')
app.log.warning('This is an warning message')
app.log.error('This is an error message')
app.log.fatal('This is a fatal message')
$ python myapp.py
INFO: This is an info message
WARNING: This is a warning message
ERROR: This is an error message
CRITICAL: This is a fatal message
Console logging can be disabled by setting
to_console
to False
in either the application defaults, or under the [log.logging]
section of the applications configuration file.File logging is disabled by default but can be enabled by setting the
file
setting under the [log.logging]
section of the application configuration.Example: Logging to File
myapp.py
from cement import App, init_defaults
CONFIG = init_defaults('myapp', 'log.logging')
CONFIG['log.logging']['file'] = '/path/to/file.log'
class MyApp(App):
class Meta:
label = 'myapp'
config_defaults = CONFIG
~/.myapp.conf
[myapp]
# ...
[log.logging]
file = /path/to/file.log
The following is specific to the default
LoggingLogHandler
, and is not an requirement of the logging interface.Logging to
app.log.debug()
is pretty straightforward. However, adding an additional parameter for the namespace
can greatly increase insight into where that log is happening. The namespace
defaults to the application name which you will see in every log like this:2012-07-30 18:05:11,357 (DEBUG) myapp : This is my message
For debugging, it might be more useful to change this to
__name__
:app.log.debug('This is my info message', __name__)
Which looks like:
2012-07-30 18:05:11,357 (DEBUG) myapp.somepackage.test : This is my message
Or even more verbose, you might prefer adding something like
__file__
and the function or class method:app.log.debug('This is my info message', '%s : my_func()' % __file__)
Which would look like:
2012-07-30 18:05:11,357 (DEBUG) myapp/somepackage/test.py : my_func() : This is my message
All interfaces in Cement can be overridden with your own implementation. This can be done either by sub-classing
LogHandler
itself, or by sub-classing an existing extension's handlers in order to alter their functionality.Example: Creating a Log Handler
myapp.py
from cement import App
from cement.core.log import LogHandler
class MyLogHandler(LogHandler):
class Meta:
label = 'my_log_handler'
# do something to implement the interface
class MyApp(App):
class Meta:
label = 'myapp'
log_handler = 'my_log_handler'
handlers = [
MyLogHandler,
]
Last modified 5yr ago