Python

Python Logging: Sistem Logging

Tutorial lengkap Python Logging β€” logger, handlers, formatters, levels, dictionary config, dan praktik terbaik untuk membangun sistem logging profesional di aplikasi Python

1. Pengenalan Logging

Logging adalah proses mencatat peristiwa (event) yang terjadi saat program berjalan. Modul logging di Python adalah library standar yang menyediakan sistem logging yang fleksibel dan powerful β€” jauh lebih baik daripada menggunakan print() untuk debugging.

Logging digunakan di semua aplikasi production-grade β€” mulai dari web server, API, script automasi, hingga aplikasi desktop. Log membantu developer memahami apa yang terjadi di dalam sistem, mendeteksi masalah, dan melakukan audit.

Ekosistem Logging di Python

Diagram: Arsitektur Logging Python
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 ARSITEKTUR LOGGING                           β”‚
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Kode    │────▢│  Logger  │────▢│      Handler(s)      β”‚ β”‚
β”‚  β”‚  Anda    β”‚     β”‚  (entry  β”‚     β”‚                      β”‚ β”‚
β”‚  β”‚          β”‚     β”‚   point) β”‚     β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚ β”‚ StreamHandler    β”‚ β”‚ β”‚
β”‚                                     β”‚ β”‚ (console output) β”‚ β”‚ β”‚
β”‚                                     β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚
β”‚                                     β”‚ β”‚ FileHandler      β”‚ β”‚ β”‚
β”‚                                     β”‚ β”‚ (write to file)  β”‚ β”‚ β”‚
β”‚                                     β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚
β”‚                                     β”‚ β”‚ RotatingFileH.   β”‚ β”‚ β”‚
β”‚                                     β”‚ β”‚ (auto-rotate)    β”‚ β”‚ β”‚
β”‚                                     β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚
β”‚                                     β”‚ β”‚ SMTPHandler      β”‚ β”‚ β”‚
β”‚                                     β”‚ β”‚ (send email)     β”‚ β”‚ β”‚
β”‚                                     β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚                                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                                                β”‚             β”‚
β”‚                                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚                                     β”‚     Formatter        β”‚ β”‚
β”‚                                     β”‚  (format pesan log)  β”‚ β”‚
β”‚                                     β”‚                      β”‚ β”‚
β”‚                                     β”‚  2024-06-26 10:30:15 β”‚ β”‚
β”‚                                     β”‚  app.module - INFO    β”‚ β”‚
β”‚                                     β”‚  - Pesan log...      β”‚ β”‚
β”‚                                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Mengapa Logging?

print() vs logging

Aspek print() logging
LevelTidak adaDEBUG, INFO, WARNING, ERROR, CRITICAL
OutputHanya consoleConsole, file, email, HTTP, socket
FormatManualOtomatis (timestamp, level, module)
RotasiTidak adaOtomatis rotate file per ukuran/waktu
KontrolSulit di-disableBisa di-filter per level/module
Thread-safeTidakYa
Production❌ Tidak cocokβœ… Standar industri
Python β€” print vs logging
# ❌ Menggunakan print() β€” tidak profesional
print("Database connected")        # Kapan? Dari mana? Level apa?
print("User Budi logged in")       # Tidak ada timestamp
print("Error: connection failed")  # Tidak bisa di-filter

# βœ… Menggunakan logging β€” profesional
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

logger.info("Database connected")
# INFO:__main__:Database connected

logger.info("User Budi logged in")
# INFO:__main__:User Budi logged in

logger.error("Error: connection failed")
# ERROR:__main__:Error: connection failed

3. Log Levels

Python logging memiliki 5 level standar yang menunjukkan tingkat keparahan pesan. Setiap level memiliki angka (severity) β€” semakin tinggi angkanya, semakin kritis.

