Loguru
La lib Python qui rend les logs plaisants : couleurs,
rotation, JSON, capture d'exceptions, le tout en une ligne d'import. Tout
ce que la stdlib logging demande 20 lignes pour configurer.
À quoi ça sert
Loguru est une lib externe (pip install loguru) avec une
philosophie : il existe un seul logger global déjà
configuré et coloré, prêt à l'emploi. Tu importes, tu loggues, c'est tout.
from loguru import logger
logger.info("démarrage")
logger.warning("attention")
logger.error("raté")
Aucune config, sortie déjà colorée, timestamp inclus. Le contrat est : 1 ligne pour démarrer, 1 ligne par option supplémentaire.
logging est plus flexible et universel
(toutes les libs Python l'utilisent), mais sa config initiale est
verbeuse. Loguru est plus simple, mais c'est une
dépendance externe et ses paramètres ne sont pas reconnus par les
libs tierces. En pratique : Loguru pour ton code, et on
intercepte les libs externes pour qu'elles passent par Loguru aussi
(voir how-to).
Le concept : sinks
Loguru appelle « sink » (puits) chaque destination où écrire un log : la console, un fichier, un service distant, une fonction Python… Tu en ajoutes autant que tu veux, et chaque sink peut filtrer par niveau et formater à sa manière.
- 1 sink console est créé par défaut au démarrage.
- Tu en ajoutes avec
logger.add(...). - Tu retires le sink par défaut avec
logger.remove()si tu veux tout reconfigurer.
Un exemple d'usage
Logger en console et dans un fichier qui tourne tous les jours, garde 7 jours, et compressé en zip :
from loguru import logger
logger.add(
"app_{time:YYYY-MM-DD}.log",
rotation="00:00", # nouveau fichier à minuit
retention="7 days", # supprime les + vieux que 7 jours
compression="zip", # compresse les anciens
level="INFO",
)
logger.info("prêt")
logger.debug("pas affiché car niveau INFO sur ce sink")
Voilà. En 3 lignes utiles tu as la rotation par date, la rétention, et l'archivage compressé — soit ~50 lignes à écrire en stdlib.
How-to : utiliser Loguru
-
Installer
bashuv add loguru -
Configurer en un point d'entrée
Au début de ton
main.py: on remove le sink par défaut puis on en ajoute deux (console + fichier) avec des niveaux et formats spécifiques.pythonimport sys from loguru import logger logger.remove() # enlève la config par défaut logger.add(sys.stderr, level="INFO", format="<green>{time:HH:mm:ss}</green> <level>{level}</level> {message}") logger.add("logs/app.log", level="DEBUG", rotation="10 MB", retention=10, # garder 10 fichiers encoding="utf-8")Le format Loguru utilise des balises
<color>pour la console, et{name}au lieu du%(name)sde stdlib. -
Logger en JSON pour Loki / Elasticsearch
En prod, on veut souvent du JSON pour pouvoir parser/rechercher. Loguru le fait avec
serialize=True:pythonlogger.add("logs/app.jsonl", serialize=True)Chaque ligne devient un objet JSON avec
{ "text": ..., "record": { "time": ..., "level": ..., "message": ..., "extra": {...} } }, prêt à être ingéré par Loki ou un agent Fluent Bit. -
Capturer automatiquement les exceptions
Le décorateur
@logger.catchlogge automatiquement toute exception qui sort de la fonction, avec stack trace, sans avoir à écrire untry/except.pythonfrom loguru import logger @logger.catch def traitement(x): return 1 / x traitement(0) # loggue l'exception en ERROR avec stack trace, n'arrête pas le programmePratique pour les tâches d'arrière-plan où tu veux logger le crash mais continuer à tourner.
-
Ajouter du contexte avec
bindOn veut souvent enrichir les logs avec une info récurrente : l'ID utilisateur, l'ID de requête, le nom du job…
logger.bind()crée un logger « pré-rempli » :pythonreq_logger = logger.bind(request_id="abc-123", user="olivier") req_logger.info("requête traitée") # Avec un format qui inclut {extra}, le contexte apparaîtra dans chaque ligne -
Intercepter les logs de la stdlib
Les libs externes (FastAPI, SQLAlchemy, requests…) utilisent
loggingde la stdlib. Pour qu'elles passent aussi par Loguru, on installe un handler intercepteur au démarrage. Snippet officiel à copier-coller :pythonimport logging from loguru import logger class InterceptHandler(logging.Handler): def emit(self, record): try: level = logger.level(record.levelname).name except ValueError: level = record.levelno logger.opt(depth=6, exception=record.exc_info).log( level, record.getMessage() ) logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True)À partir de là,
logging.getLogger("uvicorn").info(...)passe par Loguru et hérite de tes formatages. -
Formats temporels et rotations possibles
rotationetretentionacceptent plusieurs syntaxes — un des points forts de Loguru :python# rotation rotation="10 MB" # par taille rotation="1 day" # par durée rotation="00:00" # à une heure précise rotation="monday at 12:00" # par jour de semaine # retention retention="7 days" # supprimer après 7 jours retention=10 # garder 10 fichiers max # compression compression="zip" # ou "gz", "tar.gz", "bz2"...
Aide-mémoire
from loguru import logger
logger.debug("...")
logger.info("...")
logger.warning("...")
logger.error("...")
logger.critical("...")
logger.success("opé OK") # niveau spécifique Loguru
logger.remove() # reset
logger.add(sys.stderr, level="INFO")
logger.add("app.log", rotation="10 MB",
retention="7 days", compression="zip")
logger.add("app.jsonl", serialize=True) # JSON pour Loki
@logger.catch # auto-log les exceptions
def f(): ...
logger.bind(user="X").info("action") # contexte
logger.opt(colors=True).info("<green>ok</green>")
"{time:YYYY-MM-DD HH:mm:ss}"
"{level}" "{message}"
"{name}:{function}:{line}"
"{extra}" # dict des données bind()
Loguru et le reste de l'écosystème
- logging (stdlib) — la lib de base de Python. Loguru peut intercepter ses appels (voir how-to) pour que toutes les libs externes passent par lui.
-
Loki — combo classique :
Loguru écrit en JSON (
serialize=True), un agent (Promtail, Fluent Bit) lit le fichier, l'envoie à Loki, et Grafana affiche. -
FastAPI — on intercepte
les logs uvicorn et fastapi pour les unifier avec Loguru. Combiné
avec un middleware qui appelle
logger.bind(request_id=...), on a des logs corrélés par requête. - Celery — même chose : on intercepte le logger Celery pour que les logs de tâches sortent au même format que le reste.
- Prefect — Prefect a son propre système de logs intégré à son UI ; on garde Loguru pour le code métier à l'intérieur des tâches.
Trois cas où la stdlib reste plus adaptée : 1) une lib ou un framework que tu publies (ne pas imposer Loguru à tes utilisateurs), 2) des envs contraints qui interdisent les dépendances (CI minimal, lambdas custom), 3) un projet d'équipe où la convention est déjà stdlib. Partout ailleurs, Loguru gagne le ratio confort/coût.
Pour aller plus loin
- Dépôt officiel : github.com/Delgan/loguru
- Documentation : loguru.readthedocs.io
- Guide d'interception stdlib : section « compatible with standard logging »