Lewati ke konten utama

Tutorial Logging Loguru Python: Penyiapan Tanpa Konfigurasi

Pelajari Loguru, kerangka kerja logging paling mudah di Python. Kuasai rotasi file, logging terstruktur, penanganan pengecualian, dan sink kustom tanpa konfigurasi.
· 10 mnt Baca

Jelajahi bersama AI

Sepanjang karier coding, Anda terbiasa melakukan debug dengan pernyataan print(). Mungkin Anda pernah mencoba modul logging bawaan Python sekali dua kali, tetapi kembali ke print karena lebih sederhana.

Sebenarnya ada cara yang lebih baik dan sama mudahnya digunakan.

Pernyataan print tidak dapat disimpan ke file atau diaktifkan/dinonaktifkan dengan mudah. Logging bawaan Python bisa melakukan itu, tetapi membutuhkan kode penyiapan yang lebih panjang daripada program Anda sendiri.

Loguru mengambil pendekatan berbeda: logging harus semudah printing, namun jauh lebih bermanfaat. Anda mendapatkan warna di terminal, stempel waktu otomatis, dan kemampuan menyimpan semuanya ke file tanpa menulis satu baris konfigurasi pun.

Dalam tutorial ini, saya akan menunjukkan contoh praktis yang membuat logging terasa alami alih-alih membebani. Anda akan melihat fitur-fitur yang mungkin belum Anda ketahui, menggunakan pola kode yang benar-benar mempermudah debug.

Jika Anda baru dalam debugging Python atau ingin memperkuat keterampilan dasar, membangun fundamental Python yang solid membantu Anda memahami kapan dan mengapa logging diperlukan.

Mulai Dengan Loguru: Keajaiban Tanpa Konfigurasi

Menginstal Loguru hanya butuh satu perintah:

pip install loguru

Dengan modul logging biasa, Anda harus menyiapkan handler, formatter, dan mengonfigurasi semuanya sebelum melihat satu pesan log pun. 

Untuk perbandingan lebih mendalam tentang pendekatan logging bawaan Python, lihat tutorial logging komprehensif yang membahas metode tradisional.

Dengan Loguru, Anda cukup mengimpor dan mulai melakukan logging:

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)

Output muncul di terminal Anda dengan warna, stempel waktu, dan level log secara otomatis. Tanpa perlu penyiapan.

Output konsol Loguru menampilkan pesan log berwarna dengan stempel waktu dan level log berbeda di terminal Python

Misalnya Anda membangun web scraper sederhana. Berikut perubahan cara Anda melakukan debug:

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

Perhatikan level log yang berbeda (info, debug, success, error) dan format gaya kurung kurawal. Semuanya langsung bekerja tanpa file konfigurasi atau kode penyiapan.

Logging ke File dan Rotasi yang Sederhana

Saat Anda melakukan debug dengan output konsol, semuanya hilang begitu Anda menutup terminal. Anda tidak bisa menelusuri apa yang terjadi satu jam lalu, dan jika skrip Anda crash semalaman, tidak ada jejak apa yang salah. Anda juga tidak mudah membagikan output debug kepada rekan saat meminta bantuan.

Logging ke file menyelesaikan ini dengan menyimpan semuanya secara permanen.

Logging tradisional membuat Anda menulis kode konfigurasi untuk menyiapkan file handler. Anda perlu menentukan path file, membuat direktori, dan menangani perizinan. Dengan Loguru, menambahkan logging ke file benar-benar cukup satu baris:

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")

Sekarang semuanya disimpan ke app.log sambil tetap tampil di terminal Anda.

Namun file log akan membesar seiring waktu. Aplikasi web yang berjalan berhari-hari bisa menghasilkan gigabyte log yang akhirnya memenuhi disk. Rotasi file menyelesaikan ini dengan otomatis membuat file log baru saat kondisi tertentu terpenuhi. File lama diubah namanya dengan stempel waktu, dan file baru dimulai:

# 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")