Level Angka Kapan Digunakan Contoh
DEBUG10Info detail untuk debuggingVariabel x=42, query SQL
INFO20Konfirmasi bahwa program berjalan normalServer started, user login
WARNING30Sesuatu yang tidak diharapkan tapi program masih jalanDisk space low, deprecated API
ERROR40Error yang menyebabkan fungsi gagalDB connection failed, file not found
CRITICAL50Error fatal yang menyebabkan program berhentiOut of memory, system crash
Diagram: Log Level Hierarchy
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            LOG LEVEL HIERARCHY                    β”‚
β”‚                                                   β”‚
β”‚  Level         Angka    Keparahan                 β”‚
β”‚  ─────────────────────────────────────            β”‚
β”‚  CRITICAL  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  50  πŸ”΄ Paling kritis       β”‚
β”‚  ERROR     β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ   40  πŸ”΄ Error                β”‚
β”‚  WARNING   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ     30  🟑 Peringatan           β”‚
β”‚  INFO      β–ˆβ–ˆβ–ˆβ–ˆ       20  🟒 Informasi            β”‚
β”‚  DEBUG     β–ˆβ–ˆ         10  πŸ”΅ Detail debug         β”‚
β”‚                                                   β”‚
β”‚  Jika level set ke WARNING:                       β”‚
β”‚  βœ… CRITICAL, ERROR, WARNING β†’ tercatat           β”‚
β”‚  ❌ INFO, DEBUG β†’ diabaikan                       β”‚
β”‚                                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Python β€” Log Levels
import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

# Menggunakan setiap level
logger.debug("Memproses data: x=42, y=100")
# DEBUG:__main__:Memproses data: x=42, y=100

logger.info("Server berhasil dimulai pada port 8000")
# INFO:__main__:Server berhasil dimulai pada port 8000

logger.warning("Penggunaan memori mencapai 85%")
# WARNING:__main__:Penggunaan memori mencapai 85%

logger.error("Gagal terhubung ke database PostgreSQL")
# ERROR:__main__:Gagal terhubung ke database PostgreSQL

logger.critical("Sistem kehabisan memori! Shutdown darurat!")
# CRITICAL:__main__:Sistem kehabisan memori! Shutdown darurat!

# Menggunakan f-string untuk formatting
user = "Budi"
action = "login"
logger.info(f"User {user} melakukan {action}")
# INFO:__main__:User Budi melakukan login

# Cara yang lebih efisien: lazy formatting
logger.info("User %s melakukan %s", user, action)
# String hanya di-format jika level aktif (hemat performa)

4. Basic Logging

Konfigurasi Dasar dengan basicConfig

Python β€” basicConfig
import logging

# ===== Konfigurasi paling sederhana =====
logging.basicConfig(level=logging.INFO)
logging.info("Pesan info")  # Akan muncul di console

# ===== Konfigurasi dengan format lengkap =====
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
# Output: 2024-06-26 10:30:15 - __main__ - INFO - Pesan info

# ===== Konfigurasi output ke file =====
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    filename='app.log',       # Tulis ke file
    filemode='w'              # 'w' = overwrite, 'a' = append
)

logging.debug("Debug message")
logging.info("Info message")
logging.warning("Warning message")
# Semua tertulis ke app.log

# ===== Penting: basicConfig hanya bisa dipanggil SEKALI =====
# Panggilan kedua akan diabaikan!
# Gunakan Handler untuk konfigurasi yang lebih fleksibel.

Variabel yang Tersedia di Format

Variabel Keterangan Contoh
%(asctime)sTimestamp2024-06-26 10:30:15
%(name)sNama logger__main__
%(levelname)sNama levelINFO
%(levelno)sNomor level20
%(message)sPesan logUser logged in
%(filename)sNama fileapp.py
%(funcName)sNama fungsiprocess_data
%(lineno)dNomor baris42
%(module)sNama modulapp
%(process)dProcess ID12345
%(thread)dThread ID67890

5. Formatters

Formatter menentukan format output pesan log β€” timestamp, level, nama module, dan isi pesan.

Python β€” Formatters
import logging

# Buat logger
logger = logging.getLogger('myapp')
logger.setLevel(logging.DEBUG)

# Buat formatter
formatter_simple = logging.Formatter('%(levelname)s - %(message)s')

