Belajar Django - Logging, Debugging & Testing
Episode 15 of 27

Belajar Django - Logging, Debugging & Testing

Membangun visibilitas aplikasi: konfigurasi LOGGING Django dan structured logging, debugging dengan Django Debug Toolbar, lalu pengujian dengan TestCase dan client test, pytest-django, serta coverage untuk memastikan kode teruji.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Sampai episode 14 aplikasi sudah kaya fitur — dan semakin kaya, semakin banyak yang bisa salah. Di episode ini kita membangun tiga hal yang menentukan kepercayaan diri di produksi: logging (mengetahui apa yang terjadi), debugging (menemukan di mana kesalahannya), dan testing (memastikan kesalahan tidak kembali).

Mengapa topik ini penting? Karena bug yang tidak terlihat adalah bom waktu. Logging yang baik memberi jejak saat insiden terjadi, debug toolbar mempercepat analisis saat development, dan test yang rapi membuat perubahan kode jadi berani tanpa takut merusak fitur lain. Tiga keterampilan ini memisahkan "developer" dari "engineer".

Konfigurasi LOGGING

Django memakai modul logging Python standar dengan hierarki: LoggerHandlerFormatter. Tambahkan konfigurasi di settings.py:

Pythonsettings.py - LOGGING
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "verbose": {
            "format": "{asctime} {levelname} {name} {message}",
            "style": "{",
        },
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "verbose",
        },
        "file": {
            "class": "logging.handlers.RotatingFileHandler",
            "filename": BASE_DIR / "logs/django.log",
            "maxBytes": 10 * 1024 * 1024,
            "backupCount": 5,
            "formatter": "verbose",
        },
    },
    "loggers": {
        "django": {"handlers": ["console", "file"], "level": "INFO"},
        "blog": {"handlers": ["console"], "level": "DEBUG", "propagate": False},
    },
}

RotatingFileHandler memotong file saat mencapai maxBytes dan menyimpan backupCount file lama — mencegah log memakan disk. Logger django menangkap request/error framework; logger blog untuk logika aplikasi sendiri.

Structured Logging

Log teks bebas sulit diparsing. Structured logging menghasilkan JSON per baris — standar untuk dikirim ke observability (episode 26 memakai OpenTelemetry). Tanpa library tambahan, format JSON bisa dibuat via formatter custom:

Pythondevblog/logging_formatter.py
import json
import logging
from datetime import datetime
 
class JsonFormatter(logging.Formatter):
    def format(self, record):
        data = {
            "ts": datetime.utcnow().isoformat() + "Z",
            "level": record.levelname,
            "logger": record.name,
            "message": record.getMessage(),
        }
        if record.exc_info:
            data["exc"] = self.formatException(record.exc_info)
        return json.dumps(data)

Pakai di production:

Pythonsettings.py - JSON formatter
LOGGING = {
    ...
    "formatters": {
        "json": {"()": "devblog.logging_formatter.JsonFormatter"},
    },
    "handlers": {
        "console": {"class": "logging.StreamHandler", "formatter": "json"},
    },
}

Di kode aplikasi:

Pythonblog/views.py - logging
import logging
 
logger = logging.getLogger(__name__)
 
def publish_post(request, pk):
    ...
    logger.info("post published", extra={"post_id": pk, "user": request.user.username})

Setiap log jadi satu objek JSON yang bisa di-query — ts, level, logger, plus field ekstra. Ini fondasi debugging di produksi.

Tip

Prinsip level log: DEBUG = detail untuk development, INFO = event penting (login, publish), WARNING = kondisi abnormal yang belum fatal, ERROR = operasi gagal, CRITICAL = sistem tidak bisa lanjut. Jangan log data sensitif (password, token, PII) — log yang bocor adalah insiden keamanan tersendiri (episode 18).

Django Debug Toolbar

Toolbar yang paling sering dipakai untuk debugging request di development:

Install debug toolbar
pip install django-debug-toolbar
Pythonsettings.py - debug toolbar
if DEBUG:
    INSTALLED_APPS += ["debug_toolbar"]
    MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"]
 
INTERNAL_IPS = ["127.0.0.1"]

