NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #269 most downloaded on PyPI
Structured Logging for Python
Last release 4 months ago
06 Jun 2026
Ships fairly regularly
a new release about every 3 months
Nearly every release is documented
notes for 43 of 43 stable releases
Nothing withdrawn
no release was ever pulled
13 years old
43 releases · first in 2013
Support for better-exceptions is deprecated and will be removed within a year. Use our Rich integration or copy-paste the one line of code you need .…
Given how long this release took, it's pretty thicc with nice things all over the board! Apologies for the long release cycle; it's been a victim of the slopocalypse and me trying to navigate my way thru the new normal. Extra big thanks to my sponsors for not abandoning me in these unironically trying times. ❤️
Full changelog below!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), Kraken Tech (@kraken-tech), Klaviyo (@klaviyo), Privacy Solutions GmbH (@privacy-solutions), FilePreviews (@filepreviews), Ecosystems (@ecosyste-ms), TestMu AI Open Source Office (Formerly LambdaTest) (@LambdaTest-Inc), GitHub (@github), Doist (@Doist), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).
Buttondown (@buttondown), Christopher Dignam (@chdsbd), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Rivo Laks (@rivol), Polar (@polarsource), Mike Fiedler (@miketheman), Duncan Hill (@cricalix), Colin Marquardt (@cmarqu), Pieter Swinkels (@swinkels), Nick Libertini (@libertininick), Brian M. Dennis (@crossjam), Al Sweigart (@asweigart), Celebrity News AG (@celebritynewsag), The Westervelt Company (@westerveltco), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Thomas Klinger (@thmsklngr), Andreas Poehlmann (@ap--), August Trapper Bigelow (@atbigelow), Carlton Gibson (@carltongibson), and Roboflow (@roboflow).
Python 3.15 support. #813
structlog.dev.rich_monochrome_traceback for Rich-based monochrome exception rendering and add support for it throughout structlog.dev.ConsoleRenderer when the user asks for no colors. #794
structlog.BytesLogger now has a name attribute which allows you to use it with the structlog.stdlib.add_logger_name() processor without using the standard library integration. #786
structlog.processors.CallsiteParameterAdder now supports CallsiteParameter.QUAL_MODULE that adds the qualified import name of the module of the callsite, or __main__ if the module is the entry point. This is only available for structlog-originated events since the standard library has no equivalent (except for the convention of setting the logger's name to __name__). #812
structlog.stdlib.BoundLogger now has is_enabled_for() and get_effective_level() methods that are snake_case aliases for its isEnabledFor() and getEffectiveLevel() methods. This makes it more compatible with the native structlog.typing.FilteringBoundLogger, so you can swap configurations without changing your call sites. #818
structlog.dev.ConsoleRenderer does not warn anymore when the exception key has a rendered value despite having a fancy formatter configured. #790structlog.BytesLogger, structlog.PrintLogger, and structlog.WriteLogger now hold weak references to the files they use for output. This prevents their leakage in long-running processes that open many logfiles, such as task executors that create a per-task BytesLogger or WriteLogger. #807
structlog.WriteLogger is usable after unpickling. #787
structlog.processors.CallsiteParameterAdder now reports the calling thread's id and name for async log methods, instead of the thread from the executor pool that runs the underlying sync logger. #710 #805
This release contains contributions from @ashb, @BlocksecPHD, @funkyfuture, @hynek, @JiwaniZakir, @sirosen, and @veeceey.
You can verify this release's artifact attestions using GitHub's CLI tool by downloading the sdist and wheel from PyPI and running:
$ gh attestation verify --owner hynek structlog-26.1.0.tar.gzand
$ gh attestation verify --owner hynek structlog-26.1.0-py3-none-any.whlOne column per quarter.
…the boolean pad_level argument. pad_event is now deprecated.
Huge release! There's plenty of important little bug fixes and new features, but the headliner is definitely the improved ergonomics of structlog.dev.ConsoleRenderer. We have finally accepted that local development has different priorities than production and made it both mutable (with automatic re-configuration) and also easily retrievable (cr = ConsoleRenderer.get_active()). This allows you, for example, to disable Rich exception formatting as easily as structlog.dev.ConsoleRenderer.get_active().exception_formatter = structlog.dev.plain_traceback. Please check out the updated docs!
Full changelog below!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), thanks.dev (@thnxdev), Privacy Solutions GmbH (@privacy-solutions), Quesma (@QuesmaOrg), FilePreviews (@filepreviews), LambdaTest (@LambdaTest-Inc), Doist (@Doist), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).
Buttondown (@buttondown), Jeff McCarrell (@jmccarrell), Christopher Dignam (@chdsbd), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Polar (@polarsource), Mike Fiedler (@miketheman), Duncan Hill (@cricalix), Colin Marquardt (@cmarqu), Pieter Swinkels (@swinkels), Nick Libertini (@libertininick), Brian M. Dennis (@crossjam), Celebrity News AG (@celebritynewsag), The Westervelt Company (@westerveltco), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Thomas Klinger (@thmsklngr), Andreas Poehlmann (@ap--), August Trapper Bigelow (@atbigelow), Carlton Gibson (@carltongibson), Roboflow (@roboflow), and Jeff McCarrell (@jmccarrell).
structlog.dev.ConsoleRenderer()'s pad_event argument has been renamed to pad_event_to to differentiate it from the boolean pad_level argument. pad_event is now deprecated.Added structlog.dev.ConsoleRenderer.get_active() that returns the currently active structlog.dev.ConsoleRenderer(). #749
structlog.dev.ConsoleRenderer() now supports setting the exception_formatter attribute.
You can now disable the pretty-printing of exceptions by setting it to structlog.dev.plain_traceback:
cr = structlog.dev.ConsoleRenderer.get_active()
cr.exception_formatter = structlog.dev.plain_tracebackSame goes for sort_keys, columns, colors, force_colors, level_styles, pad_event_to, event_key, timestamp_key, and repr_native_str.
Added structlog.dev.ConsoleRenderer.get_default_column_styles() for reuse the default column styles. #741
structlog.testing.capture_logs() now optionally accepts processors to apply before capture. #728
structlog.dev.RichTracebackFormatter now exposes the upstream code_width parameter. Default width is now None for full terminal width. Full terminal width is now handled by Rich itself, bringing support for reflow and COLUMN environment variable. Passing -1 for width is now deprecated and automatically replaced by None. #717
Native loggers now allow the passing of a dictionary for dictionary-based interpolation log.info("hello %(name)s!", {"name": "world"}). #748
On Python 3.11+, structlog.processors.CallsiteParameterAdder now supports CallsiteParameter.QUAL_NAME that adds the qualified name of the callsite, including scope and class names. This is only available for structlog-originated events since the standard library has no equivalent.
structlog.stdlib.LoggerFactory now supports the stacklevel parameter. #763
structlog.dev.rich_traceback() now throws a more helpful error when Rich is missing. #735structlog.processors.MaybeTimeStamper now respects the key argument when determining whether to overwrite the timestamp field. #747
structlog.tracebacks.extract() no longer raises a RecursionError when the cause chain of an exception contains itself. #739
Default config now respects FORCE_COLOR on Windows. #758
This release contains contributions from @agunnerson-elastic, @HairlessVillager, @hynek, @l1nd3r0th, @leonardo-panseri, and @noirbizarre.
You can verify this release's artifact attestions using GitHub's CLI tool by downloading the sdist and wheel from PyPI and running:
$ gh attestation verify --owner hynek structlog-25.5.0.tar.gzand
$ gh attestation verify --owner hynek structlog-25.5.0-py3-none-any.whlThe main feature is support for exception groups we stole adapted from Rich , however the main reason for this release at this point in time are backw
The main feature is support for exception groups we stole adapted from Rich, however the main reason for this release at this point in time are backwards-incompatible changes in the upcoming Python 3.13.4. Update structlog before updating Python, if you use structlog.stdlib.filter_by_level().
Full changelog below!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), Klaviyo (@klaviyo), Privacy Solutions GmbH (@privacy-solutions), FilePreviews (@filepreviews), Doist (@Doist), nate nowack (@zzstoatzz), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).
Buttondown (@buttondown), Christopher Dignam (@chdsbd), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Polar (@polarsource), Mike Fiedler (@miketheman), Duncan Hill (@cricalix), Colin Marquardt (@cmarqu), Pieter Swinkels (@swinkels), Nick Libertini (@libertininick), Brian M. Dennis (@crossjam), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), The Westervelt Company (@westerveltco), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Thomas Klinger (@thmsklngr), Andreas Poehlmann (@ap--), August Trapper Bigelow (@atbigelow), Carlton Gibson (@carltongibson), and Roboflow (@roboflow).
Not to forget 14 more amazing humans who chose to be generous but anonymous!
Support for Python 3.14 and Python 3.13.4.
Python 3.14 has an backwards-incompatible change to logging.Logger.isEnabledFor() (it now always returns False if a log entry is in flight) that has been backported to 3.13.4 (expected on 2025-06-03). It mainly affects structlog.stdlib.filter_by_level(). #723
structlog.tracebacks now handles exception groups. structlog.tracebacks.Stack has two new fields, is_group: bool and exceptions: list[Trace]. This works similarly to what Rich v14.0.0 does. #720
structlog.processors.ExceptionPrettyPrinter now respects the exception_formatter arguments instead of always using the default formatter. #724This release contains contributions from @anujdas, @hynek, and @sscherfke.
You can verify this release's artifact attestions using GitHub's CLI tool by downloading the sdist and wheel from PyPI and running:
$ gh attestation verify --owner hynek structlog-25.4.0.tar.gzand
$ gh attestation verify --owner hynek structlog-25.4.0-py3-none-any.whlThis fixes a rather ugly bug where seemingly UTC timestamps in TimeStamper had the timestamp from the local timezone when passing utc=True .
This fixes a rather ugly bug where seemingly UTC timestamps in TimeStamper had the timestamp from the local timezone when passing utc=True.
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), Klaviyo (@klaviyo), Privacy Solutions GmbH (@privacy-solutions), Andreas Jung (@zopyx), Ecosystems (@ecosyste-ms), FilePreviews (@filepreviews), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).
Buttondown (@buttondown), Christopher Dignam (@chdsbd), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Polar (@polarsource), Mike Fiedler (@miketheman), Duncan Hill (@cricalix), Colin Marquardt (@cmarqu), Pieter Swinkels (@swinkels), Nick Libertini (@libertininick), Brian M. Dennis (@crossjam), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), The Westervelt Company (@westerveltco), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Thomas Klinger (@thmsklngr), Andreas Poehlmann (@ap--), August Trapper Bigelow (@atbigelow), Carlton Gibson (@carltongibson), and Roboflow (@roboflow).
Not to forget 15 more amazing humans who chose to be generous but anonymous!
structlog.processors.TimeStamper now again uses timestamps using UTC for custom format strings when utc=True. #713This release contains contributions from @hynek, and @m-endra.
You can verify this release's artifact attestions using GitHub's CLI tool by downloading the sdist and wheel from PyPI and running:
$ gh attestation verify --owner hynek structlog-25.3.0.tar.gzand
$ gh attestation verify --owner hynek structlog-25.3.0-py3-none-any.whlQuick release before my travel frenzy! It seems like the boring fix to type hints of bind() et al is a fan favorite, though.
Quick release before my travel frenzy! It seems like the boring fix to type hints of bind() et al is a fan favorite, though.
Full changelog below!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), Ecosystems (@ecosyste-ms), Klaviyo (@klaviyo), Privacy Solutions GmbH (@privacy-solutions), FilePreviews (@filepreviews), nate nowack (@zzstoatzz), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).
Buttondown (@buttondown), Christopher Dignam (@chdsbd), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Polar (@polarsource), Mike Fiedler (@miketheman), Duncan Hill (@cricalix), Colin Marquardt (@cmarqu), Pieter Swinkels (@swinkels), Nick Libertini (@libertininick), Brian M. Dennis (@crossjam), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), The Westervelt Company (@westerveltco), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Thomas Klinger (@thmsklngr), Andreas Poehlmann (@ap--), August Trapper Bigelow (@atbigelow), Carlton Gibson (@carltongibson), and Roboflow (@roboflow).
Not to forget 14 more amazing humans who chose to be generous but anonymous!
structlog.tracebacks.Stack now includes an exc_notes field reflecting the notes attached to the exception. #684structlog.stdlib.BoundLogger's binding-related methods now also return Self. #694
structlog.processors.TimeStamper now produces internally timezone-aware datetime objects. Default output hasn't changed, but you can now use %z in your fmt string. #709
structlog.dev.RichTracebackFormatter for imports. #699structlog.processors.LogfmtRenderer for imports. #701This release contains contributions from @camillol, @hynek, @k4nar, @keongalvin, and @ttrei.
You can verify this release's artifact attestions using GitHub's CLI tool by downloading the sdist and wheel from PyPI and running:
$ gh attestation verify --owner hynek structlog-25.2.0.tar.gzand
$ gh attestation verify --owner hynek structlog-25.2.0-py3-none-any.whlLots of updates to exception handling that I hope will stabilize a bit now.
Lots of updates to exception handling that I hope will stabilize a bit now.
Full changelog below!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), Klaviyo (@klaviyo), FilePreviews (@filepreviews), Privacy Solutions GmbH (@privacy-solutions), Gedankenspieler (@Gedankenspieler), Daniel Fortunov (@asqui), Kevin P. Fleming (@kpfleming), and Polar (@polarsource).
Buttondown (@buttondown), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Chris Withers (@cjw296), Mike Fiedler (@miketheman), Duncan Hill (@cricalix), Colin Marquardt (@cmarqu), Pieter Swinkels (@swinkels), Nick Libertini (@libertininick), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), The Westervelt Company (@westerveltco), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Thomas Klinger (@thmsklngr), Andreas Poehlmann (@ap--), August Bigelow (@atbigelow), Carlton Gibson (@carltongibson), and Roboflow (@roboflow).
Not to forget 11 more amazing humans who chose to be generous but anonymous!
Add structlog.stdlib.render_to_log_args_and_kwargs processor. Same as structlog.stdlib.render_to_log_kwargs, but also allows to pass positional arguments to logging. With it, you do not need to add structlog.stdlib.PositionalArgumentsFormatter processor to format positional arguments from structlog loggers. #668
Native loggers now have is_enabled_for() and get_effective_level() methods that mirror the behavior of the standard library's logging.Logger.isEnabledFor() and logging.Logger.getEffectiveLevel(). #689
structlog.typing.BindableLogger protocol now returns Self instead of BindableLogger. This adds a dependency on typing-extensions for Pythons older than 3.11. #642 #659
structlog.dev.ConsoleRenderer will quote string value with special characters. #647
structlog.stdlib.recreate_defaults() now also adds structlog.stdlib.PositionalArgumentsFormatter. In default native mode, this is done by the loggers at the edge.
structlog.make_filtering_bound_logger() now also accepts a string for min_level.
Fix handling calls to {logger}.exception() outside of exception blocks. Depending on the structlog configuration, this either resulted in an event dict key exception: "MISSING" or lead to an error. Now, an invalid or missing exc_info will just be ignored. This means, that calling {logger}.exception() outside of an exception block is basically the same as calling {logger}.error(). #634 #680
Instantiating structlog.dev.ConsoleRenderer does not mutate the passed styles dict anymore. #669
The native FilteringBoundLogger.fatal() method now maps to the critical level, as it does in the standard library. Note that the level is discouraged to use there, so we recommend to stick to error() or critical(). #677
structlog.tracebacks.ExceptionDictTransformer now actually accepts None for locals_max_length and locals_max_string. #675
This release contains contributions from @aThorp96, @brcsw, @denis-savran, @emmanuel-ferdman, @hynek, @kain88-de, @Sh4pe, @sscherfke, @Tinche, @trim21, and @yaelmi3.
You can verify this release's artifact attestions using GitHub's CLI tool by downloading the sdist and wheel from PyPI and running:
$ gh attestation verify --owner hynek structlog-25.1.0.tar.gzand
$ gh attestation verify --owner hynek structlog-25.1.0-py3-none-any.whlThis is just a docs / PyPI README update. No code changes whatsoever.
This is just a docs / PyPI README update. No code changes whatsoever.
Full changelog below!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), FilePreviews (@filepreviews), Klaviyo (@klaviyo), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).
Adam Hill (@adamghill), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Mike Fiedler (@miketheman), Thomas Klinger (@thmsklngr), Duncan Hill (@cricalix), and Colin Marquardt (@cmarqu).
Not to forget 7 more amazing humans who chose to be generous but anonymous!
No code changes since 24.3.0
You can verify this release's artififact attestions using GitHub's CLI tool by downloading the sdist and wheel from PyPI and running:
$ gh attestation verify --owner hynek structlog-24.4.0.tar.gzand
$ gh attestation verify --owner hynek structlog-24.4.0-py3-none-any.whlThis is just a quick release so I can focus on my other projects. But do enjoy the improved traceback dict rendering and log level handling in testing
This is just a quick release so I can focus on my other projects. But do enjoy the improved traceback dict rendering and log level handling in testing!
Full changelog below!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), FilePreviews (@filepreviews), Klaviyo (@klaviyo), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).
Adam Hill (@adamghill), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Mike Fiedler (@miketheman), Thomas Klinger (@thmsklngr), Duncan Hill (@cricalix), and Colin Marquardt (@cmarqu).
Not to forget 7 more amazing humans who chose to be generous but anonymous!
Restore feature parity between structlog.traceback.ExceptionDictTransformer and Rich's traceback extractor:
repr() on strings, too (improves handling of SecretStr implementations).locals_max_length config optionlocals_hide_sunder config optionlocals_hide_dunder config optionsuppress config optionstructlog.testing.capture_logs() now maps the exception log level to error (as it's elsewhere). #628Overdue, and mostly bug fixes & optimizations! See y'all after my vacation. 🌴
Overdue, and mostly bug fixes & optimizations! See y'all after my vacation. 🌴
Full changelog below!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), FilePreviews (@filepreviews), Klaviyo (@klaviyo), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).
Adam Hill (@adamghill), Dan Groshev (@si14), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), Mike Fiedler (@miketheman), Thomas Klinger (@thmsklngr), Duncan Hill (@cricalix), and Colin Marquardt (@cmarqu).
Not to forget 7 more amazing humans who chose to be generous but anonymous!
It is now possible to disable log level-padding in structlog.dev.LogLevelColumnFormatter and structlog.dev.ConsoleRenderer. #599
The structlog.processors.CallsiteParameterAdder can now be pickled. #603
structlog.processors.CallsiteParameterAdder now also works with structlog.stdlib.BoundLogger's non-standard async methods (ainfo(), and so forth) #618
structlog.processors.LogfmtRenderer now escapes newlines. #592
structlog.processors.LogfmtRenderer now escapes backslashes and double quotes. #594
structlog.processors.CallsiteParameterAdder has been optimized to be about 2x faster. #606
structlog.stdlib.render_to_log_kwargs now correctly passes stacklevel as a kwarg to stdlib logging. #619This quick bugfix release fixes two regressions and the fact that RichTracebackFormatter has been ignoring its *width* argument the whole time.
This quick bugfix release fixes two regressions and the fact that RichTracebackFormatter has been ignoring its width argument the whole time.
Full changelog below!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), FilePreviews (@filepreviews), Daniel Fortunov (@asqui), Kevin P. Fleming (@kpfleming), and Sören Weber (@SoerenWeber).
Adam Hill (@adamghill), Dan Groshev (@si14), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Ionel Cristian Mărieș (@ionelmc), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Tim Schilling (@tim-schilling), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), and Mike Fiedler (@miketheman).
Not to forget 6 more amazing humans who chose to be generous but anonymous!
The lazy logger proxy returned by structlog.get_logger() now returns its initial values when asked for context. When asked for context before binding for the first time, it returned an empty dictionary in 23.3.0.
The displayed level name when using structlog.stdlib.BoundLogger.exception() is "error" instead of "exception". Fixes regression in 23.3.0. #584
Don't ignore the width argument of RichTracebackFormatter. #587
The highlight is the configurability of structlog.dev.ConsoleRenderer's output (check out !) and structlog.processors.CallsiteParameterAdder getting a
The highlight is the configurability of structlog.dev.ConsoleRenderer's output (check out https://www.structlog.org/en/stable/console-output.html#console-output-configuration!) and structlog.processors.CallsiteParameterAdder getting asyncio support.
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), FilePreviews (@filepreviews), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).
Adam Hill (@adamghill), Dan Groshev (@si14), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Ionel Cristian Mărieș (@ionelmc), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Tim Schilling (@tim-schilling), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), Sławomir Ehlert (@slafs), Mostafa Khalil (@khadrawy), Filip Mularczyk (@mukiblejlok), and Mike Fiedler (@miketheman).
Not to forget 6 more amazing humans who chose to be generous but anonymous!
The colorful development logger is now even more configurable! Choose freely your colors and the order of the key-value pairs! Implement your own formatters for certain keys!
Implementing the output on top of the new columns API has changed the default very slightly, but shouldn't be noticeable. #577
Async log methods (those starting with an a) now also support the collection of callsite information using structlog.processors.CallsiteParameterAdder. #565
structlog.stdlib.recreate_defaults() now also adds structlog.stdlib.add_logger_name to the processors. Check out the updated screenshot!The return value from get_logger() (a BoundLoggerLazyProxy) now passes isinstance-checks against structlog.typing.BindableLogger on Python 3.12. #561
structlog.threadlocal.tmp_bind() now also works with BoundLoggerLazyProxy (in other words: before anything is bound to a bound logger).
stdlib: ProcessorFormatter can now be told to not render the log record message using getMessage and just str(record.msg) instead. #550
stdlib: structlog.stdlib.BoundLogger.exception()'s handling ofLogRecord.exc_info is now set consistent with logging. #571 #572
Not a super exciting release, but it was time to deliver some fixes and quality-of-life features to the people!
Not a super exciting release, but it was time to deliver some fixes and quality-of-life features to the people!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), HiredScore (@HiredScore), FilePreviews (@filepreviews), Daniel Fortunov (@asqui), and Kevin P. Fleming (@kpfleming).
Adam Hill (@adamghill), Dan Groshev (@si14), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Tom Ballinger (@thomasballinger), Ionel Cristian Mărieș (@ionelmc), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Tim Schilling (@tim-schilling), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), Stefan Hagen (@sthagen), and Sławomir Ehlert (@slafs).
Not to forget 4 more amazing humans who chose to be generous but anonymous!
Official support for Python 3.12. #515
structlog.processors.MaybeTimeStamper that only adds a timestamp if there isn't one already. #81
structlog.dev.ConsoleRenderer now supports renamed timestamp keys using the timestamp_key parameter. #541
structlog.dev.RichTracebackFormatter that allows to configure the traceback formatting. #542
structlog.stdlib.AsyncBoundLogger will probably be deprecated in the future.
This release brings the hybrid approach to sync / async logging to structlog's standard library integration. You don't have to configure anything anymore, simply prepend the method name with an a and await it: await logger.ainfo("this is async!"). structlog.stdlib.AsyncBoundLogger will probably be deprecated in the future.
This release also brings support for FORCE_COLOR and NO_COLOR to structlog's default configuration. structlog was originally not meant to be used without configuration, but times have changed and we're breaking new ground!
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), Sentry (@getsentry), HiredScore (@HiredScore), FilePreviews (@filepreviews), and Daniel Fortunov (@asqui).
Adam Hill (@adamghill), Dan Groshev (@si14), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), Stein Magnus Jodal (@jodal), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Tom Ballinger (@thomasballinger), @medecau, Ionel Cristian Mărieș (@ionelmc), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Tim Schilling (@tim-schilling), Chris Withers (@cjw296), Christopher Dignam (@chdsbd), and Stefan Hagen (@sthagen).
Not to forget 2 more amazing humans who chose to be generous but anonymous!
structlog.stdlib.BoundLogger now has, analogously to our native logger, a full set of async log methods prefixed with an a: await log.ainfo("event!") #502
The default configuration now respects the presence of FORCE_COLOR (regardless of its value, unless an empty string). This disables all heuristics whether it makes sense to use colors. #503
The default configuration now respects the presence of NO_COLOR (regardless of its value, unless an empty string). This disables all heuristics whether it makes sense to use colors and overrides FORCE_COLOR. #504
ConsoleRenderer now reuses the _figure_out_exc_info to process the exc_info argument like ExceptionRenderer does. This prevents crashes if the actual Exception is passed for the exc_info argument instead of a tuple or True. #482
FilteringBoundLogger.aexception() now extracts the exception info using sys.exc_info() before passing control to the asyncio executor (where original exception info is no longer available). #488
This is bug-fix release due to overly-zealous string interpolation in the native bound logger. You can now pass anything as event again (but it really
This is bug-fix release due to overly-zealous string interpolation in the native bound logger. You can now pass anything as event again (but it really should be a string) and log % signs as long as you don't pass positional arguments.
This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), Sentry (@getsentry), HiredScore (@HiredScore), FilePreviews (@filepreviews), and Daniel Fortunov (@asqui).
@rzijp, Adam Hill (@adamghill), Dan Groshev (@si14), Tamir Bahar (@tmr232), Adi Roiban (@adiroiban), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), Stein Magnus Jodal (@jodal), Iwan Aucamp (@aucampia), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Thomas Ballinger (@thomasballinger), @medecau, Ionel Cristian Mărieș (@ionelmc), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Jannis Leidel (@jezdez), Tim Schilling (@tim-schilling), Chris Withers (@cjw296), and Christopher Dignam (@chdsbd).
Not to forget 2 more amazing humans who chose to be generous but anonymous!
FilteringBoundLogger (used by default) is now only attempted if positional arguments are passed. This prevents crashes if something different than a string is passed for the event argument. #475Accessing package metadata as attributes on the *structlog* module is deprecated (e.g. structlog.__version__). Please use `importlib.metadata` instead…
This is another (too) big release, but before I go into new features, allow me to beg you to check out structlog's documentation. I've spent easily half of the time on bringing is up to date, restructuring, and adding usage recipes. Not new in this release, but did you know that the standard library chapter has flowcharts that give you as visual explanations of how the various methods work? This is usually the biggest sticking point when starting to use structlog.
Feature-wise the big thing is that structlog's internal (and extremely fast) loggers (the one created using structlog.make_filtering_bound_logger() got two new features that people have asked for forever:
log.info("hello %s!", "world") works now!await log.ainfo("hello %s!", "world") is the same thing as above, but async.This release would not be possible without my generous sponsors! Thank you to all of you making sustainable maintenance possible! If you would like to join them, go to https://github.com/sponsors/hynek and check out the sweet perks!
Variomedia AG (@variomedia), Tidelift (@tidelift), Sentry (@getsentry), HiredScore (@HiredScore), FilePreviews (@filepreviews), and Daniel Fortunov (@asqui).
@rzijp, Adam Hill (@adamghill), Dan Groshev (@si14), Tamir Bahar (@tmr232), Adi Roiban (@adiroiban), Magnus Watn (@magnuswatn), David Cramer (@dcramer), Moving Content AG (@moving-content), Stein Magnus Jodal (@jodal), Iwan Aucamp (@aucampia), ProteinQure (@ProteinQure), Jesse Snyder (@jessesnyder), Rivo Laks (@rivol), Thomas Ballinger (@thomasballinger), @medecau, Ionel Cristian Mărieș (@ionelmc), The Westervelt Company (@westerveltco), Philippe Galvan (@PhilippeGalvan), Birk Jernström (@birkjernstrom), Jannis Leidel (@jezdez), Tim Schilling (@tim-schilling), Chris Withers (@cjw296), and Christopher Dignam (@chdsbd).
Not to forget 2 more amazing humans who chose to be generous but anonymous!
structlog.__version__). Please use importlib.metadata instead (for Python 3.7: the importlib-metadata PyPI package).structlog.types module is now deprecated in favor of the structlog.typing module. It seems like the Python typing community is settling on this name.FilteringBoundLogger (used by default) now allows for string interpolation using positional arguments:
>>> log.info("Hello %s! The answer is %d.", "World", 42, x=1)
2022-10-07 10:04.31 [info ] Hello World! The answer is 42. x=1
FilteringBoundLogger now also has support for asyncio-based logging. Instead of a wrapper class like structlog.stdlib.AsyncBoundLogger, async equivalents have been added for all logging methods. So instead of log.info("hello") you can also write await log.ainfo("hello") in async functions and methods.
This seems like the better approach and if it's liked by the community, structlog.stdlib.BoundLogger will get those methods too. #457
:) for seconds.The entire structlog.threadlocal module is deprecated. Please use the primitives from structlog.contextvars instead.
This is a (too) big release, so it has many highlights!
Firstly, rendering exceptions in machine-readable logs (usually JSON) got a big upgrade: thanks to structlog.processors.dict_tracebacks you can now have fully structured exceptions in your logs!
To ease getting started with structlog, we're now shipping structlog.stdlib.recreate_defaults() that recreates structlog's default behavior, but on top of standard library's logging. The output looks the same, but it runs through logging's machinery and integrates itself easier. The default configuration now also merges your contextvars-based context, so enjoy structlog.contextvars.bind_contextvars() without configuring anything!
Another request wish that kept coming up is naming the message key differently than event. We're aware that nowadays keys like msg are more common, but structlog pre-dates the software that introduced and popularized it. To allow for more consistency across your platforms, structlog now ships structlog.processors.EventRenamer that allows you to rename the default event key to something else and additionally also allows you to rename another key to event.
❤️ Huge thanks to my GitHub sponsors, Tidelift subscribers, and Ko-fi buyers! ❤️
None of my projects would exist in their current form without you!
The entire structlog.threadlocal module is deprecated. Please use the primitives from structlog.contextvars instead.
If you're using the modern APIs (bind_threadlocal() / merge_threadlocal()) it's enough to replace them 1:1 with their contextvars counterparts. The old approach around wrap_dict() has been discouraged for a while.
Currently there are no concrete plans to remove the module, but no patches against it will be accepted from now on. #409
structlog.processors.StackInfoRenderer now has an additional_ignores parameter that allows you to filter out your own logging layer. #396structlog.WriteLogger, a faster – but more low-level – alternative to structlog.PrintLogger. It works the way PrintLogger used to work in previous versions. #403 #404structlog.make_filtering_bound_logger()-returned loggers now also have a log() method to match the structlog.stdlib.BoundLogger signature closer. #413structlog.tracebacks module, and most notably the structlog.tracebacks.ExceptionDictTransformer which can be used with the new structlog.processors.ExceptionRenderer to render JSON tracebacks. #407structlog.stdlib.recreate_defaults(log_level=logging.NOTSET) that recreates structlog's defaults on top of standard library's logging. It optionally also configures logging to log to standard out at the passed log level. #428structlog.processors.EventRenamer allows you to rename the hitherto hard-coded event dict key event to something else. Optionally, you can rename another key to event at the same time, too. So adding EventRenamer(to="msg", replace_by="_event") to your processor pipeline will rename the standard event key to msg and then rename the _event key to event. This allows you to use the event key in your own log files and to have consistent log message keys across languages.structlog.dev.ConsoleRenderer(event_key="event") now allows to customize the name of the key that is used for the log message.structlog.make_filtering_bound_logger() now returns a method with the same signature for all log levels, whether they are active or not. This ensures that invalid calls to inactive log levels are caught immediately and don't explode once the log level changes. #401structlog.PrintLogger – that is used by default – now uses print() for printing, making it a better citizen for interactive terminal applications. #399structlog.testing.capture_logs now works for already initialized bound loggers. #408structlog.processors.format_exc_info() is no longer a function, but an instance of structlog.processors.ExceptionRenderer. Its behavior has not changed. #407structlog.contextvars.merge_contextvars processor. That means you can use structlog.contextvars features without configuring structlog.bind, unbind, try_unbind and new methods in the FilteringBoundLogger Protocol. This makes it easier to use objects of type FilteringBoundLogger in a typed context. #392sys.stdouts are now handled more gracefully by ConsoleRenderer (that's used by default). #404structlog.stdlib.render_to_log_kwargs() now correctly handles the presence of exc_info, stack_info, and stackLevel in the event dictionary. They are transformed into proper keyword arguments instead of putting them into the extra dictionary. #424, #427I didn't expect to make this release but @aucampia and @airwoodix contributed features that I'm sure will excite many users, so here's Santa Hynek 🎅 w
I didn't expect to make this release but @aucampia and @airwoodix contributed features that I'm sure will excite many users, so here's Santa Hynek 🎅 with a surprise release.
structlog.processors.LogfmtRenderer processor to render log lines using the logfmt format. #376structlog.stdlib.ExtraAdder processor that adds extra attributes of logging.LogRecord objects to the event dictionary. This processor can be used for adding data passed in the extra parameter of the logging module's log methods to the event dictionary. #209 #377structlog.processor.CallsiteParameterAdder processor that adds parameters of the callsite that an event dictionary orginated from to the event dictionary. This processor can be used to enrich events dictionaries with information such as the function name, line number and filename that an event dictionary orignated from. #380This release is mostly about a regression when importing using a Python interpreter running with the PYTHONOPTIMIZE=2 environment variable set, or as
This release is mostly about a regression when importing using a Python interpreter running with the PYTHONOPTIMIZE=2 environment variable set, or as python -OO. The one new feature is kinda neat too, though!
The old *processor* (singular) parameter is now deprecated, but no plans exist to remove it. #365
The main reason for this comparatively timely release is that aiohttp 3.8's new behavior of starting new loops within aiohttp.web.run_app() led to breakage in apps that use structlog.stdlib.AsyncBoundLogger.
The one big new feature though is the support for much more powerful processor chains within structlog.stdlib.ProcessorFormatter. This took me way too long to get right, but I'm excited to share it with you.
This is also the first release without a setup.py. Invoking it was never tested and never supported, so now it's gone. Please use standard packaging tools like PyPA's build or flit directly if you want to package structlog yourself.
structlog switched its packaging to flit. Users shouldn't notice a difference, but (re-)packagers might.none
structlog.dev.ConsoleRenderer now has sort_keys boolean parameter that allows to disable the sorting of keys on output. #358
structlog.processors.TimeStamper now works well with FreezeGun even when it gets applied before the loggers are configured. #364
structlog.stdlib.AsyncBoundLogger now determines the running loop when logging, not on instantiation. That has a minor performance impact, but makes it more robust when loops change (e.g. aiohttp.web.run_app()), or you want to use sync_bl before a loop has started.
structlog.stdlib.ProcessorFormatter now has a processors argument that allows to define a processor chain to run over all log entries.
Before running the chain, two additional keys are added to the event dictionary: _record and _from_structlog. With them it's possible to extract information from logging.LogRecords and differentiate between structlog and logging log entries while processing them.
The old processor (singular) parameter is now deprecated, but no plans exist to remove it. #365
Support for for beautiful (and helpful!) exceptions by integrating ConsoleRenderer with rich or better-exceptions.
To implement pretty exceptions (see Changes below), structlog.dev.ConsoleRenderer now formats exceptions itself.
Make sure to remove format_exc_info from your processor chain if you configure structlog manually. This change is not really breaking, because the old use-case will keep working as before. However if you pass pretty_exceptions=True (which is the default if either rich or better-exceptions is installed), a warning will be raised and the exception will be renderered without prettyfication.
none
structlog is now importable if sys.stdout is None (e.g. when running using pythonw). #313
structlog.threadlocal.get_threadlocal() and structlog.contextvars.get_contextvars() can now be used to get a copy of the current thread-local/context-local context that has been bound using structlog.threadlocal.bind_threadlocal() and structlog.contextvars.bind_contextvars(). #331 #337
structlog.threadlocal.get_merged_threadlocal(bl) and structlog.contextvars.get_merged_contextvars(bl) do the same, but also merge the context from a bound logger bl. Same pull requests as previous change.
structlog.contextvars.bind_contextvars() now returns a mapping of keys to contextvars.Tokens, allowing you to reset values using the new structlog.contextvars.reset_contextvars(). #339
Exception rendering in structlog.dev.ConsoleLogger is now configurable using the exception_formatter setting. If either the rich or the better-exceptions package is present, structlog will use them for pretty-printing tracebacks. rich takes precedence over better-exceptions if both are present.
This only works if format_exc_info is absent in the processor chain. #330 #349
All use of colorama on non-Windows systems has been excised. Thus, colors are now enabled by default in structlog.dev.ConsoleRenderer on non-Windows systems. You can keep using colorama to customize colors, of course. #345
The final processor can now return a bytearray (additionally to str and bytes). #344
structlog.threadlocal.wrap_dict() now has a correct type annotation. \#290
none
none
Accessing the _context attribute of a bound logger is now deprecated. Please use the new structlog.get_context().
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.
_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
_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 – that means the backwards-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.
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,
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
The default bound logger (wrapper_class) if you don't configure structlog has changed.
It's mostly compatible with the old one but a few uncommon methods like log, failure, or err don't exist anymore.
You can regain the old behavior by using structlog.configure(wrapper_class=structlog.BoundLogger).
Please note that due to the various interactions between settings, it's possible that you encounter even more errors. We strongly urge you to always configure all possible settings since the default configuration is not covered by our backwards-compatibility policy.
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.
structlog.PrintLogger now supports copy.deepcopy().
#268This is the last version to support Python 2.7 (including PyPy) and 3.5. All following versions will only support Python 3.6 or later.
structlog.contextvars that allows to have a global but context-local structlog context the same way as with structlog.threadlocal since 19.2.0.
#201,
#236structlog.testing for first class testing support.
The first entry is the context manager capture_logs() that allows to make assertions about structured log calls.
#14,
#234structlog.threadlocal.unbind_threadlocal().
#239Python 3.4 is not supported anymore. It has been unsupported by the Python core team for a while now and its PyPI downloads are negligible.
Python 3.4 is not supported anymore. It has been unsupported by the Python core team for a while now and its PyPI downloads are negligible.
It's very unlikely that structlog will break under 3.4 anytime soon, but we don't test it anymore.
structlog.stdlib.structlog.stdlib.BoundLogger. To makes it easier to use it as a drop-in replacement for logging.Logger.
#198structlog.dev.set_exc_info() that will set exc_info=True if the method's name is exception and exc_info isn't set at all.
This is only necessary when the standard library integration is not used.
It fixes the problem that in the default configuration, structlog.get_logger().exception("hi") in an except block would not print the exception without passing exc_info=True to it explicitly.
#130,
#173,
#200,
#204bind().
#222,
#225structlog.stdlib.ProcessorFormatter. It allows to pass a foreign log record's args attribute to the event dictionary under the positional_args key.
#228structlog.stdlib.ProcessorFormatter now takes a logger object as an optional keyword argument.
This makes ProcessorFormatter work properly with stuctlog.stdlib.filter_by_level().
#219structlog.dev.ConsoleRenderer now calls str() on the event value. #221structlog.dev.ConsoleRenderer now uses no colors by default, if Colorama is not available.
#215
structlog.dev.ConsoleRenderer now initializes Colorama lazily, to prevent accidental side-effects just by importing structlog.
#210
A best effort has been made to make as much of structlog pickleable as possible to make it friendlier with multiprocessing and similar libraries.
Some classes can only be pickled on Python 3 or using the dill library though and that is very unlikely to change.
So far, the configuration proxy, structlog.processor.TimeStamper, structlog.BoundLogger, structlog.PrintLogger and structlog.dev.ConsoleRenderer have been made pickleable.
Please report if you need any another class fixed.
#126
structlog.ReturnLogger and structlog.PrintLogger now have a fatal() log method. #181
structlog.ReturnLogger and structlog.PrintLogger now have a fatal() log method.
#181pip install -e .[dev] now installs all development dependencies.
Sorry for the inconveniences this undoubtedly will cause!dicts to stdlib logging.
#187,
#188,
#189SystemError: error return without exception set.
A workaround has been added.
#174Added structlog.stdlib.add_log_level_number() processor that adds the level *number* to the event dictionary. Can be used to simplify log filtering. #
structlog.stdlib.add_log_level_number() processor that adds the level number to the event dictionary.
Can be used to simplify log filtering.
#151structlog.processors.JSONRenderer now allows for overwriting the default argument of its serializer.
#77,
#163try_unbind() that works like unbind() but doesn't raise a KeyError if one of the keys is missing.
#171The meaning of the structlog[dev] installation target will change from "colorful output" to "dependencies to develop *structlog*" in 19.1.0.
The meaning of the structlog[dev] installation target will change from "colorful output" to "dependencies to develop structlog" in 19.1.0.
The main reason behind this decision is that it's impossible to have a structlog in your normal dependencies and additionally a structlog[dev] for development (pip will report an error).
structlog.dev.ConsoleRenderer now accepts a force_colors argument to output colored logs even if the destination is not a tty.
Use this option if your logs are stored in files that are intended to be streamed to the console.structlog.dev.ConsoleRenderer now accepts a level_styles argument for overriding the colors for individual levels, as well as to add new levels.
See the docs for ConsoleRenderer.get_default_level_styles() for usage.
#139structlog.is_configured() to check whether or not structlog has been configured.structlog.get_config() to introspect current configuration.structlog.stdlib.BoundLogger.exception() now uses the exc_info argument if it has been passed instead of setting it unconditionally to True. #149dicts on Python 3.6+ and PyPy since they are ordered by default.structlog.stdlib.ProcessorFormatter now accepts *keep_exc_info* and *keep_stack_info* arguments to control what to do with this information on log rec
structlog.stdlib.ProcessorFormatter now accepts keep_exc_info and keep_stack_info arguments to control what to do with this information on log records.
Most likely you want them both to be False therefore it's the default.
#109structlog.stdlib.add_logger_name() now works in structlog.stdlib.ProcessorFormatter's foreign_pre_chain.
#112structlog.stdlib.ProcessorFormatter after rendering.
This fix is for you if you tried to use it and got TypeError: not all arguments converted during string formatting exceptions.
#116,
#117The main features of this release are massive improvements in standard library's logging integration. Have a look at the updated standard library chap
The main features of this release are massive improvements in standard library's logging integration.
Have a look at the updated standard library chapter on how to use them!
Special thanks go to Fabian Büchler, Gilbert Gilb's, Iva Kaneva, insolite, and sky-code, that made them possible.
structlog.stdlib.render_to_log_kwargs().
This allows you to use logging-based formatters to take care of rendering your entries.
#98structlog.stdlib.ProcessorFormatter which does the opposite: This allows you to run structlog processors on arbitrary logging.LogRecords.
#79,
#105structlog.processors.KeyValueRenderer and structlog.dev.ConsoleRenderer.
This allows for human-readable non-ASCII output on Python 2 (repr() on Python 2 behaves like ascii() on Python 3 in that regard).
As per compatibility policy, it's on (original behavior) in KeyValueRenderer and off (human-friendly behavior) in ConsoleRenderer.
#94structlog.dev.ConsoleRenderer and made it the default renderer.
#78structlog.dev.ConsoleRenderer if you don't configure structlog.
Colors are used if available and human-friendly timestamps are prepended.
This is in line with our backwards-compatibility policy that explicitly excludes default settings.structlog.processors.TimeStamper are more precise now.Python 3.3 and 2.6 aren't supported anymore. They may work by chance but any effort to keep them working has ceased.
Python 3.3 and 2.6 aren't supported anymore. They may work by chance but any effort to keep them working has ceased.
The last Python 2.6 release was on October 29, 2013 and isn't supported by the CPython core team anymore. Major Python packages like Django and Twisted dropped Python 2.6 a while ago already.
Python 3.3 never had a significant user base and wasn't part of any distribution's LTS release.
drop_missing argument to KeyValueRenderer.
If key_order is used and a key is missing a value, it's not rendered at all instead of being rendered as None.
#67__traceback__ are now also rendered on Python 3.get_logger().
This lead to in-place mutation of them if used before configuration which in turn lead to the problem that configuration was applied only partially to them later.
#72Added structlog.dev.ConsoleRenderer that renders the event dictionary aligned and with colors.
structlog.dev.ConsoleRenderer that renders the event dictionary aligned and with colors.structlog.processors.UnicodeDecoder that will decode all byte string values in an event dictionary to Unicode.serializer parameter to structlog.processors.JSONRenderer which allows for using different (possibly faster) JSON encoders than the standard library.structlog.processors.ExceptionPrettyPrinter and structlog.processors.format_exc_info now support passing of Exceptions on Python 3.Added structlog.ReturnLogger.failure and structlog.PrintLogger.failure as preparation for the new Twisted logging system.
structlog.ReturnLogger.failure and structlog.PrintLogger.failure as preparation for the new Twisted logging system.__name__, better.
#58Added option to specify target key in structlog.processors.TimeStamper processor. #51
structlog.processors.TimeStamper processor.
#51logging.Logger.exception within structlog.
#52log.err from quoting strings rendered by structlog.twisted.JSONRenderer.Tolerate frames without a __name__ when guessing callsite names.
__name__ when guessing callsite names.Added structlog.stdlib.add_log_level and structlog.stdlib.add_logger_name processors. #44
structlog.stdlib.add_log_level and structlog.stdlib.add_logger_name processors.
#44structlog.stdlib.BoundLogger.log.
#42structlog.stdlib.BoundLogger.exception.
#22Drop support for Python 3.2. There is no justification to add complexity for a Python version that nobody uses. If you are one of the 0.350% that use
structlog.PrintLogger now is thread-safe.from structlog import * works now (but you still shouldn't use it).Don't cache proxied methods in structlog.threadlocal._ThreadLocalDictWrapper. This doesn't affect regular users.
structlog.threadlocal._ThreadLocalDictWrapper. This doesn't affect regular users.Added structlog.processors.StackInfoRenderer for adding stack information to log entries without involving exceptions. Also added it to default proces
structlog.processors.StackInfoRenderer for adding stack information to log entries without involving exceptions.
Also added it to default processor chain.
#6structlog.get_logger that are passed to logger factories.
The standard library factory uses this for explicit logger naming.
#12structlog.processors.ExceptionPrettyPrinter for development and testing when multiline log entries aren't just acceptable but even helpful.### Fixed - Fix stdlib's name guessing.
Added forgotten structlog.processors.TimeStamper to API documentation.
structlog.processors.TimeStamper to API documentation.Greatly enhanced and polished the documentation and added a new theme based on Write The Docs, requests, and Flask.
structlog.stdlib.BoundLogger.structlog.ReturnLogger now allows arbitrary positional and keyword arguments.structlog.twisted.BoundLogger.structlog.get_logger and structlog.wrap_logger to cache the BoundLogger they assemble according to configuration on first use.
See the chapter on performance and the cache_logger_on_first_use argument of structlog.configure and structlog.wrap_logger.structlog.BoundLoggerBase.Add key_order option to structlog.processors.KeyValueRenderer for more predictable log entries with any dict class.
key_order option to structlog.processors.KeyValueRenderer for more predictable log entries with any dict class.structlog.twisted.JSONRenderer without abusing __repr__.structlog.PrintLogger now uses proper I/O routines and is thus viable not only for examples but also for production.Initial release.
Initial release.
Your coding agent can read these notes before it upgrades. Set up the MCP server →