For the complete documentation index, see llms.txt. This page is also available as Markdown.

Logging

Logging adalah mata dan telinga aplikasi kita di production. Tanpa log yang baik, kita buta terhadap apa yang terjadi: error tidak terdeteksi, performa tidak terukur, dan debugging menjadi mimpi buruk.

Di bab ini kita akan meningkatkan sistem logging dari log.Printf biasa menjadi structured logging dengan slog.Logger.

📂 Kode Lengkap Bab Ini: Seluruh kode yang dibahas di bab ini tersedia di GitHub:

🔗 github.com/jacky-htg/workshop/tree/main/09-logging

9.1 Masalah dengan Logging Saat Ini

Sejauh ini kita menggunakan log.Printf dan log.Fatalf dari package log standar. Pendekatan ini memiliki dua kelemahan utama:

Masalah
Penjelasan
Dampak

Variabel global

log package menggunakan logger global

Sulit di-test, tidak bisa disuntikkan (dependency injection)

Hanya teks

Output berupa string tidak terstruktur

Tool monitoring (Loki, Elasticsearch) sulit memparsing

Paket log standard bisa secara mudah dibuat menjadi variabel lokal, namun sulit untuk mendukung format struktured log.

Contoh log teks (sulit diparsing):

2024/01/15 10:30:45 error: querying users: connection refused

Contoh log terstruktur (mudah diparsing):

{"time":"2024-01-15T10:30:45Z","level":"ERROR","msg":"error: querying users","error":"connection refused","component":"repository"}

9.2 Mengenal slog.Logger

Go 1.21+ memperkenalkan package log/slog (Structured Logging) yang menjadi standar bawaan. Keunggulannya:

  • Multiple output formats – Teks (human-friendly) atau JSON (machine-friendly)

  • Log levels – Debug, Info, Warn, Error

  • Structured fields – Menambahkan key-value pairs ke setiap log

  • Context-aware – Bisa mengambil nilai dari context.Context

Kita akan menggunakan library wrapper dari go-libs/logger untuk kemudahan:

9.3 Dependency Injection untuk Logger

Prinsip penting: Logger juga harus di-inject, bukan global. Mengapa?

  • Testing bisa menggunakan logger mock

  • Setiap komponen bisa memiliki konteks sendiri (misal: menambahkan component field)

  • Tidak ada hidden dependency

Langkah 1: Update Bootstrap

Tambahkan Log field ke struct App dan inisialisasi di NewApp():

Langkah 2: Propagasikan Logger ke Semua Layer

Logger harus di-passing dari main() → bootstrap → handler → service → repository.

Update cmd/server/main.go:

Langkah 3: Update Repository Layer

Langkah 4: Update Service Layer

Langkah 5: Update Handler Layer

Langkah 6: Update CLI Main

9.4 Format Output: Teks vs JSON

logger.InitLogger(nil) secara default menghasilkan output teks yang mudah dibaca manusia. Untuk production, kita bisa mengubah ke format JSON:

Contoh output JSON:

9.5 Hierarki Log Levels

slog.Logger mendukung level logging yang bisa dikonfigurasi:

Level
Penggunaan

Debug

Informasi detail untuk debugging (hanya di development)

Info

Informasi normal (server started, user created, dll)

Warn

Kejadian tidak normal tapi tidak fatal (retry, timeout)

Error

Error yang perlu diinvestigasi

Ringkasan Bab 9

Di bab ini kita telah belajar:

Konsep
Implementasi

Structured logging

Menggunakan slog.Logger dengan format JSON

Dependency injection

Logger di-passing dari main() ke semua layer

Log levels

Debug, Info, Warn, Error

Context fields

Menambahkan field terstruktur ke setiap log

Bootstrap integration

Logger menjadi bagian dari struct App

Manfaat yang kita peroleh:

  • ✅ Log terstruktur (JSON) → mudah diintegrasikan dengan tool monitoring

  • ✅ Logger di-inject → mudah di-test dan diganti implementasinya

  • ✅ Log levels → bisa filter sesuai kebutuhan (debug di dev, info/warn di prod)

  • ✅ Konteks yang kaya → setiap log bisa membawa field tambahan (user_id, request_id, dll)

Yang akan datang:

  • Saat ini semua log menggunakan context.Background()

  • Bab selanjutnya: Routing – membangun router HTTP sendiri untuk mendukung multiple endpoints dengan method (GET, POST, PUT, DELETE) dan path parameters

Last updated