diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 75bbbf78..b488ed05 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -45,7 +45,7 @@ It's people like *you* who make this project such a great tool for everyone. - Don't break [backwards-compatibility](SECURITY.md). -## Local Development Environment +## Local development environment First, **fork** the repository on GitHub and **clone** it using one of the alternatives that you can copy-paste by pressing the big green button labeled `<> Code`. @@ -224,7 +224,7 @@ If your change is interesting to end-users, there needs to be an entry in our `C ``` -## See You on GitHub! +## See you on GitHub! Again, this whole file is mainly to help you to get started by codifying tribal knowledge and expectations to save you time and turnarounds. It is **not** meant to be a barrier to entry, so don't be afraid to open half-finished PRs and ask questions if something is unclear! diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 4357414a..db9b7559 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -1,6 +1,6 @@ # Security Policy -## Supported Versions +## Supported versions We are following [*CalVer*](https://calver.org) with generous backwards-compatibility guarantees. Therefore we only support the latest version. @@ -13,7 +13,7 @@ They may be adjusted in the future to provide a better experience when starting So please make sure to **always** properly configure your applications. -## Reporting a Vulnerability +## Reporting a vulnerability To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. diff --git a/docs/bound-loggers.md b/docs/bound-loggers.md index ac7cb646..deb7254f 100644 --- a/docs/bound-loggers.md +++ b/docs/bound-loggers.md @@ -65,7 +65,7 @@ Whenever you call one of those methods on the *bound logger*, it will: [^str]: {any}`str`, {any}`bytes`, or {any}`bytearray` to be exact. -### Step-by-Step Example +### Step-by-Step example Assuming you've left the default configuration and have: @@ -103,7 +103,7 @@ If you call `log.info("Hello, %s!", "world", number=42)` now, the following happ (filtering)= -## Filtering by Log Levels +## Filtering by log levels Filtering based on log levels can be done in a processor very easily[^stdlib], however that means unnecessary performance overhead through function calls. We care a lot about performance and that's why *structlog*'s default *bound logger* class implements level-filtering as close to the users as possible: in the *bound logger*'s logging methods *before* even creating an *event dict* and starting the processor chain. @@ -146,7 +146,7 @@ Passing `20` instead of `logging.INFO` would have worked too. [^stdlib]: And it's in fact supported for standard library logging with the {func}`structlog.stdlib.filter_by_level` processor. -## Wrapping Loggers Manually +## Wrapping loggers manually In practice, you won't be instantiating bound loggers yourself. You will configure *structlog* as explained in the {doc}`next chapter ` and then just call {func}`structlog.get_logger`. diff --git a/docs/configuration.md b/docs/configuration.md index 9c750d05..ee4cf520 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -51,12 +51,12 @@ See also {doc}`performance`. ::: -## What To Configure +## What to configure You can find the details in the API documentation of {func}`structlog.configure`, but let's introduce the most important ones at a high level first. -### Wrapper Classes +### Wrapper classes You've met {doc}`bound-loggers` in the last chapter. They're the objects returned by {func}`~structlog.get_logger` and allow to bind key-value pairs into their private context. @@ -65,7 +65,7 @@ You can configure their type using the `wrapper_class` keyword. Whenever you bind or unbind data to a *bound logger*, this class is instantiated with the new context and returned. -### Logger Factories +### Logger factories We've already talked about wrapped loggers responsible for the output, but we haven't explained where they come from until now. Unlike with *bound loggers*, you often need more flexibility when instantiating them. diff --git a/docs/console-output.md b/docs/console-output.md index 302342a2..13985f40 100644 --- a/docs/console-output.md +++ b/docs/console-output.md @@ -34,7 +34,7 @@ For the console and beyond. (columns-config)= -## Console Output Configuration +## Console output configuration :::{versionadded} 23.3.0 ::: @@ -106,7 +106,7 @@ structlog.configure(processors=structlog.get_config()["processors"][:-1]+[cr]) ::: -## Standard Environment Variables +## Standard environment variables *structlog*'s default configuration uses colors if standard out is a TTY (that is, an interactive session). @@ -117,6 +117,6 @@ It's possible to override this behavior by setting two standard environment vari Please note that `NO_COLOR` disables _all_ styling, including bold and italics. -## Disabling Exception Pretty-Printing +## Disabling exception pretty-printing If you prefer the default terse Exception rendering, but still want Rich installed, you can disable the pretty-printing by instantiating {class}`structlog.dev.ConsoleRenderer()` yourself and passing `exception_formatter=structlog.dev.plain_traceback`. diff --git a/docs/contextvars.md b/docs/contextvars.md index caead6c9..10c1b1e9 100644 --- a/docs/contextvars.md +++ b/docs/contextvars.md @@ -101,7 +101,7 @@ def _helper(): (flask-example)= -## Example: Flask and Thread-Local Data +## Example: Flask and thread-local data Let's assume you want to bind a unique request ID, the URL path, and the peer's IP to every log entry by storing it in thread-local storage that is managed by context variables: diff --git a/docs/exceptions.md b/docs/exceptions.md index b32fcd86..7fe452ec 100644 --- a/docs/exceptions.md +++ b/docs/exceptions.md @@ -27,7 +27,7 @@ The most common use-cases are already covered by the following processors: : Uses {class}`structlog.tracebacks.ExceptionDictTransformer` to give you a structured and JSON-serializable `exception` key. -## Console Rendering +## Console rendering Our {doc}`console-output`'s {class}`structlog.dev.ConsoleRenderer` takes an *exception_formatter* argument that allows for customizing the output of exceptions. diff --git a/docs/getting-started.md b/docs/getting-started.md index 86a60987..d0042c98 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -16,7 +16,7 @@ Try both to find out which one you like better -- the screenshot in the README a On **Windows**, you also have to install [Colorama](https://pypi.org/project/colorama/) if you want colorful output beside exceptions. -## Your First Log Entry +## Your first log entry A lot of effort went into making *structlog* accessible without reading pages of documentation. As a result, the simplest possible usage looks like this: @@ -81,7 +81,7 @@ So let's go a step further. (building-ctx)= -## Building a Context +## Building a context Imagine a hypothetical web application that wants to log out all relevant data with just the APIs that we've introduced so far: @@ -167,7 +167,7 @@ For that, *structlog* gives you thread-local context storage based on the {mod}` See {doc}`contextvars` for more information and a more complete example. -## Manipulating Log Entries in Flight +## Manipulating log entries in flight Now that your log events are dictionaries, it's also much easier to manipulate them than if they were plain strings. @@ -212,7 +212,7 @@ So assuming you want to follow [best practices](logging-best-practices.md) and r ``` -## *structlog* and Standard Library's `logging` +## *structlog* and standard library's `logging` While *structlog*'s loggers are very fast and sufficient for the majority of our users, you're not bound to them. Instead, it's been designed from day one to wrap your *existing* loggers and **add** *structure* and *incremental context building* to them. diff --git a/docs/index.md b/docs/index.md index 1433430a..c9833440 100644 --- a/docs/index.md +++ b/docs/index.md @@ -62,7 +62,7 @@ exceptions ``` -## Development Affordances +## Development affordances *structlog*'s focus is on production systems, but it comes with **pretty console logging** and handy in-development helpers both for your **comfort** and your code's **quality**. @@ -77,7 +77,7 @@ typing (integration)= -## Integration with Existing Systems +## Integration with existing systems *structlog* is both zero-config as well as highly configurable. You can use it on its own or integrate with existing systems. @@ -93,7 +93,7 @@ twisted ``` -## *structlog* in Practice +## *structlog* in practice The following chapters deal with considerations of using *structlog* in the real world. @@ -121,7 +121,7 @@ modindex ``` -## Deprecated Features +## Deprecated features ```{toctree} :maxdepth: 1 diff --git a/docs/logging-best-practices.md b/docs/logging-best-practices.md index f018a9f6..70a7f2cc 100644 --- a/docs/logging-best-practices.md +++ b/docs/logging-best-practices.md @@ -14,7 +14,7 @@ It doesn't matter where or how your application runs -- it just works, and the r [^unix]: This is obviously a privileged UNIX-centric view but even Windows has tools and means for log management although we won't be able to discuss them here. -## Canonical Log Lines +## Canonical log lines Generally speaking, having as few log entries per request as possible is a good thing. The less noise, the more insights. @@ -24,7 +24,7 @@ The less noise, the more insights. At Stripe, this concept is called [Canonical Log Lines](https://brandur.org/canonical-log-lines). -## Pretty Printing vs. Structured Output +## Pretty printing vs. structured output Colorful and pretty printed log messages are nice during development when you locally run your code. @@ -61,7 +61,7 @@ Here is a simple example of how you can have pretty logs during development and ``` -## Centralized Logging +## Centralized logging Nowadays you usually don't want your log files in compressed archives distributed over dozens -- if not thousands -- of servers or cluster nodes. You want them in a single location. diff --git a/docs/processors.md b/docs/processors.md index 85b4118c..b5f1fc62 100644 --- a/docs/processors.md +++ b/docs/processors.md @@ -124,7 +124,7 @@ It does **not** use the standard library, but it does use its names and order of (adapting)= -## Adapting and Rendering +## Adapting and rendering An important role is played by the *last* processor because its duty is to adapt the `event_dict` into something the logging methods of the *wrapped logger* understand. With that, it's also the *only* processor that needs to know anything about the underlying system. @@ -156,7 +156,7 @@ Advanced log aggregation and analysis tools like [*Logstash*](https://www.elasti For a list of shipped processors, check out the {ref}`API documentation `. -## Third-Party Packages +## Third-Party packages *structlog* was specifically designed to be as composable and reusable as possible, so whatever you're missing: chances are, you can solve it with a processor! diff --git a/docs/recipes.md b/docs/recipes.md index adb4585c..29e786b8 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -7,7 +7,7 @@ Please note that recipes related to integration with frameworks have an [own cha (rename-event)= -## Renaming the `event` Key +## Renaming the `event` key The name of the event is hard-coded in *structlog* to `event`. But that doesn't mean it has to be called that in your logs. @@ -23,7 +23,7 @@ With the {class}`structlog.processors.EventRenamer` processor, you can, for inst (finer-filtering)= -## Fine-Grained Log-Level Filtering +## Fine-grained log-level filtering *structlog*'s native log levels as provided by {func}`structlog.make_filtering_bound_logger` only know **one** log level – the one that is passed to `make_filtering_bound_logger()`. Sometimes, that can be a bit too coarse, though. @@ -78,7 +78,7 @@ Pick the data you're interested in from the {class}`structlog.processors.Callsit (custom-wrappers)= -## Custom Wrappers +## Custom wrappers ```{testsetup} import structlog @@ -141,7 +141,7 @@ These two methods and one attribute are all you need to write own *bound loggers [dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself -## Passing Context to Worker Threads +## Passing context to worker threads Thread-local context data based on [context variables](contextvars.md) is -- as the name says -- local to the thread that binds it. When using threads to process work in parallel, you have to pass the thread-local context **into** the worker threads. @@ -188,7 +188,7 @@ def manager(request_id: str): See the [issue 425](https://github.com/hynek/structlog/issues/425) for a more complete example. -## Switching Console Output to Standard Error +## Switching console output to standard error When using structlog without standard library integration and want the log output to go to standard error (*stderr*) instead of standard out (*stdout*), you can switch with a single line of configuration: diff --git a/docs/standard-library.md b/docs/standard-library.md index 541fcdf6..3b307541 100644 --- a/docs/standard-library.md +++ b/docs/standard-library.md @@ -12,7 +12,7 @@ It will recreate the default configuration on top of `logging` and optionally co ::: -## Just Enough `logging` +## Just enough `logging` If you want to use *structlog* with `logging`, you should have at least a fleeting understanding on how the standard library operates because *structlog* will *not* do any magic things in the background for you. Most importantly you have to *configure* the `logging` system *additionally* to configuring *structlog*. @@ -35,7 +35,7 @@ This will send all log messages with the [log level](https://docs.python.org/3/l If you require more complex behavior, please refer to the standard library's `logging` documentation. -## Concrete Bound Logger +## Concrete bound logger *structlog* ships a stdlib-specific [*bound logger*](bound-loggers.md) that mirrors the log methods of standard library's {any}`logging.Logger` with correct type hints. @@ -125,7 +125,7 @@ To use it, {doc}`configure ` *structlog* to use `AsyncBoundLogger (stdlib-config)= -## Suggested Configurations +## Suggested configurations :::{note} We do appreciate that fully integrating *structlog* with standard library's `logging` is fiddly when done for the first time. @@ -137,7 +137,7 @@ However, once it is set up, you can rely on not having to ever touch it again. Depending *where* you'd like to do your formatting, you can take one of four approaches: -### Don't Integrate +### Don't integrate The most straight-forward option is to configure standard library `logging` close enough to what *structlog* is logging and leaving it at that. @@ -155,7 +155,7 @@ This can cause interleaving of log entries from *structlog* and `logging` logger ::: -### Rendering Within *structlog* +### Rendering within *structlog* This is the simplest approach where *structlog* does all the heavy lifting and passes a fully-formatted string to `logging`. Chances are, this is all you need. @@ -250,7 +250,7 @@ hello ``` -### Rendering Using `logging`-based Formatters +### Rendering using `logging`-based formatters You can choose to use *structlog* only for building the event dictionary and leave all formatting -- additionally to the output -- to the standard library. @@ -328,7 +328,7 @@ Keep this in mind if you only get the event name without any context, and except (processor-formatter)= -### Rendering Using *structlog*-based Formatters Within `logging` +### Rendering using *structlog*-based formatters within `logging` Finally, the most ambitious approach. Here, you use *structlog*'s {class}`~structlog.stdlib.ProcessorFormatter` as a {any}`logging.Formatter` for both `logging` as well as *structlog* log entries. diff --git a/docs/thread-local.md b/docs/thread-local.md index 3ed17dfa..227179e1 100644 --- a/docs/thread-local.md +++ b/docs/thread-local.md @@ -21,7 +21,7 @@ structlog.reset_defaults() ``` -## The `merge_threadlocal` Processor +## The `merge_threadlocal` processor *structlog* provides a simple set of functions that allow explicitly binding certain fields to a global (thread-local) context and merge them later using a processor into the event dict. @@ -43,7 +43,7 @@ These functions map 1:1 to the {doc}`contextvars` APIs, so please use those inst - {func}`structlog.contextvars.get_merged_contextvars` -## Thread-local Contexts +## Thread-local contexts *structlog* also provides thread-local context storage in a form that you may already know from [*Flask*](https://flask.palletsprojects.com/en/latest/design/#thread-locals) and that makes the *entire context* global to your thread or greenlet. @@ -51,7 +51,7 @@ This makes its behavior more difficult to reason about which is why we generally Therefore, there are currently no plans to re-implement this behavior on top of context variables. -### Wrapped Dicts +### Wrapped dicts In order to make your context thread-local, *structlog* ships with a function that can wrap any dict-like class to make it usable for thread-local storage: {func}`structlog.threadlocal.wrap_dict`. @@ -123,7 +123,7 @@ The state before the `with` statement is saved and restored once it's left. If you want to detach a logger from thread-local data, there's {func}`structlog.threadlocal.as_immutable`. -#### Downsides & Caveats +#### Downsides & caveats The convenience of having a thread-local context comes at a price though: diff --git a/docs/twisted.md b/docs/twisted.md index 8629a7f8..3c547264 100644 --- a/docs/twisted.md +++ b/docs/twisted.md @@ -9,7 +9,7 @@ Since `sys.exc_clear` has been dropped in Python 3, there is currently no way to ::: -## Concrete Bound Logger +## 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: @@ -56,7 +56,7 @@ In order to avoid that *structlog* disturbs your CamelCase harmony, it comes wit That gives you regular and simple-to-parse single-line JSON log entries no matter what happens. -## Bending Foreign Logging To Your Will +## 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`. @@ -89,7 +89,7 @@ $ twistd -n --logger structlog.twisted.plainJSONStdOutLogger web ... ``` -## Suggested Configuration +## Suggested configuration ```python import structlog diff --git a/docs/why.md b/docs/why.md index a1ac4135..5dd575f9 100644 --- a/docs/why.md +++ b/docs/why.md @@ -1,6 +1,6 @@ # Why … -## … Structured Logging? +## … structured logging? > I believe the widespread use of format strings in logging is based on two presumptions: > @@ -21,7 +21,7 @@ More general advice about production-grade logging can be found in the later cha ## … structlog? -### Easier Logging +### Easier logging You can stop writing prose and start thinking in terms of an event that happens in the context of key-value pairs: @@ -42,7 +42,7 @@ You can still use string interpolation using positional arguments: 2022-10-10 07:19:25 [info ] Hello, world! ``` -### Data Binding +### Data binding Since log entries are dictionaries, you can start binding and re-binding key-value pairs to your loggers to ensure they are present in every following logging call: @@ -56,7 +56,7 @@ Since log entries are dictionaries, you can start binding and re-binding key-val You can also bind key-value pairs to {doc}`context variables ` that look global, but are local to your thread or *asyncio* context -- which usually means your web request. -### Powerful Pipelines +### Powerful pipelines Each log entry goes through a [processor pipeline](processors.md) that is just a chain of functions that receive a dictionary and return a new dictionary that gets fed into the next function. That allows for simple but powerful data manipulation: @@ -103,7 +103,7 @@ Internally, formatters are processors whose return value (usually a string) is p Reported use cases are sending them out via network or saving them to a database. -### Highly Testable +### Highly testable *structlog* is thoroughly tested and we see it as our duty to help you to achieve the same in *your* applications. That's why it ships with a [test helpers](testing.md) to introspect your application's logging behavior with little-to-no boilerplate.