formatter_detail = logging.Formatter(
    '%(asctime)s | %(name)s | %(levelname)-8s | %(filename)s:%(lineno)d | %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

formatter_json = logging.Formatter(
    '{"time": "%(asctime)s", "level": "%(levelname)s", '
    '"module": "%(module)s", "message": "%(message)s"}',
    datefmt='%Y-%m-%dT%H:%M:%S'
)

# Buat handler dan pasang formatter
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
console_handler.setFormatter(formatter_simple)

file_handler = logging.FileHandler('app_detail.log', encoding='utf-8')
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(formatter_detail)

json_handler = logging.FileHandler('app.json', encoding='utf-8')
json_handler.setLevel(logging.WARNING)
json_handler.setFormatter(formatter_json)

# Pasang handler ke logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)
logger.addHandler(json_handler)

# Test
logger.debug("Pesan debug")        # Hanya console
logger.info("Pesan info")           # Console + file_detail
logger.warning("Pesan warning")     # Console + file_detail + json
logger.error("Pesan error")         # Console + file_detail + json

6. Handlers

Handler menentukan ke mana pesan log dikirim β€” console, file, email, atau HTTP. Satu logger bisa memiliki beberapa handler sekaligus.

Jenis Handler

Handler Fungsi Kegunaan
StreamHandlerOutput ke console (stdout/stderr)Debugging lokal
FileHandlerTulis ke fileLog permanen
RotatingFileHandlerFile dengan rotasi berdasarkan ukuranProduction
TimedRotatingFileHandlerFile dengan rotasi berdasarkan waktuLog harian
SMTPHandlerKirim email saat errorAlerting
HTTPHandlerKirim log via HTTPCentralized logging
SysLogHandlerKirim ke syslogSystem logging

RotatingFileHandler

Python β€” Rotating Handler
import logging
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler

logger = logging.getLogger('myapp')
logger.setLevel(logging.DEBUG)

# ===== RotatingFileHandler β€” rotate per ukuran =====
# File rotate saat mencapai 5MB, simpan 5 backup
rotating_handler = RotatingFileHandler(
    'app.log',
    maxBytes=5 * 1024 * 1024,  # 5 MB
    backupCount=5,              # Simpan 5 file backup
    encoding='utf-8'
)
rotating_handler.setLevel(logging.INFO)

# File yang dihasilkan:
# app.log       (aktif)
# app.log.1     (backup terbaru)
# app.log.2
# app.log.3
# app.log.4
# app.log.5     (backup terlama, akan dihapus)

# ===== TimedRotatingFileHandler β€” rotate per waktu =====
# Rotate setiap tengah malam, simpan 30 hari
timed_handler = TimedRotatingFileHandler(
    'daily.log',
    when='midnight',            # Rotate jam 00:00
    interval=1,                 # Setiap 1 interval
    backupCount=30,             # Simpan 30 file backup
    encoding='utf-8'
)

# Opsi 'when':
# 'S'  β†’ setiap detik
# 'M'  β†’ setiap menit
# 'H'  β†’ setiap jam
# 'D'  β†’ setiap hari
# 'midnight' β†’ setiap tengah malam
# 'W0'-'W6' β†’ setiap hari dalam minggu (0=Senin)

# Pasang handler
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
rotating_handler.setFormatter(formatter)
timed_handler.setFormatter(formatter)

logger.addHandler(rotating_handler)
logger.addHandler(timed_handler)

7. Loggers dan Hierarchy

Logger di Python memiliki hierarki berdasarkan nama, dipisahkan oleh titik (.). Logger anak mewarisi konfigurasi dari logger parent.

Diagram: Logger Hierarchy
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              LOGGER HIERARCHY                      β”‚
β”‚                                                    β”‚
β”‚  root logger                                       β”‚
β”‚  β”œβ”€β”€ myapp                 (parent untuk semua)    β”‚
β”‚  β”‚   β”œβ”€β”€ myapp.database    (DB operations)         β”‚
β”‚  β”‚   β”œβ”€β”€ myapp.api         (API requests)          β”‚
β”‚  β”‚   └── myapp.auth        (authentication)        β”‚
β”‚  └── another_app                                   β”‚
β”‚                                                    β”‚
β”‚  Logging flow:                                     β”‚
β”‚  1. Pesan dicatat ke logger                        β”‚
β”‚  2. Jika logger punya handler β†’ proses             β”‚
β”‚  3. Pesan propagate ke parent β†’ ulangi             β”‚
β”‚  4. Sampai ke root logger                          β”‚
β”‚                                                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Python β€” Logger Hierarchy
import logging

# ===== Membuat logger dengan nama =====
# Logger dengan hierarki (dipisahkan titik)
logger_db = logging.getLogger('myapp.database')
logger_api = logging.getLogger('myapp.api')
logger_auth = logging.getLogger('myapp.auth')

# Set level pada masing-masing logger
logger_db.setLevel(logging.DEBUG)
logger_api.setLevel(logging.INFO)
logger_auth.setLevel(logging.WARNING)

# ===== Propagasi =====
# Logger anak mewarisi handler dari parent
# myapp.database β†’ myapp β†’ root

# Nonaktifkan propagasi jika ingin handler sendiri
# logger_db.propagate = False

# ===== Praktik terbaik: gunakan __name__ =====
# __name__ otomatis memberi nama berdasarkan modul
# Jika file di: myapp/database.py β†’ logger nama "myapp.database"
logger = logging.getLogger(__name__)

# Di production, biasanya setup di main app:
def setup_logging():
    """Setup logging untuk seluruh aplikasi."""
    root = logging.getLogger()
    root.setLevel(logging.DEBUG)

    # Console handler untuk development
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    console.setFormatter(logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    ))
    root.addHandler(console)

    # File handler untuk production
    from logging.handlers import RotatingFileHandler
    file_h = RotatingFileHandler(
        'app.log', maxBytes=10*1024*1024, backupCount=5
    )
    file_h.setLevel(logging.DEBUG)
    file_h.setFormatter(logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    ))
    root.addHandler(file_h)