Stempel waktu bawaan berfungsi, namun sering kali dalam UTC atau sulit dibaca. Loguru memungkinkan Anda menyesuaikan format datetime sesuai kebutuhan:

# 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")

Untuk sistem produksi, Anda butuh kontrol lebih atas file lama. Logging produksi memerlukan penerapan praktik terbaik Python agar log Anda mudah dirawat dan aman. Tanpa pengelolaan, file log menumpuk dan menghabiskan penyimpanan:

# 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

Mari lihat ini dalam skenario realistis. Anda membangun pipeline data yang memproses banyak file CSV setiap malam, membersihkan dan memvalidasi data pelanggan sebelum memuatnya ke database. Anda perlu melacak file mana yang berhasil diproses dan menangkap masalah kualitas data:

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")

Log Anda disimpan dengan stempel waktu yang mudah dibaca, file berotasi otomatis, dan log lama dibersihkan sendiri. Anda dapat meninjau apa yang terjadi beberapa hari kemudian atau mengirim file log ke rekan saat troubleshooting.

Logging Terstruktur untuk Aplikasi Modern

Saat menjalankan aplikasi web, log Anda cepat menjadi campuran informasi yang berantakan. Aksi pengguna, kueri basis data, panggilan API, dan error tercampur menjadi dinding teks. Anda tidak mudah memfilter pengguna tertentu, melacak permintaan individual, atau mem-parsing log secara otomatis untuk sistem pemantauan.

Aplikasi berbasis data sangat diuntungkan dari logging terstruktur. Jika Anda bekerja dengan pipeline data atau analitik, mengembangkan keterampilan analis data membantu Anda memahami informasi apa yang perlu ditangkap dalam log.

Logging berbasis string tradisional memperburuk ini. Setiap pesan log hanyalah teks, jadi mengekstrak data bermakna membutuhkan pola regex yang kompleks atau pencarian manual.

Logging terstruktur mengubah ini dengan memperlakukan entri log sebagai objek data, bukan sekadar teks. Setiap entri log menjadi catatan terstruktur dengan bidang yang dapat dicari, sehingga mudah ditanya dan dianalisis secara terprogram.

Logging terstruktur JSON dengan serialize=True

Loguru membuat logging terstruktur menjadi sederhana dengan opsi 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")

Parameter serialize=True memberi tahu Loguru untuk menghasilkan JSON alih-alih teks biasa. Alih-alih kalimat yang mudah dibaca, file log Anda kini berisi data terstruktur:

{"text": "User login", "record": {"time": "2024-07-15T14:30:25", "level": {"name": "INFO"}, "extra": {"user_id": 123, "ip_address": "192.168.1.1"}}}

Format ini bekerja sempurna dengan alat analisis log yang dapat mencari dan memfilter data JSON secara otomatis.

Pengikatan konteks

Namun aplikasi web membutuhkan lebih dari sekadar data terstruktur. Anda butuh konteks yang menghubungkan entri log terkait. Saat memproses permintaan pengguna, Anda ingin semua log terkait berbagi informasi umum seperti user ID atau session ID.

Pengikatan konteks menyelesaikan ini dengan melampirkan informasi persisten ke logger Anda menggunakan 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'])

Kini setiap log dari order_logger otomatis menyertakan user_id dan order_id, sehingga mudah melacak semua log terkait pesanan tertentu.

Banyak sink untuk output berbeda

Aplikasi modern juga membutuhkan output log berbeda untuk tujuan berbeda. Anda mungkin ingin log konsol yang mudah dibaca saat pengembangan, tetapi log JSON untuk pemantauan produksi. Di Loguru, setiap tujuan output disebut “sink” — anggap sebagai tempat aliran pesan log.

Loguru memungkinkan Anda menambahkan banyak sink dengan format dan aturan berbeda:

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")

Panggilan logger.remove() menghapus output konsol bawaan Loguru agar Anda bisa menyiapkan sendiri. Setiap logger.add() membuat sink baru dengan aturannya sendiri tentang apa yang dicatat dan bagaimana formatnya.

Kini pernyataan log yang sama menghasilkan output berbeda:

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

