Logging is important no matter what application you’re writing or what language you’re working in. While Python does offer the logging library, it doesn’t really suit large-scale applications that use services like Datadog or Loki.

Structlog is a library that takes logging and makes your logs structured so that they’re machine-readable. Instead of emitting a flat string:

INFO:root:User 42 checked out order 9981

The library instead will write it as a dictionary with appropriate key-value pairs:

{
 "event": "checkout_completed", 
 "user_id": 42, 
 "order_id": 9981, 
 "timestamp": "2025-06-23T14:22:01Z", 
 "level": "info"
}

The benefits of using structlog

This package is beneficial for many reasons, with the most obvious being that applications like CloudWatch can index and query it easily; you can throw an LLM at it as well and have it write appropriate grep / find statements and have it do further analysis as well.

However, something that is more powerful is context binding, where you are able to attach shared context (such as a request ID) and it’ll show up on every log line that follows:

import structlog

log = structlog.get_logger()

def handle_request(request_id: str, user_id: int):
    bound_log = log.bind(
                    request_id=request_id, 
                    user_id=user_id
                )
    bound_log.info("request_started")

    # do things

    bound_log.info("request_completed", duration_ms=142)

Which will give us the following output (formatted to fit on screen):

{
 "event": "request_started",
 "request_id": "abc-123", 
 "user_id": 99
}
{
 "event": "request_completed", 
 "request_id": "abc-123", 
 "user_id": 99, 
 "duration_ms": 142
}

That request_id follows every log line without you having to pass it around manually and remembering to include it.

When should you use it?

If you're writing a quick script that runs once and exits, structlog is overkill. Stick with print() or basic logging.

But if any of these apply to your project, it's worth setting up:

  • You're running a web service (FastAPI, Flask, Django) and need to trace requests

  • You're shipping logs to a centralized platform (Datadog, Loki, CloudWatch, Splunk)

  • You're debugging issues that span multiple services or workers

  • You need to audit what happened for a specific user or transaction

It also plays well with Python's built-in logging module - you can wire them together so existing libraries that use logging still get their output captured alongside your structlog events.

If you want to go deeper, the official getting started guide is genuinely good and covers processors, async support, and testing.

Happy coding!

📧 Join the Python Snacks Newsletter! 🐍

Want even more Python-related content that’s useful? Here’s 3 reasons why you should subscribe the Python Snacks newsletter:

  1. Get Ahead in Python with bite-sized Python tips and tricks delivered straight to your inbox, like the one above.

  2. Exclusive Subscriber Perks: Receive a curated selection of up to 6 high-impact Python resources, tips, and exclusive insights with each email.

  3. Get Smarter with Python in under 5 minutes. Your next Python breakthrough could just an email away.

You can unsubscribe at any time.

Interested in starting a newsletter or a blog?

Do you have a wealth of knowledge and insights to share with the world? Starting your own newsletter or blog is an excellent way to establish yourself as an authority in your field, connect with a like-minded community, and open up new opportunities.

If TikTok, Twitter, Facebook, or other social media platforms were to get banned, you’d lose all your followers. This is why you should start a newsletter: you own your audience.

This article may contain affiliate links. Affiliate links come at no cost to you and support the costs of this blog. Should you purchase a product/service from an affiliate link, it will come at no additional cost to you.

Reply

Avatar

or to participate

Keep Reading