I’m happy to announce the release of structlog 20.2.0! As the version indicates, I’ve published it in 2020, but I wanted to wait with the announcement until y’all are back to sober from celebrating the end of a hell of a year!
With more than half a million downloads per month, structlog is the most popular solution for structured logging in Python. It doesn’t just allow you to log key-value pairs in a structured manner, it also makes it EASIER and FASTER. Check out https://www.structlog.org/en/stable/why.html if you’re intruiged but not convinced!
Heartfelt thanks go to my generous GitHub sponsors https://github.com/sponsors/hynek, companies subscribing on Tidelift https://tidelift.com/subscription/pkg/pypi-structlog (currently nobody :( – tell your boss!), and people who bought me a coffee on https://ko-fi.com/the_hynek!
Additional SPECIAL thanks to Sentry https://sentry.io/ who were incredibly generous and included structlog in their FOSS financing round https://blog.sentry.io/2020/02/18/funding-open-source/! If you ever miss errors in production, check them out – I’ve been cheerleading for them since 2015!
Support like that makes me work on FOSS on a Saturday afternoon, so please consider supporting me https://hynek.me/say-thanks/ too! <3
20.2.0 took a long time to brew, but it’s a HUGE release. The main features of this release are:
- Full type hints coverage for all public and private APIs. - Non-blocking asyncio logger for standard library integration. Yes, your logging won’t block your asyncio applications anymore! - New high-performance logger that is independent from the standard library but has the same log levels. Here’re some microbenchmarks: https://twitter.com/hynek/status/1328338427121635329 (graphs follow in replies). - Prettier docs; courtesy of furo https://github.com/pradyunsg/furo. - Python 3.6+ only.
All Changes: ============
- Python 2.7 and 3.5 aren't supported anymore. The package meta data should ensure that you keep getting 20.1.0 on those versions. #244
- structlog is now fully type-annotated. This won't break your applications, but if you use Mypy, it will most likely break your CI.
Check out the new chapter on typing for details.
- Accessing the _context attribute of a bound logger is now deprecated. Please use the new structlog.get_context().
- structlog has now type hints for all of its APIs! Since structlog is highly dynamic and configurable, this led to a few concessions like a specialized structlog.stdlib.get_logger() whose only difference to structlog.get_logger() is that it has the correct type hints.
We consider them provisional for the time being – i.e. the backward compatibility does not apply to them in its full strength until we feel we got it right. Please feel free to provide feedback! #223, #282
- Added structlog.make_filtering_logger that can be used like configure(wrapper_class=make_filtering_bound_logger(logging.INFO)). It creates a highly optimized bound logger whose inactive methods only consist of a return None. This is now also the default logger.
- As a complement, structlog.stdlib.add_log_level() can now additionally be imported as structlog.processors.add_log_level since it just adds the method name to the event dict.
- structlog.processors.add_log_level() is now part of the default configuration.
- structlog.stdlib.ProcessorFormatter no longer uses exceptions for control flow, allowing foreign_pre_chain processors to use sys.exc_info() to access the real exception.
- Added structlog.BytesLogger to avoid unnecessary encoding round trips. Concretely this is useful with orjson which returns bytes. #271
- The final processor now also may return bytes that are passed untouched to the wrapped logger.
- structlog.get_context() allows you to retrieve the original context of a bound logger. #266,
- structlog.PrintLogger now supports copy.deepcopy(). #268
- Added structlog.testing.CapturingLogger for more unit testing goodness.
- Added structlog.stdlib.AsyncBoundLogger that executes logging calls in a thread executor and therefore doesn't block. #245