# Panggil di awal aplikasi
setup_logging()

8. Exception Logging

Logging exception dengan benar sangat penting untuk debugging di production. Modul logging memiliki fitur khusus untuk mencatat traceback.

Python β€” Exception Logging
import logging

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# ===== exc_info=True β€” catat traceback lengkap =====
def proses_data(data):
    try:
        hasil = 100 / data
        return hasil
    except ZeroDivisionError:
        logger.error("Gagal memproses data: pembagian dengan nol!", exc_info=True)
        # exc_info=True menambahkan traceback lengkap di log
        #
        # ERROR:__main__:Gagal memproses data: pembagian dengan nol!
        # Traceback (most recent call last):
        #   File "app.py", line 6, in proses_data
        #     hasil = 100 / data
        # ZeroDivisionError: division by zero

# ===== logger.exception() β€” shortcut untuk exc_info=True =====
def baca_file(path):
    try:
        with open(path, 'r') as f:
            return f.read()
    except FileNotFoundError:
        logger.exception(f"File tidak ditemukan: {path}")
        # logger.exception() otomatis set exc_info=True
        # Hanya gunakan di dalam blok except!

# ===== Stack info β€” tambah info stack tanpa exception =====
def fungsi_dalam():
    logger.warning("Ada masalah di sini", stack_info=True)
    # Tambahkan stack trace meskipun tidak ada exception

# ===== Contoh: API error handler =====
def handle_api_request(request):
    logger.info(f"Menerima request: {request.method} {request.url}")
    try:
        result = proses_request(request)
        logger.info(f"Request berhasil: {result.status}")
        return result
    except TimeoutError:
        logger.error("API timeout", exc_info=True)
        return {"error": "Timeout"}
    except Exception as e:
        logger.critical(f"Error tidak terduga: {e}", exc_info=True)
        return {"error": "Internal server error"}

9. Konfigurasi Logging

Python menyediakan beberapa cara untuk mengkonfigurasi logging β€” dari basicConfig, dictConfig, hingga file konfigurasi.

Dictionary Config

Python β€” dictConfig
import logging
import logging.config

# ===== Dictionary-based configuration =====
LOGGING_CONFIG = {
    'version': 1,
    'disable_existing_loggers': False,

    # Formatters
    'formatters': {
        'standard': {
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        },
        'simple': {
            'format': '%(levelname)s - %(message)s'
        },
        'detailed': {
            'format': '%(asctime)s | %(name)s | %(levelname)-8s | '
                      '%(filename)s:%(lineno)d | %(funcName)s() | %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        }
    },

    # Handlers
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'INFO',
            'formatter': 'simple',
            'stream': 'ext://sys.stdout'
        },
        'file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'level': 'DEBUG',
            'formatter': 'detailed',
            'filename': 'app.log',
            'maxBytes': 10485760,  # 10 MB
            'backupCount': 5,
            'encoding': 'utf-8'
        },
        'error_file': {
            'class': 'logging.FileHandler',
            'level': 'ERROR',
            'formatter': 'detailed',
            'filename': 'errors.log',
            'encoding': 'utf-8'
        }
    },

    # Loggers
    'loggers': {
        'myapp': {
            'level': 'DEBUG',
            'handlers': ['console', 'file', 'error_file'],
            'propagate': False
        },
        'myapp.database': {
            'level': 'WARNING',
            'handlers': ['file', 'error_file'],
            'propagate': False
        }
    },

    # Root logger
    'root': {
        'level': 'WARNING',
        'handlers': ['console', 'file']
    }
}

