Jogging is a thin wrapper around Python's logging functionality to make Django logging easier. It provides a central place to configure all your loggers, a standard location to import loggers, and makes common logging use cases simpler.
With Jogging, you can control the destination, format, and verbosity of logs with fine granularity. Configuring module-level logging is just as easy as configuring logging for specific functions.
To use it, you add a few configurations to settings.py, import Jogging's log functions instead of Python's, and then log away like you normally do.
Python's logging module does all the heavy lifting. As a result, you can use Jogging to configure logging for code that already exists. And great care has been taken to make sure logging's power isn't hidden away behind abstractions.
You can grab the latest release from the Downloads section, or by running pip install jogging
.
- Add
'jogging'
to yourINSTALLED_APPS
- Add
'jogging.middleware.LoggingMiddleware'
to yourMIDDLEWARE_CLASSES
Code samples are easier than words, so here's a few of them. These go in settings.py.
from jogging.handlers import DatabaseHandler import logging GLOBAL_LOG_LEVEL = logging.INFO GLOBAL_LOG_HANDLERS = [DatabaseHandler()] # takes any Handler object that Python's logging takes
Everything INFO and above will get logged to the database.
Note that Jogging doesn't wrap Handlers; they're the same as in logging. This means you can do everything logging.Handler lets you do, and then throw the Handler objects into Jogging.
from jogging.handlers import DatabaseHandler from logging import StreamHandler import logging LOGGING = { # all logs from myapp1 go to the database 'myapp1': { 'handler': DatabaseHandler(), # an initialized handler object 'level': logging.DEBUG, }, # ...except for this one view which will log CRITICAL to stderr 'myapp1.views.super_important_view': { 'handler': StreamHandler(), 'level': logging.CRITICAL, }, }
Only the most specific logger will be matched (i.e. super_important_view()
won't log to the database in this example).
from jogging.handlers import DatabaseHandler from logging import StreamHandler, FileHandler import logging LOGGING = { # all logs from myapp1 go to the database 'myapp1': { 'handler': DatabaseHandler(), 'level': logging.DEBUG, }, # this time, we'll have super_important_view log CRITICAL to stderr again, but # we'll also have it log everything to the database 'myapp1.views.super_important_view': { 'handlers': [ { 'handler': StreamHandler(), 'level': logging.CRITICAL, 'format': "%(asctime)-15s %(source): %(message)s %(foo)s" }, { 'handler': DatabaseHandler(), 'level': logging.DEBUG }, ] }, # this is the name of a logger that a third party app already logs to. # you can configure it just like the others, without breaking anything. 'simple_example': { 'handler': StreamHandler(), 'level': logging.CRITICAL, } }
The format property on handlers takes the same specifiers as Python's logging, plus some extras:
%(source)s
is the method that made the logging call.%(foo)s
is a parameter passed into the logging call.
from jogging import logging logging.info("I'm an info message") logging.debug(msg="I'm a debug message", foo="bar")
Remember %(foo)s
from the 'format'
property in the Advanced configuration above? It will be populated with "bar"
in the debug call.
jogging.handlers.DatabaseHandler
- Logs to the database, so logs are browsable/searchable/filterable in the admin.
jogging.handlers.EmailHandler
- Logs to emails.
jogging.handlers.InlineOnPageHandler
- Coming soon. Append logs to the bottom of the rendered page.
- What's the difference between Jogging and django-logging?
- Django logging just sets up a single root logger for you. Jogging lets you set up different loggers for different modules. The "basic" configuration above solves the same use case as django-logging.
- What's the difference between Jogging and django-db-log?
- django-db-log just logs exceptions to the database. It's not for debug or general purpose logging, and doesn't have anything to do with Python's logging module. Jogging comes with a handler called DatabaseHandler that logs exceptions (and anything else you want) to the database just like django-db-log does.
- If you can use logging's log functions and still use Jogging, what's the benefit of using Jogging's log functions?
- Two reasons: firstly, you get a
source
variable you can use in your logger's formatter that is populated with the name of the calling function; and secondly, Jogging's log functions pick the right logger for you automatically, so you don't have to worry about whether the logger is already set up.
Much inspiration was taken from Django's logging proposal.
Jogging requires a dictionary, settings.LOGGING
, that defines the loggers you want to control through Jogging (by name). Here is how Jogging works:
- All loggers are created on server startup from
settings.LOGGING
(the init code is in models.py, for lack of a better place). Handlers are added to the loggers as defined, and levels are set. - When your app calls Jogging's log functions, the calling function is matched against the logger names in
settings.LOGGING
and the most specific logger is chosen. For example, saymyproj.myapp.views.func()
is the caller; it will match loggers namedmyproj.myapp.views.func
,myproj.myapp.views
,myproj.myapp
, andmyproj
. The first (most specific) one that matches will be chosen. log()
is called on the chosen logger, and Python's logging module takes over from here.
List of handlers in Python's logging module: http://docs.python.org/library/logging.html#handler-objects
Format specifiers for Python's logging module: http://docs.python.org/library/logging.html#formatter-objects
It's pronounced "yogging" actually -- the "j" is silent.