# Processors

The true power of `structlog` lies in its combinable log processors. A log processor is a regular callable, i.e. a function or an instance of a class with a `__call__()` method.

## Chains

The processor chain is a list of processors. Each processors receives three positional arguments:

logger
  Your wrapped logger object. For example `logging.Logger`.
method_name
  The name of the wrapped method. If you called `log.warn('foo')`, it will be `"warn"`.
event_dict
  Current context together with the current event. If the context was `{'a': 42}` and the event is `"foo"`, the initial `event_dict` will be `{'a':42, 'event': 'foo'}`.

The return value of each processor is passed on to the next one as `event_dict` until finally the return value of the last processor gets passed into the wrapped logging method.

### Examples

If you set up your logger like:

    from structlog import PrintLogger, wrap_logger
    wrapped_logger = PrintLogger()
    logger = wrap_logger(wrapped_logger, processors=[f1, f2, f3, f4])
    log = logger.new(x=42)

and call `log.msg('some_event', y=23)`, it results in the following call chain:

    wrapped_logger.msg(
       f4(wrapped_logger, 'msg',
          f3(wrapped_logger, 'msg',
             f2(wrapped_logger, 'msg',
                f1(wrapped_logger, 'msg', {'event': 'some_event', 'x': 42, 'y': 23})
             )
          )
       )
    )

In this case, `f4` has to make sure it returns something `wrapped_logger.msg` can handle (see Adapting and Rendering).

The simplest modification a processor can make is adding new values to the `event_dict`. Parsing human-readable timestamps is tedious, not so UNIX timestamps – let’s add one to each log entry!

    import calendar
    import time

    def timestamper(logger, log_method, event_dict):
        event_dict["timestamp"] = calendar.timegm(time.gmtime())
        return event_dict

Please note, that `structlog` comes with such an processor built in: `TimeStamper`.

## Filtering

If a processor raises `structlog.DropEvent`, the event is silently dropped.

Therefore, the following processor drops every entry:

    from structlog import DropEvent

    def dropper(logger, method_name, event_dict):
        raise DropEvent

But we can do better than that!

How about dropping only log entries that are marked as coming from a certain peer (e.g. monitoring)?

    from structlog import DropEvent

    class ConditionalDropper(object):
        def __init__(self, peer_to_ignore):
            self._peer_to_ignore = peer_to_ignore

        def __call__(self, logger, method_name, event_dict):
            """
            >>> cd = ConditionalDropper('127.0.0.1')
            >>> cd(None, None, {'event': 'foo', 'peer': '10.0.0.1'})
            {'peer': '10.0.0.1', 'event': 'foo'}
            >>> cd(None, None, {'event': 'foo', 'peer': '127.0.0.1'})
            Traceback (most recent call last):
            ...
            DropEvent
            """
            if event_dict.get('peer') == self._peer_to_ignore:
                raise DropEvent
            else:
                return event_dict

## Adapting and Rendering

An important role is played by the last processor because its duty is to adapt the `event_dict` into something the underlying logging method understands. With that, it’s also the only processor that needs to know anything about the underlying system.

It can return one of three types:

- A string that is passed as the first (and only) positional argument to the underlying logger.
- A tuple of `(args, kwargs)` that are passed as `log_method(*args, **kwargs)`.
- A dictionary which is passed as `log_method(**kwargs)`.

Therefore `return 'hello world'` is a shortcut for `return (('hello world',), {})` (the example in Chains assumes this shortcut has been taken).

This should give you enough power to use `structlog` with any logging system while writing agnostic processors that operate on dictionaries.

Changed in version 14.0.0: Allow final processor to return a dict.

### Examples

The probably most useful formatter for string based loggers is `JSONRenderer`. Advanced log aggregation and analysis tools like logstash offer features like telling them “this is JSON, deal with it” instead of fiddling with regular expressions.

More examples can be found in the examples chapter. For a list of shipped processors, check out the API documentation.

## Third Party Packages

Since processors are self-contained callables, it’s easy to write your own and to share them in separate packages. The following processor packages are known to be currently available on PyPI:

- structlog-pretty: Processors for prettier output – a code syntax highlighter, JSON and XML prettifiers, a multiline string printer, and a numeric value rounder.

Please feel free to submit a pull request to extend this list with your package!