Contoh lengkap Loguru: sistem pendaftaran pengguna

Mari lihat contoh yang lebih sederhana namun realistis menggunakan Loguru — sistem pendaftaran pengguna dasar:

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("[email protected]", "secure123")

Penyiapan ini memberi Anda output konsol yang mudah dibaca saat pengembangan, log JSON terstruktur untuk pemantauan otomatis, dan log error terpisah untuk peringatan. Metode bind() memastikan semua log untuk setiap pendaftaran pengguna menyertakan alamat email, sehingga debug jauh lebih mudah.

Penanganan Pengecualian Loguru

Saat kode Anda crash, biasanya Anda mendapatkan stack trace dasar yang memberi tahu di mana error terjadi, tetapi tidak banyak tentang alasannya. Anda kehilangan nilai variabel saat crash, sehingga sulit memahami apa yang salah. Penanganan pengecualian tradisional juga mengharuskan Anda membungkus semuanya dalam blok try-catch dan mencatat setiap pengecualian secara manual.

Ini menjadi sangat menyakitkan saat debug masalah produksi. Pengguna melaporkan error, tetapi Anda tidak dapat mereproduksinya karena tidak memiliki konteks yang ada saat error terjadi.

Loguru menyelesaikan ini dengan penangkapan pengecualian otomatis dan traceback yang disempurnakan yang menunjukkan tepat apa yang terjadi di kode Anda saat sesuatu berjalan salah.

Penangkapan pengecualian otomatis dengan @logger.catch

Dekorator @logger.catch secara otomatis menangkap pengecualian apa pun yang terjadi di suatu fungsi dan mencatatnya dengan konteks lengkap. Dekorator seperti @logger.catch adalah konsep Python tingkat menengah yang dapat mengubah cara Anda menangani error di seluruh codebase:

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)

Alih-alih program Anda crash dengan pesan error dasar, Loguru menangkap pengecualian dan mencatatnya dengan informasi terperinci, sementara program Anda terus berjalan. Dekorator ini berfungsi pada fungsi apa pun — metode kelas, fungsi async, atau fungsi biasa.

Traceback yang disempurnakan dengan inspeksi variabel

Namun Loguru melangkah lebih jauh dengan traceback yang disempurnakan yang menampilkan nilai variabel di setiap level call stack. Fitur ini disebut “diagnose” dan ibarat debugger yang tertanam di log Anda:

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)

Dengan diagnose=True, saat fungsi crash karena mencoba mengurangkan string dari angka, Loguru menunjukkan tepat apa yang ada di setiap variabel:

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"

Tingkat detail ini membuat debug jauh lebih cepat karena Anda dapat melihat persis data apa yang menyebabkan masalah.

Penanganan pengecualian yang peka terhadap lingkungan

Namun, traceback yang disempurnakan dapat mengekspos informasi sensitif seperti kata sandi atau API key di log produksi. Loguru memungkinkan Anda mengontrol perilaku ini untuk lingkungan yang berbeda:

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")

Evaluasi malas untuk kinerja

Fitur kuat lainnya adalah evaluasi malas (lazy evaluation), yang meningkatkan kinerja saat mencatat operasi mahal. Terkadang Anda ingin mencatat informasi kompleks, tetapi hanya jika benar-benar terjadi error:

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()}

Sintaks lambda: membuat fungsi yang hanya dipanggil ketika Loguru benar-benar menulis pesan log. Jika tidak ada error, expensive_data_summary() tidak pernah dijalankan, menghemat waktu pemrosesan.

Strategi berbeda untuk jenis error berbeda

Anda juga dapat menggunakan strategi penanganan pengecualian yang berbeda untuk berbagai jenis error:

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)

Parameter reraise=False memberi tahu Loguru untuk mencatat pengecualian tetapi tidak melemparkannya kembali, sehingga program Anda dapat terus berjalan. Ini berguna untuk fitur opsional yang tidak boleh merusak alur kerja utama Anda.

Contoh lengkap: pemrosesan file dengan penanganan error

