Twisted¶
Warning
Since sys.exc_clear
has been dropped in Python 3, there is currently no way to avoid multiple tracebacks in your log files if using structlog together with Twisted on Python 3.
Note
structlog currently only supports the legacy – but still perfectly working – Twisted logging system found in twisted.python.log
.
Concrete bound logger¶
To make structlog’s behavior less magical, it ships with a Twisted-specific wrapper class that has an explicit API instead of improvising: structlog.twisted.BoundLogger
.
It behaves exactly like the generic structlog.BoundLogger
except:
it’s slightly faster due to less overhead,
hence causing less cryptic error messages if you get method names wrong.
In order to avoid that structlog disturbs your CamelCase harmony, it comes with an alias for structlog.get_logger
called structlog.getLogger
.
Processors¶
structlog comes with two Twisted-specific processors:
structlog.twisted.EventAdapter()
This is useful if you have an existing Twisted application and just want to wrap your loggers for now. It takes care of transforming your event dictionary into something twisted.python.log.err can digest.
For example:
def onError(fail): failure = fail.trap(MoonExploded) log.err(failure, _why="event-that-happened")
will still work as expected.
Needs to be put at the end of the processing chain. It formats the event using a renderer that needs to be passed into the constructor:
configure(processors=[EventAdapter(KeyValueRenderer()])
The drawback of this approach is that Twisted will format your exceptions as multi-line log entries which is painful to parse. Therefore structlog comes with:
structlog.twisted.JSONRenderer()
Goes a step further and circumvents Twisted logger’s Exception / Failure handling and renders it itself as JSON strings. That gives you regular and simple-to-parse single-line JSON log entries no matter what happens.
Bending foreign logging to your will¶
structlog comes with a wrapper for Twisted’s log observers to ensure the rest of your logs are in JSON too: structlog.twisted.JSONLogObserverWrapper
.
What it does is determining whether a log entry has been formatted by structlog.twisted.JSONRenderer
and if not, converts the log entry to JSON with event
being the log message and putting Twisted’s system
into a second key.
So for example:
2013-09-15 22:02:18+0200 [-] Log opened.
becomes:
2013-09-15 22:02:18+0200 [-] {"event": "Log opened.", "system": "-"}
There is obviously some redundancy here. Also, I’m presuming that if you write out JSON logs, you’re going to let something else parse them which makes the human-readable date entries more trouble than they’re worth.
To get a clean log without timestamps and additional system fields ([-]
), structlog comes with structlog.twisted.PlainFileLogObserver
that writes only the plain message to a file and structlog.twisted.plainJSONStdOutLogger
that composes it with the aforementioned structlog.twisted.JSONLogObserverWrapper
and gives you a pure JSON log without any timestamps or other noise straight to standard out:
$ twistd -n --logger structlog.twisted.plainJSONStdOutLogger web
{"event": "Log opened.", "system": "-"}
{"event": "twistd 13.1.0 (python 2.7.3) starting up.", "system": "-"}
{"event": "reactor class: twisted...EPollReactor.", "system": "-"}
{"event": "Site starting on 8080", "system": "-"}
{"event": "Starting factory <twisted.web.server.Site ...>", ...}
...
Suggested configuration¶
import structlog
structlog.configure(
processors=[
structlog.processors.StackInfoRenderer(),
structlog.twisted.JSONRenderer()
],
context_class=dict,
logger_factory=structlog.twisted.LoggerFactory(),
wrapper_class=structlog.twisted.BoundLogger,
cache_logger_on_first_use=True,
)
See also Logging Best Practices.