Loguru: Python logging without the handler boilerplate
Python logging made (stupidly) simple
At a glance
- What is it?
- Loguru replaces the standard library's logger, handler, formatter and filter setup with a single pre-configured logger object. It is a good fit for scripts and small services, and a worse fit for code that must hand its logs to an existing stdlib pipeline.
- Who is it for?
- Adopt Loguru for scripts, CLIs and small services where you control the whole logging setup and want file rotation without writing handler code. Do not adopt it if your logs must flow through an existing standard logging configuration, or if you need per-library logger namespaces that a third party controls.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Loguru removes: four objects to configure before one line of output
The standard logging module asks you to assemble a logger, at least one handler, a formatter, and usually a level filter before anything is written. Loguru's README states the library's aim plainly: to bring enjoyable logging in Python, and to let you start with `from loguru import logger`. The audience is anyone who has reached for `print()` because wiring a logger felt like more work than the debugging it would produce.
The design decision behind that is stated as a rule rather than a preference. According to the README, the main concept of Loguru is that there is one and only one `logger`. It is pre-configured and writes to `stderr` from the moment you import it. Nothing is registered, nothing is named, and there is no `getLogger(__name__)` call to make. That single object is described as an interface which dispatches messages to configured handlers, so the mental model is a fan-out point rather than a hierarchy of named loggers.
That is also where the trade-off lives. A single logger means the module name is not part of the logger identity. If you rely on `logging.getLogger(__name__)` to route one package's messages to one destination and another package's to a different one, Loguru does not give you that for free. It gives you `filter` on `add()` instead, which is a different mechanism with different semantics.
How logger.add() replaces handlers, formatters and filters
Everything configurable goes through one function. The README states it directly: how to add a handler, how to set up formatting, how to filter messages, how to set the level, one answer, the `add()` function. The signature shown in the README takes a sink plus `format`, `filter` and `level`:
logger.add(sys.stderr, format="{time} {level} {message}", filter="my_module", level="INFO")A sink is the destination. The README lists the forms it can take: a simple function, a string path, a file-like object, a coroutine function, or a built-in Handler. That last one is the compatibility seam. Because a stdlib Handler is an accepted sink, Loguru can push records into an existing logging pipeline rather than replacing it outright.
Each `add()` call returns an identifier, and `remove()` takes that identifier back. The README notes this is particularly useful for superseding the default `stderr` handler, and that calling `logger.remove()` with no argument makes a fresh start. If you never call `remove()`, the default sink stays active and your messages appear twice once you add a file sink.
Message formatting follows `str.format()` rather than percent style. The README's example is `logger.info("We discovered {} is the answer to {question}", 42, question="everything")`, and it notes that with recent Python versions you can also pass a template string. Log records are contextualized with a record dict, which is what the format fields draw from.
Installing Loguru and writing a first rotating log file
Installation is a single pip command. The README gives it as `pip install loguru` with no extra index or build step.
pip install loguruThe package is published on PyPI as `loguru`, the project metadata names it `loguru`, and the build backend is `flit_core`. The only declared runtime dependencies are conditional: `colorama` on Windows, `win32-setctime` on Windows, and `aiocontextvars` for Python below 3.7. On a current CPython or PyPy install on Linux or macOS, nothing else is pulled in.
A first real use is a script that logs to a rotating file. The README's file logging examples use a string path as the sink, with optional `rotation`, `retention` and `compression` arguments:
from loguru import logger
logger.remove()
logger.add("file_1.log", rotation="500 MB")
logger.add("file_X.log", retention="10 days")
logger.add("file_Y.log", compression="zip")
logger.info("We discovered {} is the answer to {question}", 42, question="everything")The `logger.remove()` call matters here. Without it, the default `stderr` sink is still registered and the same message also goes to the terminal. The rotation value is a string, not a number of bytes, and the README shows time-based values alongside size-based ones: `"12:00"` rotates each day at noon, `"1 week"` rotates once the file is old enough. Retention is separate from rotation, so a file can rotate on size while old files are deleted on age. The README does not document rollback of a rotation or what happens if the process dies mid-rotation.
Where Loguru is the wrong tool
The single-logger model is the main limitation, and it is a deliberate one. The README also describes Loguru as entirely compatible with standard logging, and a built-in Handler can be used as a sink. That compatibility runs one direction comfortably. If a framework or a third-party library configures the stdlib root logger and expects your application's records to arrive through it, you have to bridge explicitly rather than assume the two trees merge.
There is also a version floor worth reading carefully. The project metadata declares `requires-python = ">=3.5"` and the classifiers list Python 3.5 through 3.14 plus PyPy. Supporting that range is why `aiocontextvars` appears as a dependency for Python below 3.7. A dependency list that branches on interpreter version is a maintenance cost the project absorbs, not one you avoid.
One more caveat sits in the README itself. The feature list includes a struck-through entry for "10x faster than built-in logging". A strikethrough is a retraction, and the README does not replace it with a current performance claim. Anyone choosing Loguru for throughput reasons should treat the README as silent on that point rather than as evidence in either direction.
Finally, the FAQ section below covers whether Loguru is thread safe and async safe, because those are the questions the documentation answers and the ones that decide whether Loguru belongs in a concurrent service.
Loguru versus structlog and the standard logging module
The standard library's logging module is the baseline Loguru is reacting to. It gives you named logger hierarchies, a registry of loggers, and configuration through dictConfig or fileConfig. That structure is what makes it possible for a library to emit into a namespace the application controls. Loguru trades that structure for a single object and one configuration function. If your application is the only producer of logs, the trade is favourable. If you are writing a library that other applications will configure, the stdlib is the safer interface, because your users already know how to configure it.
Structlog takes a different route again. It is built around a chain of processors that transform an event dict before it is rendered, which makes structured output the primary representation and text the rendering. Loguru's README lists structured logging as a feature, described as available as needed, so structured output is something you opt into rather than the shape everything takes. For a codebase that wants every log line to be a JSON object from the start, a processor-chain design fits more naturally. For a codebase that wants readable text with the option of structure, Loguru's default is closer to what you get for free.
The comparison that matters least is line count. All three can be configured in a few lines. What differs is who owns the configuration and what shape the records have when they leave your code.
Maintenance, licence and upgrade cost
Loguru is MIT licensed, with the licence text in the repository root as `LICENSE` and the classifier `License :: OSI Approved :: MIT License` in `pyproject.toml`. MIT is permissive: it allows use, modification and redistribution provided the copyright notice and permission notice are retained. That is the extent of what can be said here; whether a specific redistribution satisfies the notice requirement is a question for your own legal review, not for this article.
The repository is not archived. The last push to the default branch, `master`, was on 2026-08-30. The most recent release listed is 0.7.3, published on 2024-12-06, following 0.7.2 on 2023-09-11 and 0.7.1 on 2023-09-04. Those dates together suggest a project that ships releases in bursts rather than on a schedule, with repository activity continuing between them.
Upgrade cost is shaped by the supported Python range. A library that still declares support back to 3.5 and forward to 3.14 is carrying compatibility branches, and the conditional dependencies on `aiocontextvars` and the Windows packages are visible evidence of that. Pinning Loguru and reading `CHANGELOG.rst` before a minor bump is cheap. The development setup in `pyproject.toml` pins tooling by interpreter version as well, including separate `tox` pins for Python below 3.8, 3.8 to 3.11, and 3.12 and above, which tells you the test matrix is version-segmented.
Editorial conclusion
Adopt Loguru for scripts, CLIs and small services where you control the whole logging setup and want file rotation without writing handler code. Do not adopt it if your logs must flow through an existing standard logging configuration, or if you need per-library logger namespaces that a third party controls. Before committing, verify how logger.remove() interacts with any stdlib handlers you already installed, and check that the level names you use exist in the levels table.
Frequently asked questions
What are the key differences between Python logging and Loguru?
The standard library makes you configure a logger, handler, formatter and filter separately, while Loguru provides one pre-configured logger that writes to stderr on import. In Loguru, adding a handler, setting the format, filtering messages and setting the level are all done through the single add() function.
What are the different log levels in Loguru?
Loguru's add() function accepts a level argument, shown in the README as level="INFO", and the README also lists customizable levels as a feature. The README does not enumerate the full set of built-in level names.
How do I install Loguru in Python?
The README gives the installation as a single command, pip install loguru. The package is published on PyPI under the name loguru and declares no unconditional runtime dependencies.
Is Loguru thread safe and async safe?
The README lists asynchronous, thread-safe and multiprocess-safe as a feature, and notes that a sink can be a coroutine function. The README does not describe the locking strategy behind that claim.
Is Loguru open source?
Yes. The repository carries an MIT licence, with the classifier License :: OSI Approved :: MIT License in pyproject.toml and the licence text at LICENSE in the repository root.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/delgan-loguru)