Mari lihat contoh lengkap dengan sistem pemrosesan file yang menangani berbagai jenis error secara elegan:

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

Penyiapan ini memberi Anda penangkapan pengecualian otomatis, konteks error yang detail saat dibutuhkan, dan strategi penanganan berbeda untuk berbagai tipe error. Log Anda menjadi jauh lebih berguna untuk debug, sementara kode Anda tetap bersih dan mudah dibaca.

Konfigurasi dan Kustomisasi Loguru Lanjutan

Seiring aplikasi Anda berkembang, Anda akan menemukan skenario di mana default Loguru kurang pas. Mungkin Anda butuh level log khusus untuk metrik bisnis, ingin menyaring data sensitif dari log, atau perlu mengirim peringatan ke Slack saat terjadi error.

Kabar baiknya, Loguru dibangun untuk dikustomisasi tanpa kehilangan kesederhanaannya. Anda dapat memperluasnya dengan cara yang dalam sistem logging tradisional butuh konfigurasi kompleks, sembari menjaga kode tetap bersih dan mudah dibaca.

Mari lihat kustomisasi paling berguna yang menyelesaikan masalah nyata yang akan Anda hadapi di aplikasi produksi.

Level dan warna log kustom

Loguru hadir dengan level standar seperti INFO, DEBUG, dan ERROR. Namun terkadang Anda butuh sesuatu yang spesifik untuk aplikasi Anda. Mungkin Anda ingin level khusus untuk metrik kinerja atau peristiwa bisnis.

Membuat level log kustom itu mudah:

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")

Parameter no menetapkan prioritas level (angka lebih tinggi = prioritas lebih tinggi). Level standar: DEBUG=10, INFO=20, WARNING=30, ERROR=40, CRITICAL=50.

Mari lihat ini dalam skenario pelatihan 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!")

Mencegat dan memodifikasi pesan log

Terkadang Anda perlu memodifikasi pesan log sebelum ditulis. Kasus umum termasuk menghapus data sensitif, menambahkan ID permintaan, atau memformat ulang pesan untuk alat tertentu.

Loguru memungkinkan Anda mencegat pesan menggunakan parameter 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: [email protected]")

Anda juga dapat menggunakan filter untuk menambahkan informasi kontekstual:

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}"
)

Sink kustom untuk layanan eksternal

Sink adalah tempat aliran log Anda. Meskipun file dan konsol umum digunakan, sering kali Anda perlu mengirim log ke layanan eksternal seperti Slack, email, atau sistem pemantauan.

Berikut cara membuat sink kustom yang mengirim error ke 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!")

Berikut contoh praktis lainnya — sink kustom yang mengumpulkan metrik kinerja sepanjang jalannya aplikasi dan menyimpannya untuk analisis:

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...}
#   ]
# }

Keindahan pendekatan ini adalah kode aplikasi Anda tetap bersih — Anda cukup mencatat metrik seperti biasa, dan sink kolektor menangani penyimpanan secara otomatis. Anda dapat dengan mudah menggantinya dengan sink yang mengirim metrik ke Prometheus, DataDog, atau layanan pemantauan lainnya.

Kustomisasi ini memberi Anda fleksibilitas untuk menyesuaikan Loguru dengan kebutuhan spesifik sambil menjaga kesederhanaan yang menjadikannya unggul. Baik Anda membangun skrip kecil atau aplikasi besar, Anda dapat memperluas Loguru untuk menangani kebutuhan logging unik tanpa file konfigurasi kompleks atau boilerplate.

Kesimpulan

Loguru membuat logging di Python sesederhana yang seharusnya. Tidak ada lagi file konfigurasi, tidak ada lagi penyiapan handler, tidak ada lagi boilerplate. Cukup impor dan mulai logging dengan warna, stempel waktu, dan rotasi file otomatis.

Anda telah melihat bagaimana Loguru menangani titik sakit umum: menyimpan log ke file, merotasinya secara otomatis, menangkap pengecualian dengan konteks lengkap, dan mengirim log ke layanan eksternal. Fitur logging terstruktur membuatnya siap produksi, sementara level dan sink kustom memungkinkan Anda menyesuaikannya untuk kasus apa pun.

