Lernpfad
Du hast dein ganzes Programmierleben lang mit „ print()
“-Anweisungen debuggt. Vielleicht hast du schon mal das Logging-Modul von Python ausprobiert, bist aber wieder zu Prints zurückgekehrt, weil die einfacher sind.
Es gibt sogar was Besseres, das genauso einfach zu benutzen ist.
Druckaufträge können nicht in Dateien gespeichert oder einfach so ein- und ausgeschaltet werden. Die integrierte Protokollierung von Python kann das, aber dafür musst du Setup-Code schreiben, der länger ist als dein eigentliches Programm.
Loguru macht es anders: Logging sollte so einfach sein wie Drucken, aber viel nützlicher. Du bekommst Farben in deinem Terminal, automatische Zeitstempel und kannst alles in Dateien speichern, ohne auch nur eine einzige Konfigurationszeile schreiben zu müssen.
In diesem Tutorial zeige ich dir praktische Beispiele, mit denen sich das Logging ganz natürlich anfühlt und nicht wie ne lästige Pflicht. Du wirst Funktionen entdecken, von denen du wahrscheinlich noch nichts wusstest, und Code-Muster kennenlernen, die das Debuggen echt einfacher machen.
Wenn du noch keine Erfahrung mit dem Debuggen in Python hast oder deine Grundkenntnisse vertiefen möchtest, sollten Sie sich solide Python-Grundkenntnisse aneignen hilft dir zu verstehen, wann und warum Logging notwendig ist.
Erste Schritte mit Loguru: Magie ohne Konfiguration
Loguru lässt sich mit einem einzigen Befehl installieren:
pip install loguru
Mit dem normalen Modul „ logging
“ musst du Handler und Formatierer einrichten und alles konfigurieren, bevor du auch nur eine einzige Protokollmeldung siehst.
Für einen tiefergehenden Vergleich der integrierten Protokollierungsansätze von Python schau dir dieses umfassende Logging-Tutorial , das die traditionellen Methoden abdeckt.
Mit Loguru musst du nur importieren und kannst gleich loslegen:
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)
Die Ausgabe wird automatisch mit Farben, Zeitstempeln und Protokollstufen in deinem Terminal angezeigt. Keine Einrichtung nötig.
Nehmen wir mal an, du baust einen einfachen Web-Scraper. So ändert sich das Debugging:
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
Achte auf die verschiedenen Protokollebenen (info
, debug
, success
, error
) und die Formatierung mit geschweiften Klammern. Alles funktioniert sofort, ohne dass du irgendwelche Konfigurationsdateien oder Setup-Code brauchst.
Dateiprotokollierung und -rotation leicht gemacht
Wenn du mit der Konsolenausgabe debuggt, geht alles verloren, sobald du dein Terminal schließt. Du kannst nicht nach Dingen suchen, die vor einer Stunde passiert sind, und wenn dein Skript über Nacht abstürzt, gibt's keine Ahnung, was schiefgelaufen ist. Außerdem kannst du deine Debugging-Ergebnisse nicht einfach mit deinen Teamkollegen teilen, wenn du um Hilfe bittest.
Die Dateiprotokollierung löst das, indem sie alles dauerhaft speichert.
Beim normalen Logging musst du Konfigurationscode schreiben, um Datei-Handler einzurichten. Du musst Dateipfade angeben, Verzeichnisse erstellen und Berechtigungen verwalten. Mit Loguru ist das Hinzufügen der Dateiprotokollierung buchstäblich eine Zeile:
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")
Jetzt wird alles unter „ app.log
“ gespeichert und trotzdem noch in deinem Terminal angezeigt.
Aber Log-Dateien werden mit der Zeit echt riesig. Eine Web-App, die tagelang läuft, kann Gigabytes an Logs produzieren, die irgendwann deine Festplatte vollmachen. Die Dateirotation löst das, indem automatisch neue Logdateien erstellt werden, wenn bestimmte Bedingungen erfüllt sind. Die alte Datei wird mit einem Zeitstempel umbenannt und eine neue Datei wird erstellt:
# 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")
Die Standard-Zeitstempel funktionieren, sind aber oft in UTC oder schwer zu lesen. Mit Loguru kannst du Datums- und Zeitformate nach deinen Bedürfnissen anpassen:
# 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")
Für Produktionssysteme brauchst du mehr Kontrolle über alte Dateien. Für die Produktionsprotokollierung musst du die Python-Best Practices befolgen, damit deine Protokolle pflegbar und sicher sind. Ohne Verwaltung stapeln sich Log-Dateien und belegen Speicherplatz:
# 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
Schauen wir uns das mal in einem echten Szenario an. Du baust eine Datenpipeline auf, die jede Nacht mehrere CSV-Dateien verarbeitet, Kundendaten bereinigt und validiert, bevor sie in deine Datenbank geladen werden. Du musst einen Lernpfad erstellen, um zu verfolgen, welche Dateien erfolgreich verarbeitet wurden, und etwaige Probleme mit der Datenqualität zu erkennen:
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")
Deine Logs werden mit lesbaren Zeitstempeln gespeichert, Dateien werden automatisch rotiert und alte Logs werden automatisch gelöscht. Du kannst später checken, was passiert ist, oder Log-Dateien an Kollegen schicken, wenn du Probleme beheben musst.
Strukturierte Protokollierung für moderne Apps
Wenn du eine Web-App betreibst, werden deine Logs schnell zu einem Durcheinander aus verschiedenen Infos. Benutzeraktionen, Datenbankabfragen, API-Aufrufe und Fehler werden alle in einer Textwand zusammengefasst. Du kannst nicht einfach nach bestimmten Benutzern filtern, einzelne Anfragen verfolgen oder Protokolle automatisch für Überwachungssysteme analysieren.
Datenbasierte Anwendungen profitieren besonders von strukturierter Protokollierung. Wenn du mit Datenpipelines oder Analysen arbeitest, helfen dir Datenanalyse-Kenntnisse dabei, zu verstehen, welche Infos du in deinen Protokollen erfassen solltest.
Die klassische Protokollierung mit Strings macht das Ganze noch schlimmer. Jede Protokollmeldung ist nur Text, sodass du für die Extraktion aussagekräftiger Daten komplexe reguläre Ausdrücke oder manuelle Suchvorgänge brauchst.
Strukturierte Protokollierung ändert das, indem sie Protokolleinträge als Datenobjekte und nicht nur als Text behandelt. Jeder Protokolleintrag wird zu einem strukturierten Datensatz mit durchsuchbaren Feldern, sodass er einfach programmgesteuert abgefragt und analysiert werden kann.
JSON-strukturierte Protokollierung mit serialize=True
Loguru macht strukturiertes Logging mit der Option „ serialize=True
“ ganz einfach:
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")
Der Parameter „ serialize=True
“ sagt Loguru, dass es JSON statt reinem Text ausgeben soll. Statt lesbaren Sätzen hat deine Logdatei jetzt strukturierte Daten:
{"text": "User login", "record": {"time": "2024-07-15T14:30:25", "level": {"name": "INFO"}, "extra": {"user_id": 123, "ip_address": "192.168.1.1"}}}
Dieses Format passt super zu Tools für die Log-Analyse, die JSON-Daten automatisch durchsuchen und filtern können.
Kontextbindung
Aber Web-Apps brauchen mehr als nur strukturierte Daten. Du brauchst einen Zusammenhang, der ähnliche Log-Einträge verbindet. Wenn du eine Benutzeranfrage bearbeitest, solltest du sicherstellen, dass alle zugehörigen Protokolle gemeinsame Infos wie die Benutzer-ID oder die Sitzungs-ID haben.
Kontextbindung löst das, indem sie mit „ logger.bind()
“ dauerhafte Infos an deinen Logger hängt:
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'])
Jetzt enthält jeder Log von order_logger
automatisch user_id
und order_id
, sodass alle Logs zu einer bestimmten Bestellung ganz einfach nachverfolgt werden können.
Mehrere Senken für verschiedene Ausgänge
Moderne Anwendungen brauchen auch unterschiedliche Protokollausgaben für verschiedene Zwecke. Während der Entwicklung möchtest du vielleicht lesbare Konsolenprotokolle, für die Produktionsüberwachung aber JSON-Protokolle. In Loguru wird jedes Ausgabeziel als „Sink“ bezeichnet – stell dir das als einen Ort vor, an den Log-Meldungen fließen.
Mit Loguru kannst du mehrere Sinks mit unterschiedlichen Formaten und Regeln hinzufügen:
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")
Der Aufruf „ logger.remove()
“ löscht die Standard-Konsolenausgabe von Loguru, damit du deine eigene einrichten kannst. Jeder „ logger.add()
” macht eine neue „Sink” mit eigenen Regeln, was protokolliert wird und wie das aussieht.
Jetzt liefern dieselben Protokollanweisungen unterschiedliche Ausgaben:
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
Komplettes Loguru-Beispiel: Benutzerregistrierung
Schauen wir uns das mal an einem einfacheren, realistischeren Beispiel für die Verwendung von Loguru an – einem einfachen Benutzerregistrierungssystem:
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")
Mit dieser Konfiguration bekommst du während der Entwicklung eine übersichtliche Konsolenausgabe, strukturierte JSON-Protokolle für die automatisierte Überwachung und separate Fehlerprotokolle für Warnmeldungen. Die Methode „ bind()
“ sorgt dafür, dass alle Protokolle für jede Benutzerregistrierung die E-Mail-Adresse enthalten, was die Fehlersuche echt vereinfacht.
Loguru-Ausnahmebehandlung
Wenn dein Code abstürzt, bekommst du normalerweise einen einfachen Stacktrace, der dir sagt, wo der Fehler aufgetreten ist, aber nicht viel darüber, warum. Du verlierst die Werte der Variablen zum Zeitpunkt des Absturzes, was es schwierig macht, zu verstehen, was schiefgelaufen ist. Bei der herkömmlichen Ausnahmebehandlung musst du auch alles in try-catch-Blöcke packen und jede Ausnahme manuell protokollieren.
Das ist besonders nervig, wenn man Probleme in der Produktion debuggt. Benutzer melden Fehler, aber du kannst sie nicht nachmachen, weil du nicht den Kontext kennst, in dem der Fehler aufgetreten ist.
Loguru löst das mit automatischer Ausnahmeerfassung und verbesserten Rückverfolgungen, die dir genau zeigen, was in deinem Code passiert ist, als etwas schiefgelaufen ist.
Automatisches Erfassen von Ausnahmen mit @logger.catch
Der Dekorator „ @logger.catch
” fängt automatisch alle Ausnahmen ab, die in einer Funktion auftreten, und protokolliert sie mit dem vollständigen Kontext. Dekoratoren wie „ @logger.catch
“ sind ein Zwischenkonzept in Python, das die Art und Weise, wie du Fehler in deinem Code behandelst, grundlegend verändern kann:
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)
Anstatt dass dein Programm mit einer einfachen Fehlermeldung abstürzt, fängt Loguru die Ausnahme ab und protokolliert sie mit detaillierten Infos, während dein Programm weiterläuft. Der Dekorator funktioniert bei jeder Funktion – Klassenmethoden, asynchrone Funktionen oder normale Funktionen.
Verbesserte Rückverfolgung mit Variablenprüfung
Aber Loguru geht noch weiter und zeigt mit verbesserten Tracebacks die Werte der Variablen auf jeder Ebene des Aufrufstapels an. Diese Funktion heißt „Diagnose“ und ist wie ein Debugger, der in deine Protokolle eingebaut ist:
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)
Mit „ diagnose=True
“ zeigt Loguru dir genau, was in jeder Variablen war, wenn die Funktion beim Versuch, eine Zeichenfolge von einer Zahl zu subtrahieren, abstürzt:
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"
Dank dieser Detailgenauigkeit geht das Debuggen viel schneller, weil du genau siehst, welche Daten das Problem verursacht haben.
Umgebungsbewusste Ausnahmebehandlung
Allerdings können erweiterte Tracebacks sensible Infos wie Passwörter oder API-Schlüssel in Produktionsprotokollen offenlegen. Mit Loguru kannst du dieses Verhalten für verschiedene Umgebungen steuern:
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")
Lazy Evaluation für mehr Performance
Eine weitere coole Funktion ist die verzögerte Auswertung, die die Leistung bei der Protokollierung von aufwendigen Vorgängen verbessert. Manchmal willst du komplexe Infos protokollieren, aber nur, wenn tatsächlich ein Fehler auftritt:
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()}
Die Syntax „ lambda:
“ macht eine Funktion, die nur dann aufgerufen wird, wenn Loguru die Log-Nachricht tatsächlich schreibt. Wenn kein Fehler auftritt, wird „ expensive_data_summary()
“ nie ausgeführt, was Rechenzeit spart.
Unterschiedliche Strategien für verschiedene Fehlerarten
Du kannst auch verschiedene Strategien zum Umgang mit Ausnahmen für verschiedene Arten von Fehlern verwenden:
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)
Der Parameter „ reraise=False
“ sagt Loguru, dass die Ausnahme protokolliert, aber nicht erneut ausgelöst werden soll, sodass dein Programm weiterlaufen kann. Das ist praktisch für optionale Funktionen, die deinen Haupt-Workflow nicht stören sollen.
Komplettes Beispiel: Dateiverarbeitung mit Fehlerbehandlung
Schauen wir uns mal ein komplettes Beispiel mit einem Dateiverarbeitungssystem an, das verschiedene Arten von Fehlern elegant abfängt:
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
Mit dieser Konfiguration bekommst du automatisch Ausnahmen erfasst, bei Bedarf detaillierte Fehlerkontexte und verschiedene Strategien, um mit unterschiedlichen Fehlern umzugehen. Deine Protokolle werden viel nützlicher für die Fehlersuche, während dein Code übersichtlich und lesbar bleibt.
Erweiterte Loguru-Konfiguration und Anpassung
Wenn deine Anwendungen wachsen, wirst du Situationen haben, in denen die Standardeinstellungen von Loguru nicht ganz passen. Vielleicht brauchst du einen speziellen Protokollierungsgrad für Geschäftsmetriken, möchtest sensible Daten aus den Protokollen herausfiltern oder bei Fehlern Benachrichtigungen an Slack senden.
Das coole daran ist, dass Loguru so gemacht ist, dass man es anpassen kann, ohne dass es kompliziert wird. Du kannst es auf eine Art erweitern, die bei herkömmlichen Protokollierungssystemen eine komplizierte Konfiguration erfordern würde, und dabei deinen Code übersichtlich und lesbar halten.
Schauen wir uns mal die nützlichsten Anpassungen an, die echte Probleme lösen, auf die du in Produktionsanwendungen stoßen wirst.
Benutzerdefinierte Protokollstufen und Farben
Loguru kommt mit Standardstufen wie INFO, DEBUG und ERROR. Aber manchmal brauchst du etwas, das speziell auf deine Anwendung zugeschnitten ist. Vielleicht brauchst du eine spezielle Ebene für Leistungskennzahlen oder Geschäftsereignisse.
Benutzerdefinierte Protokollstufen zu erstellen ist ganz einfach:
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")
Der Parameter „ no
“ legt die Priorität der Ebene fest (höhere Zahlen = höhere Priorität). Standard-Niveaustufen: DEBUG=10, INFO=20, WARNING=30, ERROR=40, CRITICAL=50.
Schauen wir uns das mal in einem Machine-Learning-Trainingsszenario an:
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!")
Protokollmeldungen abfangen und ändern
Manchmal musst du Log-Meldungen ändern, bevor sie geschrieben werden. Häufige Anwendungsfälle sind das Löschen sensibler Daten, das Hinzufügen von Anforderungs-IDs oder das Umformatieren von Nachrichten für bestimmte Tools.
Mit Loguru kannst du Nachrichten über den Parameter „ filter
“ abfangen:
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")
Du kannst auch Filter verwenden, um Kontextinfos hinzuzufügen:
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}"
)
Maßgefertigte Waschbecken für Außenbereiche
Ein Sink ist der Ort, an den deine Protokolle fließen. Dateien und Konsolen sind zwar weit verbreitet, aber oft musst du Logs an externe Dienste wie Slack, E-Mail oder Überwachungssysteme senden.
So kannst du einen benutzerdefinierten Sink erstellen, der Fehler an Slack sendet:
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!")
Hier ist ein weiteres praktisches Beispiel: ein benutzerdefinierter Sink, der während der gesamten Ausführung Ihrer Anwendung Leistungsmetriken erfasst und zur Analyse speichert:
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...}
# ]
# }
Das coole an diesem Ansatz ist, dass dein Anwendungscode übersichtlich bleibt – du protokollierst einfach wie gewohnt die Metriken und der Collector Sink kümmert sich automatisch um die Speicherung. Du kannst das ganz einfach gegen ein Sink austauschen, das Metriken an Prometheus, DataDog oder einen anderen Überwachungsdienst sendet.
Mit diesen Anpassungen kannst du Loguru ganz einfach an deine Bedürfnisse anpassen, ohne dass es dabei seine tolle Einfachheit verliert. Egal, ob du ein kleines Skript oder eine große Anwendung entwickelst, du kannst Loguru erweitern, um deine individuellen Protokollierungsanforderungen ohne komplizierte Konfigurationsdateien oder Boilerplate-Code zu erfüllen.
Fazit
Loguru macht das Logging in Python so einfach, wie es sein sollte. Keine Konfigurationsdateien mehr, kein Handler-Setup mehr, kein Boilerplate-Code mehr. Einfach importieren und loslegen – mit Farben, Zeitstempeln und automatischer Dateirotation.
Du hast gesehen, wie es mit den üblichen Problemen klärt: Protokolle in Dateien speichern, automatisch rotieren, Ausnahmen mit vollem Kontext erfassen und Protokolle an externe Dienste senden. Die strukturierten Protokollierungsfunktionen machen es einsatzbereit, während du es mit benutzerdefinierten Ebenen und Senken an jeden Anwendungsfall anpassen kannst.
Verwende Loguru, wenn:
- Du hast keine Lust mehr auf das Debuggen von Ausdrucken
- Du brauchst schnell Skripte oder Notizbücher zum Einloggen?
- Du entwickelst Webanwendungen, die strukturierte Protokolle brauchen.
- Du willst eine bessere Ausnahmeverfolgung ohne komplizierte Einrichtung
Wenn du mehr wissen willst, schau dir neben diesem Logging-Tutorial auch die offizielle Dokumentation an, wo du alles über Python-Logging-Strategien erfährst.
Fang klein an. Ersetz eine print-Anweisung durch „ logger.info()
“. Du wirst nie wieder zurück wollen.
Loguru – Häufig gestellte Fragen
Wie schneidet Loguru im Vergleich zu anderen Python-Logging-Bibliotheken ab?
Loguru ist super, weil du nichts einrichten musst – du kannst sofort loslegen mit „from loguru import logger“. Anders als das integrierte Logging-Modul von Python, das Handler, Formatierer und eine komplexe Einrichtung braucht, bietet Loguru Farben, Zeitstempel und Dateirotation direkt aus der Box. Außerdem gibt's verbesserte Rückverfolgungen mit variabler Überprüfung, die andere Bibliotheken nicht bieten.
Was sind die Hauptvorteile von Loguru gegenüber dem integrierten Logging-Modul von Python?
Loguru macht Schluss mit komplizierten Konfigurationen, sorgt für automatische Dateirotation und -aufbewahrung, bietet strukturierte JSON-Protokollierung mit serialize=True, hat verbesserte Ausnahme-Tracebacks mit Variablenwerten und unterstützt benutzerdefinierte Sinks für externe Dienste. Du bekommst sofort einsatzbereite Logging-Funktionen, ohne irgendwelchen Setup-Code schreiben zu müssen.
Kann Loguru Anwendungen mit mehreren Threads gut verarbeiten?
Ja, Loguru ist standardmäßig threadsicher und kommt gut mit Anwendungen mit mehreren Threads klar. Du kannst Thread-Infos mit Filtern zu Logs hinzufügen, und die Methode logger.bind() funktioniert threadübergreifend, um den Kontext beizubehalten. Die Leistung von Loguru ist so optimiert, dass mehrere Protokollierungen gleichzeitig laufen können, ohne Threads zu blockieren.
Wie funktioniert die automatische Log-Rotation und -Aufbewahrung von Loguru?
Loguru bietet flexible Rotation basierend auf Dateigröße (Rotation="10 MB"), Zeitintervallen (Rotation="00:00" für täglich) oder benutzerdefinierten Bedingungen. Die Aufbewahrungsfunktion löscht automatisch alte Dateien (Aufbewahrung=10 behält 10 Dateien) und die Komprimierung spart Speicherplatz (Komprimierung="zip"). Alles läuft automatisch, ohne dass du Dateien manuell verwalten musst.
Was sind praktische Beispiele für die Verwendung der benutzerdefinierten Sink-Funktionen von Loguru?
Mit benutzerdefinierten Sinks kannst du Protokolle an externe Dienste wie Slack für Fehlermeldungen senden, Metriken für Überwachungssysteme sammeln oder Protokolle für bestimmte Tools formatieren. Du kannst Sinks erstellen, die nach Protokollstufe filtern, Kontextinfos hinzufügen oder mit Diensten wie DataDog, Prometheus oder E-Mail-Benachrichtigungen für kritische Fehler integrieren.

Ich bin ein Data Science Content Creator mit über 2 Jahren Erfahrung und einem der größten Follower auf Medium. Ich schreibe gerne ausführliche Artikel über KI und ML mit einem etwas sarkastischen Stil, denn man muss etwas tun, damit sie nicht so langweilig sind. Ich habe mehr als 130 Artikel verfasst und einen DataCamp-Kurs gemacht, ein weiterer ist in Vorbereitung. Meine Inhalte wurden von über 5 Millionen Augenpaaren gesehen, von denen 20.000 zu Followern auf Medium und LinkedIn wurden.