# Terapkan konfigurasi
logging.config.dictConfig(LOGGING_CONFIG)

# Gunakan logger
logger = logging.getLogger('myapp')
logger.debug("Debug message")    # ke file
logger.info("Info message")      # ke console + file
logger.warning("Warning message") # ke console + file
logger.error("Error message")    # ke console + file + error_file

File Config

INI β€” logging.conf
# File: logging.conf
[loggers]
keys=root,myapp

[handlers]
keys=consoleHandler,fileHandler

[formatters]
keys=simpleFormatter,detailFormatter

[logger_root]
level=WARNING
handlers=consoleHandler

[logger_myapp]
level=DEBUG
handlers=consoleHandler,fileHandler
qualname=myapp
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=INFO
formatter=simpleFormatter
args=(sys.stdout,)

[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=detailFormatter
args=('app.log', 'a', 'utf-8')

[formatter_simpleFormatter]
format=%(levelname)s - %(message)s

[formatter_detailFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=%Y-%m-%d %H:%M:%S

# === Menggunakan dari Python ===
# import logging.config
# logging.config.fileConfig('logging.conf')
# logger = logging.getLogger('myapp')

10. Praktik Terbaik

πŸ’‘ Praktik Terbaik Python Logging

1. Gunakan __name__ sebagai nama logger. Otomatis sesuai hierarki modul.
2. Jangan gunakan root logger langsung. Buat logger tersendiri per modul.
3. Set level di handler, bukan hanya di logger. Lebih fleksibel.
4. Gunakan lazy formatting. logger.info("x=%s", x) bukan logger.info(f"x={x}")
5. Selalu gunakan exc_info=True saat logging exception.
6. Gunakan RotatingFileHandler di production agar file tidak membengkak.
7. Hindari logging data sensitif (password, token, data pribadi).

Python β€” Best Practices
import logging

# βœ… 1. Gunakan __name__
logger = logging.getLogger(__name__)

# βœ… 2. Lazy formatting (hanya format jika level aktif)
user_id = 12345
logger.info("Processing user %s", user_id)  # Bukan f"..."

# βœ… 3. Jangan log data sensitif
# ❌ logger.info(f"Password: {password}")
# ❌ logger.info(f"Token: {api_token}")
# βœ… logger.info("User %s authenticated successfully", username)

# βœ… 4. Gunakan level yang tepat
logger.debug("Variable x=%d, y=%d", x, y)      # Debug detail
logger.info("Request processed in %dms", time)   # Info normal
logger.warning("Cache miss for key: %s", key)    # Perhatian
logger.error("Failed to connect: %s", err)       # Error
logger.critical("System out of memory!")          # Kritis

# βœ… 5. Structured logging untuk production
def log_request(logger, method, path, status, duration):
    """Log HTTP request dengan format terstruktur."""
    log_data = {
        'method': method,
        'path': path,
        'status': status,
        'duration_ms': duration
    }
    if status >= 500:
        logger.error("Request failed: %s", log_data)
    elif status >= 400:
        logger.warning("Client error: %s", log_data)
    else:
        logger.info("Request OK: %s", log_data)

# βœ… 6. Filter sensitive data
class SensitiveFilter(logging.Filter):
    """Filter untuk menyensor data sensitif."""
    SENSITIVE_PATTERNS = ['password', 'token', 'secret', 'api_key']

    def filter(self, record):
        msg = record.getMessage().lower()
        for pattern in self.SENSITIVE_PATTERNS:
            if pattern in msg:
                record.msg = "[SENSITIVE DATA REDACTED]"
                record.args = ()
                break
        return True

logger.addFilter(SensitiveFilter())

11. Proyek Praktik: Logging untuk Aplikasi Web

Python β€” App Logger Setup
"""
Sistem logging lengkap untuk aplikasi web.
File: logger_setup.py
"""
import logging
import logging.config
from logging.handlers import RotatingFileHandler
from datetime import datetime
from pathlib import Path

def setup_app_logging(
    app_name="myapp",
    log_dir="logs",
    console_level=logging.INFO,
    file_level=logging.DEBUG,
    max_bytes=10*1024*1024,  # 10 MB
    backup_count=10
):
    """Setup logging profesional untuk aplikasi."""

    # Buat direktori log
    log_path = Path(log_dir)
    log_path.mkdir(parents=True, exist_ok=True)

    # Root logger
    root = logging.getLogger()
    root.setLevel(logging.DEBUG)

    # Format
    detail_fmt = logging.Formatter(
        '%(asctime)s | %(name)-20s | %(levelname)-8s | '
        '%(filename)s:%(lineno)d | %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    console_fmt = logging.Formatter(
        '%(asctime)s | %(levelname)-8s | %(message)s',
        datefmt='%H:%M:%S'
    )

    # Console handler
    console = logging.StreamHandler()
    console.setLevel(console_level)
    console.setFormatter(console_fmt)
    root.addHandler(console)

    # File handler β€” semua log
    all_handler = RotatingFileHandler(
        log_path / "app.log",
        maxBytes=max_bytes,
        backupCount=backup_count,
        encoding='utf-8'
    )
    all_handler.setLevel(file_level)
    all_handler.setFormatter(detail_fmt)
    root.addHandler(all_handler)

    # File handler β€” error saja
    error_handler = RotatingFileHandler(
        log_path / "error.log",
        maxBytes=max_bytes,
        backupCount=backup_count,
        encoding='utf-8'
    )
    error_handler.setLevel(logging.ERROR)
    error_handler.setFormatter(detail_fmt)
    root.addHandler(error_handler)

    # Logger untuk aplikasi
    logger = logging.getLogger(app_name)
    logger.info("=" * 60)
    logger.info("Aplikasi %s dimulai pada %s", app_name, datetime.now())
    logger.info("=" * 60)

    return logger

# ===== Contoh penggunaan =====
if __name__ == "__main__":
    logger = setup_app_logging("beebane_api")

    # Simulasi aktivitas aplikasi
    logger.debug("Memuat konfigurasi database...")
    logger.info("Server berjalan pada port 8000")
    logger.info("Menerima request GET /api/users")
    logger.warning("Rate limit mendekati batas: 95/100")
    logger.error("Database connection timeout setelah 30s")
    logger.critical("Memory usage mencapai 95%! Restart diperlukan")

    # Simulasi exception
    try:
        result = 1 / 0
    except ZeroDivisionError:
        logger.exception("Error saat menghitung rata-rata")

    logger.info("Aplikasi selesai")

12. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Python Logging:

Pertanyaan 1: Apa urutan level logging dari yang paling rendah ke paling tinggi?

a) INFO, DEBUG, WARNING, ERROR, CRITICAL
b) DEBUG, INFO, WARNING, ERROR, CRITICAL
c) DEBUG, WARNING, INFO, ERROR, CRITICAL
d) CRITICAL, ERROR, WARNING, INFO, DEBUG

Pertanyaan 2: Apa fungsi dari Handler dalam logging?

a) Memformat pesan log
b) Menentukan level minimum logging
c) Menentukan ke mana pesan log dikirim (console, file, dll)
d) Membuat logger baru

Pertanyaan 3: Apa keunggulan logger.info("x=%s", x) dibanding logger.info(f"x={x}")?

a) Lebih mudah dibaca
b) String hanya di-format jika level log aktif (hemat performa)
c) Bisa menangani tipe data lebih banyak
d) Output lebih rapi

Pertanyaan 4: Handler apa yang cocok untuk mencegah file log membengkak di production?

a) StreamHandler
b) FileHandler
c) RotatingFileHandler
d) NullHandler

Pertanyaan 5: Apa fungsi dari logger.exception()?

a) Melempar exception baru
b) Mencatat pesan error dengan level CRITICAL
c) Mencatat pesan error pada level ERROR dengan traceback lengkap (exc_info=True)
d) Menghentikan eksekusi program
πŸ” Zoom
100%
🎨 Tema