1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
# 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,
- has an explicit API ({func}`~structlog.twisted.BoundLogger.msg` and {func}`~structlog.twisted.BoundLogger.err`),
- 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:
{func}`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](https://docs.twisted.org/en/stable/api/twisted.python.log.html#err) can digest.
For example:
```python
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:
```python
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:
{func}`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]:
```console
$ 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
```python
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 {doc}`logging-best-practices`.
[standard out]: https://en.wikipedia.org/wiki/Standard_out#Standard_output_.28stdout.29
|