Releases: hynek/structlog
22.1.0
Highlights
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!
Full Changelog
Removed
- Python 3.6 is not supported anymore.
- Pickling is now only possible with protocol version 3 and newer.
Deprecated
-
The entire
structlog.threadlocal
module is deprecated. Please use the primitives fromstructlog.contextvars
instead.If you're using the modern APIs (
bind_threadlocal()
/merge_threadlocal()
) it's enough to replace them 1:1 with theircontextvars
counterparts. The old approach aroundwrap_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
Added
structlog.processors.StackInfoRenderer
now has an additional_ignores parameter that allows you to filter out your own logging layer. #396- Added
structlog.WriteLogger
, a faster – but more low-level – alternative tostructlog.PrintLogger
. It works the wayPrintLogger
used to work in previous versions. #403 #404 structlog.make_filtering_bound_logger()
-returned loggers now also have alog()
method to match thestructlog.stdlib.BoundLogger
signature closer. #413- Added structured logging of tracebacks via the
structlog.tracebacks
module, and most notably thestructlog.tracebacks.ExceptionDictTransformer
which can be used with the newstructlog.processors.ExceptionRenderer
to render JSON tracebacks. #407 structlog.stdlib.recreate_defaults(log_level=logging.NOTSET)
that recreatesstructlog
's defaults on top of standard library'slogging
. It optionally also configureslogging
to log to standard out at the passed log level. #428structlog.processors.EventRenamer
allows you to rename the hitherto hard-coded event dict keyevent
to something else. Optionally, you can rename another key toevent
at the same time, too. So addingEventRenamer(to="msg", replace_by="_event")
to your processor pipeline will rename the standardevent
key tomsg
and then rename the_event
key toevent
. This allows you to use theevent
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.
Changed
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 usesprint()
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 ofstructlog.processors.ExceptionRenderer
. Its behavior has not changed. #407- The default configuration now includes the
structlog.contextvars.merge_contextvars
processor. That means you can usestructlog.contextvars
features without configuringstructlog
.
Fixed
- Overloaded the
bind
,unbind
,try_unbind
andnew
methods in theFilteringBoundLogger
Protocol. This makes it easier to use objects of typeFilteringBoundLogger
in a typed context. #392 - Monkeypatched
sys.stdout
s are now handled more gracefully byConsoleRenderer
(that's used by default). #404 structlog.stdlib.render_to_log_kwargs()
now correctly handles the presence ofexc_info
,stack_info
, andstackLevel
in the event dictionary. They are transformed into proper keyword arguments instead of putting them into theextra
dictionary. #424, #427
21.5.0
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.
Changes:
- Added the
structlog.processors.LogfmtRenderer
processor to render log lines using the logfmt format. #376 - Added the
structlog.stdlib.ExtraAdder
processor that adds extra attributes oflogging.LogRecord
objects to the event dictionary. This processor can be used for adding data passed in theextra
parameter of thelogging
module's log methods to the event dictionary. #209 #377 - Added the
structlog.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. #380
21.4.0
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!
Changes:
21.3.0
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.
Backward-incompatible changes:
structlog
switched its packaging to flit. Users shouldn't notice a difference, but (re-)packagers might.
Deprecations:
none
Changes:
-
structlog.dev.ConsoleRenderer
now hassort_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 usesync_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 fromlogging.LogRecord
s and differentiate betweenstructlog
andlogging
log entries while processing them.The old processor (singular) parameter is now deprecated, but no plans exist to remove it. #365
21.2.0
Highlights
- Support for for beautiful (and helpful!) exceptions by integrating ConsoleRenderer with rich or better-exceptions.
- Helpers to access thread-local and context-local context.
- Deeper contextvars support.
Backward-incompatible changes:
-
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 configurestructlog
manually. This change is not really breaking, because the old use-case will keep working as before. However if you passpretty_exceptions=True
(which is the default if eitherrich
orbetter-exceptions
is installed), a warning will be raised and the exception will be renderered without prettyfication.
Deprecations:
none
Changes:
-
structlog
is now importable ifsys.stdout
isNone
(e.g. when running usingpythonw
). #313 -
structlog.threadlocal.get_threadlocal()
andstructlog.contextvars.get_contextvars()
can now be used to get a copy of the current thread-local/context-local context that has been bound usingstructlog.threadlocal.bind_threadlocal()
andstructlog.contextvars.bind_contextvars()
. #331 #337 -
structlog.threadlocal.get_merged_threadlocal(bl)
andstructlog.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 tocontextvars.Token
s, allowing you to reset values using the newstructlog.contextvars.reset_contextvars()
. #339 -
Exception rendering in
structlog.dev.ConsoleLogger
is now configurable using theexception_formatter
setting. If either the rich or the better-exceptions package is present,structlog
will use them for pretty-printing tracebacks.rich
takes precedence overbetter-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 instructlog.dev.ConsoleRenderer
on non-Windows systems. You can keep usingcolorama
to customize colors, of course. #345 -
The final processor can now return a
bytearray
(additionally tostr
andbytes
). #344
21.1.0
Backward-incompatible changes:
none
Deprecations:
none
Changes:
20.2.0
Backward-incompatible 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.
Deprecations:
- Accessing the
_context
attribute of a bound logger is now deprecated. Please use the newstructlog.get_context()
.
Changes:
-
structlog
has now type hints for all of its APIs! Sincestructlog
is highly dynamic and configurable, this led to a few concessions like a specializedstructlog.stdlib.get_logger()
whose only difference tostructlog.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 likeconfigure(wrapper_class=make_filtering_bound_logger(logging.INFO))
. It creates a highly optimized bound logger whose inactive methods only consist of areturn None
. This is now also the default logger. -
As a complement,
structlog.stdlib.add_log_level()
can now additionally be imported asstructlog.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, allowingforeign_pre_chain
processors to usesys.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 supportscopy.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