Gunakan Loguru saat:

  • Anda lelah melakukan debug dengan print
  • Anda membutuhkan logging cepat di skrip atau notebook
  • Anda membangun aplikasi web yang membutuhkan log terstruktur
  • Anda menginginkan pelacakan pengecualian yang lebih baik tanpa penyiapan kompleks

Untuk pembelajaran lebih dalam, jelajahi dokumentasi resmi bersama tutorial logging ini untuk cakupan komprehensif strategi logging Python.

Mulailah dari hal kecil. Ganti satu pernyataan print dengan logger.info(). Anda tidak akan kembali lagi.

Loguru FAQs

Bagaimana Loguru dibandingkan dengan pustaka logging Python lainnya?

Loguru menonjol karena tidak memerlukan konfigurasi — Anda bisa langsung logging dengan from loguru import logger. Berbeda dengan modul logging bawaan Python yang membutuhkan handler, formatter, dan penyiapan kompleks, Loguru menyediakan warna, stempel waktu, dan rotasi file secara bawaan. Loguru juga menawarkan traceback yang disempurnakan dengan inspeksi variabel yang tidak disediakan pustaka lain.

Apa keunggulan utama menggunakan Loguru dibanding modul logging bawaan Python?

Loguru menghilangkan kompleksitas konfigurasi, menyediakan rotasi dan retensi file otomatis, menawarkan logging JSON terstruktur dengan serialize=True, menyertakan traceback pengecualian yang disempurnakan dengan nilai variabel, dan mendukung sink kustom untuk layanan eksternal. Anda mendapatkan fitur logging siap produksi tanpa menulis kode penyiapan.

Apakah Loguru dapat menangani aplikasi multi-thread secara efisien?

Ya, Loguru thread-safe secara bawaan dan menangani aplikasi multi-thread dengan baik. Anda dapat menambahkan informasi thread ke log menggunakan filter, dan metode logger.bind() berfungsi lintas thread untuk menjaga konteks. Performa Loguru dioptimalkan untuk logging konkuren tanpa memblokir thread.

Bagaimana cara kerja rotasi dan retensi log otomatis Loguru?

Loguru menawarkan rotasi fleksibel berdasarkan ukuran file (rotation="10 MB"), interval waktu (rotation="00:00" untuk harian), atau kondisi kustom. Retensi secara otomatis menghapus file lama (retention=10 menyimpan 10 file), dan kompresi menghemat ruang (compression="zip"). Semuanya terjadi otomatis tanpa pengelolaan file manual.

Apa contoh praktis penggunaan fitur sink kustom Loguru?

Sink kustom memungkinkan Anda mengirim log ke layanan eksternal seperti Slack untuk peringatan error, mengumpulkan metrik untuk sistem pemantauan, atau memformat log untuk alat tertentu. Anda dapat membuat sink yang memfilter berdasarkan level log, menambahkan informasi kontekstual, atau mengintegrasikan dengan layanan seperti DataDog, Prometheus, atau notifikasi email untuk error kritis.

Bexruz (Bex) Tuychiev

Penulis

Bexruz (Bex) Tuychiev

Saya adalah kreator konten data science dengan pengalaman lebih dari 2 tahun dan salah satu dengan jumlah pengikut terbesar di Medium. Saya suka menulis artikel mendalam tentang AI dan ML dengan sedikit gaya sarkastik—karena harus ada sesuatu untuk membuatnya tidak terlalu membosankan. Saya telah menghasilkan lebih dari 130 artikel dan satu kursus di DataCamp, dengan satu lagi sedang dalam proses. Konten saya telah dilihat oleh lebih dari 5 juta pasang mata, dan 20 ribu di antaranya menjadi pengikut di Medium dan LinkedIn. 

Topik

Terkait

blogs

Tutorial Korelasi di R

blogs

Spaghetti Plot dan Jalur Badai