Hide navigation sidebar
Hide table of contents sidebar
Skip to content
Back to top
Toggle table of contents sidebar

# Configuration

The focus of structlog has always been to be flexible to a fault. The goal is that a user can use it with any logger of their own that is wrapped by structlog.

That’s the reason why there’s an overwhelming amount of knobs to tweak, but – ideally – once you find your configuration, you don’t touch it ever again and, more importantly: don’t see any of it in your application code.

Let’s start at the end and introduce the ultimate convenience function that relies purely on configuration: `structlog.get_logger()`.

The goal is to reduce your per-file application logging boilerplate to:

    import structlog

    logger = structlog.get_logger()

To that end, you’ll have to call `structlog.configure()` on app initialization. You can call `structlog.configure()` repeatedly and only set one or more settings – the rest will not be affected.

If necessary, you can always reset your global configuration back to default values using `structlog.reset_defaults()`. That can be handy in tests.

At any time, you can check whether and how structlog is configured using `structlog.is_configured()` and `structlog.get_config()`}:

    >>> structlog.is_configured()
    False
    >>> structlog.configure(logger_factory=structlog.stdlib.LoggerFactory())
    >>> structlog.is_configured()
    True
    >>> cfg = structlog.get_config()
    >>> cfg["logger_factory"]
    <class 'structlog.stdlib.LoggerFactory'>

Important

Since you’ll call `structlog.get_logger()` in module scope, it runs at import time before you had a chance to configure structlog. Therefore it returns a lazy proxy that returns a correctly configured bound logger on its first call to one of the context-managing methods like `bind()`.

Thus, you must never call `new()` or `bind()` in module or class scope because , you will receive a logger configured with structlog’s default values. Use `get_logger()`’s `initial_values` to achieve pre-populated contexts.

To enable you to log with the module-global logger, it will create a temporary bound logger on each call. Therefore if you have nothing to bind but intend to do lots of log calls in a function, it makes sense performance-wise to create a local logger by calling `bind()` or `new()` without any parameters. See also Performance.

## What to configure

You can find the details in the API documentation of `structlog.configure()`, but let’s introduce the most important ones at a high level first.

### Wrapper classes

You’ve met Bound Loggers in the last chapter. They’re the objects returned by `get_logger()` and allow to bind key-value pairs into their private context. 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

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. Therefore you don’t configure a class; you configure a factory using the `logger_factory` keyword.

It’s a callable that returns the logger that gets wrapped and returned. In the simplest case, it’s a function that returns a logger – or just a class. But you can also pass in an instance of a class with a `__call__` method for more complicated setups.

The arguments you pass to `structlog.get_logger()` will be passed to the logger factory. For example, if you use `structlog.get_logger("a name")` and configure structlog to use the standard library `LoggerFactory`, which has support for positional parameters, the returned logger will have the name `"a name"`.

For the common cases of standard library logging and Twisted logging, structlog comes with two factories built right in:

- `structlog.stdlib.LoggerFactory`

- `structlog.twisted.LoggerFactory`

So all it takes to use standard library `logging` for output is:

    >>> from structlog import get_logger, configure
    >>> from structlog.stdlib import LoggerFactory
    >>> configure(logger_factory=LoggerFactory())
    >>> log = get_logger()
    >>> log.critical("this is too easy!")
    event='this is too easy!'

By using structlog’s `structlog.stdlib.LoggerFactory`, it is also ensured that variables like function names and line numbers are expanded correctly in your log format. See Standard Library Logging for more details.

Calling `structlog.get_logger()` without configuration gives you a perfectly useful `structlog.PrintLogger`. We don’t believe silent loggers are a sensible default.

### Processors

You will meet Processors in the next chapter. They are configured using the `processors` keyword that takes an `Iterable` of callables that act as processors.