The center of structlog is the immutable log wrapper BoundLogger.
All it does is:
You won’t be instantiating it yourself though. For that there is the structlog.wrap_logger() function (or the convenience function structlog.get_logger() we’ll discuss in a minute):
>>> from structlog import wrap_logger
>>> class PrintLogger(object):
... def msg(self, message):
... print message
>>> def proc(logger, method_name, event_dict):
... print 'I got called with', event_dict
... return repr(event_dict)
>>> log = wrap_logger(PrintLogger(), processors=[proc], context_class=dict)
>>> log2 = log.bind(x=42)
>>> log == log2
False
>>> log.msg('hello world')
I got called with {'event': 'hello world'}
{'event': 'hello world'}
>>> log2.msg('hello world')
I got called with {'x': 42, 'event': 'hello world'}
{'x': 42, 'event': 'hello world'}
>>> log3 = log2.unbind('x')
>>> log == log3
True
>>> log3.msg('nothing bound anymore', foo='but you can structure the event too')
I got called with {'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'}
{'foo': 'but you can structure the event too', 'event': 'nothing bound anymore'}
As you can see, it accepts one mandatory and a few optional arguments:
A list of callables that can filter, mutate, and format the log entry before it gets passed to the wrapped logger.
Default is [format_exc_info(), KeyValueRenderer].
The class to save your context in. Particularly useful for thread local context storage.
Default is collections.OrderedDict.
Additionally, the following arguments are allowed too:
Note
Free your mind from the preconception that log entries have to be serialized to strings eventually. All structlog cares about is a dictionary of keys and values. What happens to it depends on the logger you wrap and your processors alone.
This gives you the power to log directly to databases, log aggregation servers, web services, and whatnot.
To save you the hassle of using standard library logging for simple standard out logging, structlog ships a PrintLogger that can log into arbitrary files – including standard out (which is the default if no file is passed into the constructor):
>>> from structlog import PrintLogger
>>> PrintLogger().info('hello world!')
hello world!
It’s handy for both examples and in combination with tools like runit or stdout/stderr-forwarding.
Additionally – mostly for unit testing – structlog also ships with a logger that just returns whatever it gets passed into it: ReturnLogger.
>>> from structlog import ReturnLogger
>>> ReturnLogger().msg(42) == 42
True
>>> obj = ['hi']
>>> ReturnLogger().msg(obj) is obj
True
>>> ReturnLogger().msg('hello', when='again')
(('hello',), {'when': 'again'})
[*] | Since this is slightly magicy, structlog comes with concrete loggers for the Python Standard Library and Twisted that offer you explicit APIs for the supported logging methods but behave identically like the generic BoundLogger otherwise. |