Cursus
Vous avez passé toute votre carrière de programmeur à déboguer avec des instructions « print()
». Vous avez peut-être essayé une ou deux fois le module de journalisation de Python, mais vous êtes revenu aux impressions car elles sont plus simples.
Il existe en réalité une solution plus efficace et tout aussi simple à utiliser.
Les relevés imprimés ne peuvent pas être enregistrés dans des fichiers ni activés ou désactivés facilement. La fonctionnalité de journalisation intégrée à Python permet d'effectuer ces opérations, mais nécessite l'écriture d'un code de configuration plus long que votre programme lui-même.
Loguru adopte une approche différente : la journalisation doit être aussi simple que l'impression, mais bien plus utile. Vous bénéficiez de couleurs dans votre terminal, d'horodatage automatique et de la possibilité d'enregistrer toutes les données dans des fichiers sans avoir à écrire une seule ligne de configuration.
Dans ce tutoriel, je vais vous présenter des exemples pratiques qui rendent la journalisation naturelle et non contraignante. Vous découvrirez des fonctionnalités dont vous ignoriez probablement l'existence, grâce à des modèles de code qui facilitent réellement le débogage.
Si vous débutez dans le débogage Python ou souhaitez renforcer vos compétences fondamentales, l'acquisition de bases solides en Python vous aidera à comprendre quand et pourquoi la journalisation est nécessaire.
Premiers pas avec Loguru : Configuration automatique
L'installation de Loguru nécessite une seule commande :
pip install loguru
Avec le module d' logging
standard, vous devez configurer les gestionnaires, les formateurs et tous les autres paramètres avant de pouvoir afficher un seul message de journal.
Pour une comparaison plus approfondie des approches de journalisation intégrées à Python, veuillez consulter ce tutoriel complet sur la journalisation qui couvre les méthodes traditionnelles.
Avec Loguru, il vous suffit d'importer et de commencer l'enregistrement :
from loguru import logger
# Instead of print("Processing user data...")
logger.info("Processing user data...")
# Instead of print(f"Found {count} records")
logger.info("Found {} records", count)
La sortie s'affiche dans votre terminal avec des couleurs, des horodatages et des niveaux de journalisation automatiques. Aucune configuration requise.
Supposons que vous développiez un simple outil de collecte de données sur le Web. Voici comment votre débogage change :
import requests
from loguru import logger
def scrape_website(url):
logger.info("Starting scrape for {}", url)
response = requests.get(url)
logger.debug("Response status: {}", response.status_code)
if response.status_code == 200:
logger.success("Successfully scraped {} characters", len(response.text))
return response.text
else:
logger.error("Failed to scrape {}: status {}", url, response.status_code)
return None
Veuillez noter les différents niveaux de journalisation (info
, debug
, success
, error
) et le formatage avec des accolades. Tout fonctionne immédiatement, sans fichiers de configuration ni code d'installation.
Enregistrement et rotation des fichiers simplifiés
Lorsque vous effectuez un débogage avec la sortie console, vous perdez toutes vos données dès que vous fermez votre terminal. Il n'est pas possible de rechercher ce qui s'est passé il y a une heure, et si votre script plante pendant la nuit, il n'y a aucune trace de ce qui s'est passé. Il est également difficile de partager les résultats de votre débogage avec vos collègues lorsque vous avez besoin d'aide.
La journalisation des fichiers résout ce problème en enregistrant tout de manière permanente.
La journalisation traditionnelle nécessite l'écriture de code de configuration pour configurer les gestionnaires de fichiers. Vous devez spécifier les chemins d'accès aux fichiers, créer des répertoires et gérer les autorisations. Avec Loguru, l'ajout de la journalisation des fichiers se fait littéralement en une seule ligne :
from loguru import logger
# Add file logging alongside console output
logger.add("app.log")
logger.info("This appears in both console and file")
logger.error("So does this error message")
À présent, tout est enregistré dans app.log
tout en restant visible dans votre terminal.
Cependant, les fichiers journaux deviennent volumineux au fil du temps. Une application Web fonctionnant pendant plusieurs jours peut générer des gigaoctets de journaux qui finiront par remplir votre disque. La rotation des fichiers résout ce problème en créant automatiquement de nouveaux fichiers journaux lorsque certaines conditions sont remplies. L'ancien fichier est renommé avec un horodatage, et un nouveau fichier est créé :
# When app.log reaches 10 MB, it becomes app_2024-07-15_14-30-25.log
# and a new empty app.log starts
logger.add("app.log", rotation="10 MB")
# Or start a new file every day at midnight
logger.add("app.log", rotation="00:00")
Les horodatages par défaut fonctionnent, mais ils sont souvent en UTC ou difficiles à lire. Loguru vous permet de personnaliser les formats de date et d'heure en fonction de vos besoins :
# Custom timestamp format that's easier to read
logger.add("app.log",
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
rotation="1 day")
Pour les systèmes de production, il est nécessaire d'exercer un contrôle accru sur les fichiers anciens. La journalisation de la production nécessite de suivre les meilleures pratiques Python afin de garantir la maintenabilité et la sécurité de vos journaux. Sans gestion, les fichiers journaux s'accumulent et occupent de l'espace de stockage :
# Keep only the last 10 rotated files, compress the rest
logger.add("production.log",
rotation="50 MB", # New file every 50MB
retention=10, # Keep only 10 old files
compression="zip") # Compress rotated files
Examinons cela dans un scénario réaliste. Vous construisez un pipeline de données qui traite chaque nuit plusieurs fichiers CSV, nettoie et valide les données clients avant de les charger dans votre base de données. Vous devez suivre les fichiers traités avec succès et détecter tout problème de qualité des données :
import pandas as pd
from loguru import logger
# Production-ready file logging setup
logger.add("data_processing_{time:YYYY-MM-DD}.log",
rotation="00:00", # New file daily
retention="1 week", # Keep 1 week of logs
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}")
def process_csv_files(file_list):
logger.info("Starting batch processing of {} files", len(file_list))
for filename in file_list:
try:
df = pd.read_csv(filename)
logger.info("Loaded {} with {} rows", filename, len(df))
# Your processing logic here
processed_df = df.dropna()
logger.success("Processed {} - kept {} rows", filename, len(processed_df))
except Exception as e:
logger.error("Failed to process {}: {}", filename, str(e))
logger.info("Batch processing complete")
Vos journaux sont enregistrés avec des horodatages lisibles, les fichiers sont automatiquement remplacés et les anciens journaux sont supprimés automatiquement. Vous pouvez consulter ce qui s'est passé quelques jours plus tard ou envoyer des fichiers journaux à vos collègues lors du dépannage.
Journalisation structurée pour les applications modernes
Lorsque vous exécutez une application Web, vos journaux deviennent rapidement un enchevêtrement d'informations disparates. Les actions des utilisateurs, les requêtes de base de données, les appels API et les erreurs s'affichent tous ensemble dans un mur de texte. Il n'est pas facile de filtrer des utilisateurs spécifiques, de suivre des demandes individuelles ou d'analyser automatiquement les journaux pour les systèmes de surveillance.
Les applications basées sur les données bénéficient particulièrement de la journalisation structurée. Si vous travaillez avec des pipelines de données ou des analyses, développer des compétences en analyse de données vous aidera à comprendre quelles informations capturer dans vos journaux.
La journalisation traditionnelle basée sur des chaînes aggrave ce problème. Chaque message de journal est simplement du texte. L'extraction de données significatives nécessite donc des modèles d'expressions régulières complexes ou une recherche manuelle.
La journalisation structurée modifie cela en traitant les entrées de journal comme des objets de données plutôt que comme du simple texte. Chaque entrée du journal devient un enregistrement structuré avec des champs consultables, ce qui facilite les requêtes et l'analyse par programmation.
Enregistrement structuré JSON avec serialize=True
Loguru simplifie la journalisation structurée grâce à l'option d' serialize=True
:
from loguru import logger
# Enable JSON structured logging
logger.add("api.log", serialize=True)
logger.info("User login", user_id=123, ip_address="192.168.1.1")
logger.error("Payment failed", user_id=123, amount=99.99, error_code="INSUFFICIENT_FUNDS")
Le paramètre « serialize=True
» indique à Loguru d'afficher le résultat au format JSON plutôt qu'en texte brut. Au lieu de phrases lisibles, votre fichier journal contient désormais des données structurées :
{"text": "User login", "record": {"time": "2024-07-15T14:30:25", "level": {"name": "INFO"}, "extra": {"user_id": 123, "ip_address": "192.168.1.1"}}}
Ce format est parfaitement adapté aux outils d'analyse de journaux capables de rechercher et de filtrer automatiquement les données JSON.
Liaison contextuelle
Cependant, les applications Web nécessitent davantage que de simples données structurées. Vous avez besoin d'un contexte qui relie les entrées de journal associées. Lors du traitement d'une demande utilisateur, il est souhaitable que tous les journaux associés partagent des informations communes telles que l'ID utilisateur ou l'ID de session.
La liaison de contexte résout ce problème en associant des informations persistantes à votre enregistreur à l'aide de l' logger.bind()
:
from loguru import logger
def process_user_order(user_id, order_data):
# Create a logger with attached context
order_logger = logger.bind(user_id=user_id, order_id=order_data['id'])
order_logger.info("Starting order processing")
order_logger.debug("Validating payment method", method=order_data['payment'])
order_logger.info("Order processing complete", total=order_data['total'])
Désormais, chaque journal provenant de order_logger
inclut automatiquement user_id
et order_id
, ce qui facilite le suivi de tous les journaux liés à une commande spécifique.
Plusieurs éviers pour différentes sorties
Les applications modernes nécessitent également différentes sorties de journaux à des fins diverses. Vous pourriez souhaiter disposer de journaux de console lisibles pendant le développement, mais de journaux JSON pour la surveillance en production. Dans Loguru, chaque destination de sortie est appelée un « sink » (évier) — considérez-le comme un endroit où les messages du journal sont acheminés.
Loguru vous permet d'ajouter plusieurs récepteurs avec différents formats et règles :
from loguru import logger
import sys
# Remove the default console output
logger.remove()
# Sink 1: Human-readable console for development
logger.add(sys.stdout,
level="DEBUG",
format="<green>{time:HH:mm:ss}</green> | {level} | {message}")
# Sink 2: JSON file for production monitoring
logger.add("app.log",
serialize=True,
level="INFO")
# Sink 3: Error-only file for alerts
logger.add("errors.log",
level="ERROR")
L'appel logger.remove()
supprime la sortie par défaut de la console de Loguru afin que vous puissiez configurer la vôtre. Chaque filtre ( logger.add()
) crée un nouveau collecteur avec ses propres règles concernant les éléments à enregistrer et leur format.
À présent, les mêmes instructions de journalisation produisent des résultats différents :
logger.debug("Processing started") # Only appears in console
logger.info("User data loaded") # Appears in console and app.log
logger.error("Database connection failed") # Appears in all three places
Exemple complet de Loguru : Système d'enregistrement des utilisateurs
Examinons cela à l'aide d'un exemple plus simple et plus réaliste d'utilisation de Loguru : un système d'enregistrement utilisateur de base.
from loguru import logger
import sys
# Set up multiple outputs
logger.remove()
logger.add(sys.stdout, level="INFO", format="{time:HH:mm:ss} | {message}")
logger.add("user_registration.log", serialize=True, level="INFO")
logger.add("errors.log", level="ERROR")
def register_user(email, password):
# Create logger with user context
user_logger = logger.bind(email=email)
user_logger.info("Starting user registration")
# Validate email
if "@" not in email:
user_logger.error("Invalid email format")
return False
# Check if user exists
user_logger.debug("Checking if user already exists")
# Simulate password hashing
user_logger.debug("Hashing password")
# Save to database
user_logger.info("Saving user to database")
user_logger.success("User registration completed")
return True
# Usage
register_user("john@example.com", "secure123")
Cette configuration vous offre une sortie console lisible pendant le développement, des journaux JSON structurés pour la surveillance automatisée et des journaux d'erreurs distincts pour les alertes. La méthode d' bind()
garantit que tous les journaux pour chaque inscription d'utilisateur incluent l'adresse e-mail, ce qui facilite considérablement le débogage.
Gestion des exceptions Loguru
Lorsque votre code plante, vous obtenez généralement une trace de pile basique qui vous indique où l'erreur s'est produite, mais qui ne vous fournit pas beaucoup d'informations sur la cause du problème. Vous perdez les valeurs des variables au moment du plantage, ce qui rend difficile la compréhension de ce qui s'est passé. La gestion traditionnelle des exceptions nécessite également d'encapsuler tout le code dans des blocs try-catch et d'enregistrer manuellement chaque exception.
Cela devient particulièrement pénible lors du débogage de problèmes en production. Les utilisateurs signalent des erreurs, mais vous ne pouvez pas les reproduire car vous ne disposez pas du contexte qui existait au moment où l'erreur s'est produite.
Loguru résout ce problème grâce à la capture automatique des exceptions et à des traces améliorées qui vous indiquent exactement ce qui s'est passé dans votre code lorsque des erreurs se sont produites.
Capture automatique des exceptions avec @logger.catch
Le décorateur d'@logger.catch
s capture automatiquement toute exception qui se produit dans une fonction et l'enregistre avec son contexte complet. Les décorateurs tels que @logger.catch
constituent un concept Python intermédiaire. concept Python intermédiaire qui peuvent transformer la manière dont vous gérez les erreurs dans votre base de code :
from loguru import logger
@logger.catch
def divide_numbers(a, b):
result = a / b
return result
# This automatically logs the exception with full traceback
result = divide_numbers(10, 0)
Au lieu que votre programme plante avec un message d'erreur basique, Loguru capture l'exception et l'enregistre avec des informations détaillées, tandis que votre programme continue de fonctionner. Le décorateur fonctionne sur n'importe quelle fonction : méthodes de classe, fonctions asynchrones ou fonctions classiques.
Traces améliorées avec inspection des variables
Cependant, Loguru va plus loin avec des traces améliorées qui affichent les valeurs des variables à chaque niveau de la pile d'appels. Cette fonctionnalité est appelée « diagnostic » et s'apparente à un débogueur intégré à vos journaux :
from loguru import logger
# Enable enhanced tracebacks
logger.add("debug.log", diagnose=True)
@logger.catch
def process_user_data(users):
for user in users:
age = user['age']
if age > 0:
years_to_retirement = 65 - age
print(f"User {user['name']} has {years_to_retirement} years to retirement")
# When this crashes, you'll see the exact values of 'users', 'user', and 'age'
users_data = [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": "invalid"}, # This will cause an error
]
process_user_data(users_data)
Avec l' diagnose=True
, lorsque la fonction plante en essayant de soustraire une chaîne de caractères d'un nombre, Loguru vous montre exactement ce que contenait chaque variable :
TypeError: unsupported operand type(s) for -: 'int' and 'str'
Variables values:
users = [{"name": "Alice", "age": 30}, {"name": "Bob", "age": "invalid"}]
user = {"name": "Bob", "age": "invalid"}
age = "invalid"
Ce niveau de détail accélère considérablement le débogage, car vous pouvez voir exactement quelles données ont causé le problème.
Gestion des exceptions respectueuse de l'environnement
Cependant, les traces améliorées peuvent exposer des informations sensibles telles que des mots de passe ou des clés API dans les journaux de production. Loguru vous permet de contrôler ce comportement pour différents environnements :
from loguru import logger
import os
# Development: Full diagnostic information
if os.getenv("ENVIRONMENT") == "development":
logger.add("app.log", diagnose=True, level="DEBUG")
else:
# Production: Basic logging without variable inspection
logger.add("app.log", diagnose=False, level="INFO")
@logger.catch
def authenticate_user(username, password, api_key):
# In development, you'll see all variable values if this crashes
# In production, sensitive data stays hidden
if not username or not password:
raise ValueError("Missing credentials")
Évaluation paresseuse pour améliorer les performances
Une autre fonctionnalité importante est l'évaluation différée, qui améliore les performances lors de la journalisation d'opérations coûteuses. Il arrive parfois que vous souhaitiez enregistrer des informations complexes, mais uniquement si une erreur se produit réellement :
from loguru import logger
@logger.catch
def process_large_dataset(data):
try:
# Some complex processing that might fail
result = complex_calculation(data)
return result
except Exception as e:
# This expensive operation only runs if there's an error
logger.error("Processing failed with data: {data}",
data=lambda: expensive_data_summary(data))
raise
def expensive_data_summary(data):
# This function takes time to run, summarizing huge datasets
return {"row_count": len(data), "columns": list(data.keys()), "memory_usage": data.memory_usage()}
La syntaxe d'lambda:
crée une fonction qui n'est appelée que lorsque Loguru écrit réellement le message de journal. Si aucune erreur ne se produit, l' expensive_data_summary()
ne s'exécute jamais, ce qui permet de gagner du temps de traitement.
Différentes stratégies pour différents types d'erreurs
Vous pouvez également utiliser différentes stratégies de gestion des exceptions pour différents types d'erreurs :
from loguru import logger
# Configure multiple outputs for different error severities
logger.add("warnings.log", level="WARNING", filter=lambda record: record["level"].name == "WARNING")
logger.add("critical_errors.log", level="ERROR")
@logger.catch(level="ERROR")
def critical_database_operation(query):
# Database errors get logged as ERROR level
execute_database_query(query)
@logger.catch(level="WARNING", reraise=False)
def optional_feature(user_id):
# Non-critical features log as WARNING and continue execution
send_optional_notification(user_id)
def process_user_request(user_id, query):
# Critical operation - if this fails, the whole request fails
critical_database_operation(query)
# Optional operation - if this fails, request continues
optional_feature(user_id)
Le paramètre « reraise=False
» indique à Loguru d'enregistrer l'exception sans la renvoyer, ce qui permet à votre programme de continuer. Ceci est utile pour les fonctionnalités optionnelles qui ne doivent pas perturber votre flux de travail principal.
Exemple complet : traitement de fichiers avec gestion des erreurs
Examinons un exemple complet avec un système de traitement de fichiers qui gère différents types d'erreurs de manière élégante :
from loguru import logger
import os
# Set up environment-aware logging
if os.getenv("DEBUG"):
logger.add("file_processor.log", diagnose=True, level="DEBUG")
else:
logger.add("file_processor.log", diagnose=False, level="INFO")
@logger.catch(reraise=False)
def validate_file_format(filename):
if not filename.endswith(('.csv', '.json', '.xml')):
raise ValueError(f"Unsupported file format: {filename}")
@logger.catch
def load_file_data(filename):
logger.info("Loading file: {}", filename)
# Expensive operation only logged on errors
logger.debug("File stats: {stats}",
stats=lambda: {"size": os.path.getsize(filename),
"modified": os.path.getmtime(filename)})
with open(filename, 'r') as f:
return f.read()
def process_files(file_list):
results = []
for filename in file_list:
# Validation errors are logged but don't stop processing
validate_file_format(filename)
try:
# Loading errors are logged and do stop processing this file
data = load_file_data(filename)
results.append(data)
logger.success("Successfully processed {}", filename)
except Exception:
logger.error("Skipping file {} due to loading error", filename)
continue
return results
Cette configuration vous permet de bénéficier de la capture automatique des exceptions, d'un contexte d'erreur détaillé lorsque nécessaire et de différentes stratégies de gestion pour différents types d'erreurs. Vos journaux deviennent beaucoup plus utiles pour le débogage, tandis que votre code reste propre et lisible.
Configuration avancée et personnalisation de Loguru
À mesure que vos applications se développent, vous rencontrerez des scénarios dans lesquels les paramètres par défaut de Loguru ne sont pas tout à fait adaptés. Vous avez peut-être besoin d'un niveau de journalisation particulier pour les indicateurs commerciaux, souhaitez filtrer les données sensibles des journaux ou envoyer des alertes à Slack en cas d'erreur.
La bonne nouvelle, c'est que Loguru est conçu pour être personnalisé sans perdre sa simplicité. Vous pouvez l'étendre de manière à nécessiter une configuration complexe dans les systèmes de journalisation traditionnels, tout en conservant un code clair et lisible.
Examinons les personnalisations les plus utiles qui résolvent les problèmes réels auxquels vous serez confronté dans les applications de production.
Niveaux et couleurs personnalisés pour les journaux
Loguru est fourni avec des niveaux standard tels que INFO, DEBUG et ERROR. Cependant, il arrive parfois que vous ayez besoin d'une solution spécifique à votre application. Vous souhaitez peut-être un niveau spécial pour les indicateurs de performance ou les événements commerciaux.
La création de niveaux de journalisation personnalisés est simple :
from loguru import logger
# Add a custom level for business metrics
logger.level("METRIC", no=38, color="<yellow>", icon="📊")
# Add a custom level for security events
logger.level("SECURITY", no=45, color="<red><bold>", icon="🔒")
# Now you can use these levels
logger.log("METRIC", "Order completed in {} seconds", 2.5)
logger.log("SECURITY", "Failed login attempt from IP: {}", "192.168.1.100")
Le paramètre « no
» définit le niveau de priorité (plus le nombre est élevé, plus la priorité est élevée). Niveaux standard d'utilisation : DEBUG=10, INFO=20, WARNING=30, ERROR=40, CRITICAL=50.
Examinons cela dans le cadre d'un scénario de formation au machine learning :
from loguru import logger
# Set up custom levels for ML tracking
logger.level("EPOCH", no=35, color="<cyan><bold>")
logger.level("CHECKPOINT", no=38, color="<green><bold>")
# Configure output
logger.remove()
logger.add("training_{time:YYYY-MM-DD}.log", level="INFO")
def train_model(model, data_loader, epochs=10):
logger.info("Starting training with {} epochs", epochs)
for epoch in range(epochs):
# Log epoch progress with custom level
logger.log("EPOCH", "Epoch {}/{} started", epoch + 1, epochs)
# Training logic here
loss = 0.523 - (epoch * 0.05) # Simulated improving loss
accuracy = 0.72 + (epoch * 0.03) # Simulated improving accuracy
logger.info("Loss: {:.4f}, Accuracy: {:.2%}", loss, accuracy)
# Save checkpoint every 5 epochs
if (epoch + 1) % 5 == 0:
logger.log("CHECKPOINT", "Model saved at epoch {}", epoch + 1)
logger.success("Training completed!")
Interception et modification des messages de journalisation
Il est parfois nécessaire de modifier les messages de journal avant qu'ils ne soient enregistrés. Les cas d'utilisation courants incluent la suppression de données sensibles, l'ajout d'identifiants de requête ou le reformatage de messages pour des outils spécifiques.
Loguru vous permet d'intercepter des messages à l'aide du paramètre filter
:
from loguru import logger
import re
def hide_sensitive_data(record):
# Hide credit card numbers
record["message"] = re.sub(r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b',
'XXXX-XXXX-XXXX-XXXX',
record["message"])
# Hide email addresses
record["message"] = re.sub(r'\b[\w.-]+@[\w.-]+\.\w+\b',
'***@***.***',
record["message"])
# Continue processing the log
return True
# Add the filter to your logger
logger.add("secure.log", filter=hide_sensitive_data)
# Test it
logger.info("User paid with card 4532-1234-5678-9012")
logger.info("Contact email: john.doe@example.com")
Vous pouvez également utiliser des filtres pour ajouter des informations contextuelles :
from loguru import logger
import threading
def add_thread_info(record):
# Add thread name to every log message
record["extra"]["thread_name"] = threading.current_thread().name
return True
def add_environment_info(record):
# Add environment to production logs
record["extra"]["env"] = "production"
record["extra"]["region"] = "us-west-2"
return True
# Apply multiple filters
logger.add(
"app.log",
filter=lambda record: add_thread_info(record) and add_environment_info(record),
format="{time} | {extra[env]} | {extra[thread_name]} | {message}"
)
Éviers sur mesure pour services extérieurs
Un évier est l'endroit où vos journaux sont transférés. Bien que les fichiers et la console soient courants, il est souvent nécessaire d'envoyer des journaux à des services externes tels que Slack, par e-mail ou à des systèmes de surveillance.
Voici comment créer un sink personnalisé qui envoie les erreurs à Slack :
from loguru import logger
import requests
def send_to_slack(message):
"""Custom sink that sends messages to Slack"""
# Parse the log record
record = message.record
# Only send errors and above
if record["level"].no < 40: # ERROR level is 40
return
# Format message for Slack
slack_message = {
"text": f"🚨 {record['level'].name}: {record['message']}",
"attachments": [{
"color": "danger",
"fields": [
{"title": "Time", "value": str(record["time"]), "short": True},
{"title": "Function", "value": record["function"], "short": True},
{"title": "File", "value": f"{record['file'].name}:{record['line']}", "short": False}
]
}]
}
# Send to Slack webhook
webhook_url = "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
requests.post(webhook_url, json=slack_message)
# Add the custom sink
logger.add(send_to_slack, level="ERROR")
# Test it
logger.error("Database connection lost!")
Voici un autre exemple pratique : un collecteur personnalisé qui recueille des mesures de performances tout au long de l'exécution de votre application et les enregistre à des fins d'analyse.
from loguru import logger
from collections import defaultdict
import json
class MetricsCollector:
def __init__(self):
self.metrics = defaultdict(list)
def __call__(self, message):
"""This method is called for every log message"""
record = message.record
# Only process METRIC level logs
if record["level"].name != "METRIC":
return
# Extract metric data from the 'extra' fields
extra = record["extra"]
if "metric_name" in extra and "value" in extra:
self.metrics[extra["metric_name"]].append({
"value": extra["value"],
"timestamp": record["time"].timestamp()
})
def save_metrics(self):
"""Save all collected metrics to a JSON file"""
with open("metrics.json", "w") as f:
json.dump(dict(self.metrics), f, indent=2)
# Create the collector and add it as a sink
collector = MetricsCollector()
logger.add(collector)
# Create the METRIC level
logger.level("METRIC", no=38)
# Now when you log metrics, they're automatically collected
# The bind() method attaches extra data to the log entry
logger.bind(metric_name="response_time", value=0.234).log("METRIC", "API response")
logger.bind(metric_name="response_time", value=0.189).log("METRIC", "API response")
logger.bind(metric_name="active_users", value=1523).log("METRIC", "User count")
# Later, save all metrics to file
collector.save_metrics()
# The metrics.json file will contain:
# {
# "response_time": [
# {"value": 0.234, "timestamp": 1627...},
# {"value": 0.189, "timestamp": 1627...}
# ],
# "active_users": [
# {"value": 1523, "timestamp": 1627...}
# ]
# }
L'avantage de cette approche réside dans le fait que le code de votre application reste propre : vous enregistrez simplement les métriques comme d'habitude, et le collecteur se charge automatiquement du stockage. Vous pouvez facilement remplacer cet élément par un évier qui envoie des métriques à Prometheus, DataDog ou tout autre service de surveillance.
Ces personnalisations vous offrent la flexibilité nécessaire pour adapter Loguru à vos besoins spécifiques tout en conservant la simplicité qui fait son succès. Que vous développiez un petit script ou une application volumineuse, vous pouvez étendre Loguru pour répondre à vos besoins spécifiques en matière de journalisation sans avoir recours à des fichiers de configuration complexes ou à du code standard.
Conclusion
Loguru simplifie considérablement la journalisation en Python. Plus besoin de fichiers de configuration, plus besoin de configurer les gestionnaires, plus besoin de code standard. Il suffit d'importer et de commencer à enregistrer avec des couleurs, des horodatages et une rotation automatique des fichiers.
Vous avez constaté comment il gère les problèmes courants : enregistrement des journaux dans des fichiers, rotation automatique, capture des exceptions avec leur contexte complet et envoi des journaux à des services externes. Les fonctionnalités de journalisation structurée le rendent prêt pour la production, tandis que les niveaux et les récepteurs personnalisés vous permettent de l'adapter à tous les cas d'utilisation.
Utilisez Loguru lorsque :
- Vous en avez assez du débogage d'impression ?
- Vous avez besoin de scripts ou de carnets de notes pour vous connecter rapidement.
- Vous développez des applications web qui nécessitent des journaux structurés.
- Vous souhaitez bénéficier d'un meilleur suivi des exceptions sans configuration complexe.
Pour approfondir vos connaissances, veuillez consulter la documentation officielle ainsi que ce tutoriel sur la journalisation afin d'obtenir une présentation complète des stratégies de journalisation Python.
Commencez modestement. Remplacez une instruction d'impression par l'instruction suivante : logger.info()
. Vous ne pourrez plus jamais vous en passer.
FAQ Loguru
Comment Loguru se compare-t-il aux autres bibliothèques de journalisation Python ?
Loguru se distingue par son absence totale de configuration : vous pouvez commencer à enregistrer immédiatement avec « from loguru import logger ». Contrairement au module de journalisation intégré à Python, qui nécessite des gestionnaires, des formateurs et une configuration complexe, Loguru fournit des couleurs, des horodatages et une rotation des fichiers prêts à l'emploi. Il offre également des traces améliorées avec inspection variable que d'autres bibliothèques ne fournissent pas.
Quels sont les principaux avantages de Loguru par rapport au module de journalisation intégré à Python ?
Loguru élimine la complexité de la configuration, assure la rotation et la conservation automatiques des fichiers, offre une journalisation JSON structurée avec serialize=True, inclut des traces d'exception améliorées avec des valeurs variables et prend en charge des récepteurs personnalisés pour les services externes. Vous bénéficiez de fonctionnalités de journalisation prêtes à l'emploi sans avoir à écrire de code de configuration.
Loguru est-il capable de gérer efficacement les applications multithread ?
Oui, Loguru est thread-safe par défaut et gère correctement les applications multithread. Vous pouvez ajouter des informations sur les threads aux journaux à l'aide de filtres, et la méthode logger.bind() fonctionne sur tous les threads afin de conserver le contexte. Les performances de Loguru sont optimisées pour la journalisation simultanée sans bloquer les threads.
Comment fonctionne la rotation et la conservation automatiques des journaux de Loguru ?
Loguru offre une rotation flexible en fonction de la taille des fichiers (rotation = « 10 Mo »), d'intervalles de temps (rotation = « 00:00 » pour une rotation quotidienne) ou de conditions personnalisées. La conservation supprime automatiquement les anciens fichiers (conservation=10 conserve 10 fichiers) et la compression permet de gagner de l'espace (compression="zip"). Tout se déroule automatiquement, sans gestion manuelle des fichiers.
Quels sont les exemples pratiques d'utilisation des fonctionnalités personnalisées de Loguru ?
Les sinks personnalisés vous permettent d'envoyer des logs à des services externes tels que Slack pour les alertes d'erreur, de collecter des métriques pour les systèmes de surveillance ou de formater les logs pour des outils spécifiques. Vous pouvez créer des collecteurs qui filtrent par niveau de journalisation, ajoutent des informations contextuelles ou s'intègrent à des services tels que DataDog, Prometheus ou des notifications par e-mail pour les erreurs critiques.

Je suis un créateur de contenu en science des données avec plus de 2 ans d'expérience et l'un des plus grands followings sur Medium. J'aime écrire des articles détaillés sur l'IA et la ML dans un style un peu sarcastıc, car il faut bien faire quelque chose pour les rendre un peu moins ennuyeux. J'ai produit plus de 130 articles et un cours DataCamp, et un autre est en cours d'élaboration. Mon contenu a été vu par plus de 5 millions de personnes, dont 20 000 sont devenues des adeptes sur Medium et LinkedIn.