Opinionated structured logging library for Python with a fluent interface
Project description
Fluentlog
Opinionated structured logging for Python with a fluent API.
- API inspired by zerolog
- JSON output format
- OpenTelemetry naming conventions when relevant
- Near zero-cost for disabled log levels
Installation
pip install fluentlog
Getting Started
Simple example
import fluentlog
log = fluentlog.Logger().bind().int("request_id", 1).logger()
log.info().str("user", "jmcs").int("uid", 42).msg("user logged in")
# {"level":"INFO","request_id":1,"user":"jmcs","uid":42,"message":"user logged in"}
# Disabled levels have near-zero overhead
log.debug().func( expensive_func).msg("debug info") # expensive_func is never called
Log Levels
fluentlog supports the following log levels, from more to less critical:
FATAL: Errors the application can't recover fromERROR: Errors that make the current context fail, but not the entire applicationWARNING: Recoverable errorsINFO: Expected lifecycle events and relevant business signalsDEBUG: Internal details useful while diagnosing behavior during developmentTRACE: Very fine-grained execution details, usually only useful for deep debugging
You can set the log level for your logger either in the constructor or using a fluent method:
import fluentlog
log = fluentlog.Logger(level=fluentlog.Level.DEBUG)
# or
log = fluentlog.Logger().set_level(fluentlog.Level.DEBUG)
Logging context
import fluentlog
def some_func():
log = fluentlog.context()
log.info().msg("From func")
def main():
log = fluentlog.context().bind().str("context", "example").logger()
some_func()
# {"level":"INFO", "message": "From func"}
with fluentlog.context_logger(log):
some_func()
# {"level":"INFO", "context": "example", "message": "From func"}
main()
Performance
Benchmarks show ~2-3x faster than stdlib logging with formatted output, with greater advantages when log levels are filtered.
Design decisions
Why use different methods for different types?
Using different methods for different types allows for optimising serialization strategies for
mutable and immutable types. For example, dict() and list() deep-copy their arguments to prevent
mutations after the event is logged from affecting the output, while int() and str() can safely
reference immutable values directly without copying.
Why dummy events for disabled log levels?
Having dummy events achieves near-zero overhead, as we can avoid unnecessary processing without having to check the log level everywhere.
Why OpenTelemetry naming conventions?
I use OpenTelemetry for distributed tracing, and like consistent and precise naming, even when it comes at the cost of verbosity.
Why no formatted messages?
Formatted messages are familiar because that's how traditional logging usually works. But for structured logs they are a trap, as important data gets buried in strings instead of proper fields, which makes filtering and querying harder.
Why context-based logger passing?
Preserving logging context across boundaries is essential in complex applications, but having bound context inside a function is useful too. Context-based logger passing allows for both options and keeps things purposeful while avoiding cluttering application APIs.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fluentlog-0.1.0.tar.gz.
File metadata
- Download URL: fluentlog-0.1.0.tar.gz
- Upload date:
- Size: 14.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.5.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3c789846e4a2f8c7de247ba89729e0c3c9b389df8ea23fbb6c173a594880ae6
|
|
| MD5 |
77c846f5afee4ba130dbdab091f2da08
|
|
| BLAKE2b-256 |
899d33a42a4f35f8d434ed76ac05e5950bf858770d340fc8ede18de3c7657269
|
File details
Details for the file fluentlog-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fluentlog-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.5.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9ad44274e640815c45f46c119849dadfdbe6571af1428491bd57e286dd834d9
|
|
| MD5 |
dcf26f14ba958443543f6a5c3f17f29c
|
|
| BLAKE2b-256 |
bc0936864fdc9a9996cc65ae4321294d9d79a2c9795d7d44b4a19f47c112d809
|