Panelnya menampilkan per-request: SQL queries (jumlah + durasi), cache, template, headers, dan settings. Jangan pernah mengaktifkan ini di produksi — ia menambah overhead besar dan membocorkan query SQL ke siapa pun.

Warning

Debug Toolbar hanya boleh aktif saat DEBUG = True. Kalau DEBUG tidak sengaja True di produksi, dua hal langsung bocor: halaman error menampilkan traceback penuh + settings (termasuk SECRET_KEY di konteks template), dan toolbar mengekspos detail internal. Episode 18 akan meng-hardening ini, dan manage.py check --deploy mendeteksinya.

Testing dengan TestCase dan Client Test

Test Django dibangun di atas unittest. django.test.TestCase membuat database test terisolasi yang di-rollback tiap test. Client test mensimulasikan request:

Pythonblog/tests.py
from django.test import TestCase
from django.urls import reverse
 
from .models import Post
 
class PostListViewTests(TestCase):
    def setUp(self):
        self.author = User.objects.create_user(username="alice", password="x")
        self.post = Post.objects.create(
            title="Halo Dunia",
            slug="halo-dunia",
            body="Isi post",
            status="published",
            author=self.author,
        )
 
    def test_list_only_shows_published(self):
        Post.objects.create(
            title="Draft", slug="draft", body="x",
            status="draft", author=self.author,
        )
        response = self.client.get(reverse("blog:home"))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Halo Dunia")
        self.assertNotContains(response, "Draft")
 
    def test_detail_returns_404_for_unknown(self):
        response = self.client.get(reverse("blog:post_detail", args=[999]))
        self.assertEqual(response.status_code, 404)

setUp dijalankan sebelum tiap test. self.client mensimulasikan browser: get, post, login(). assertContains memeriksa konten HTML; assertEqual(status_code, ...) memeriksa status.

pytest-django dan Coverage

pytest lebih ringkas untuk suite besar:

Install pytest tooling
pip install pytest pytest-django pytest-cov
pytest.ini
[pytest]
DJANGO_SETTINGS_MODULE = devblog.settings
python_files = tests.py test_*.py *_tests.py

Test dengan fixture-style:

Pythonblog/tests/test_views.py
import pytest
 
@pytest.mark.django_db
def test_home_returns_200(client):
    response = client.get("/")
    assert response.status_code == 200

Jalankan dengan coverage:

Jalankan pytest + coverage
pytest --cov=blog --cov-report=term-missing

Output menampilkan persentase coverage per file dan baris yang belum ter-cover. @pytest.mark.django_db memberi akses database test hanya pada test yang butuh.

Note

Coverage 100% bukan jaminan bug-free — yang penting adalah baris-baris kritis (auth, payment, permission) ter-cover penuh. Target realistis produksi: 80%+ dengan prioritas pada view yang menangani uang dan data pengguna. Kombinasi TestCase (unit/integration) dan client/pytest (request-level) menutupi dua level sekaligus.

Verifikasi dan CI

Sebelum masuk pipeline CI (episode 23), pastikan ketiganya jalan bersama:

Suite verifikasi lengkap
python manage.py check
pytest --cov=blog
python manage.py check --deploy   # preview produksi (episode 18)

Penutup

Inti yang harus dibawa pulang:

  • Logging: logger → handler → formatter; RotatingFileHandler mencegah disk penuh.
  • Structured logging: JSON per baris untuk observability dan query yang mudah.
  • Jangan log data sensitif; toolbar dan DEBUG=True dilarang di produksi.
  • TestCase + client test untuk unit/integration; assertContains untuk cek konten.
  • pytest-django + coverage untuk suite yang ringkas dan terukur.
  • Debug Toolbar memberi visibilitas SQL — senjata audit N+1 episode 14.

Di episode 16 selanjutnya kita merapikan fondasi deployment: Settings & Environments Management — pemisahan konfigurasi per environment, django-environ/pydantic-settings, pengelolaan secrets, dan prinsip 12-factor untuk project yang siap produksi. Sampai jumpa di episode 16!

Belajar Django - Logging, Debugging & Testing | Belajar Django