Compiler bisa menangkap tipe yang salah, tetapi tidak bisa menangkap logika yang salah: fungsi yang mengembalikan nilai tak terduga, variabel yang berubah di titik yang salah, atau kondisi yang tidak pernah tercapai. Debugger menyelesaikan masalah itu dengan cara menghentikan eksekusi di titik yang kita pilih, lalu membiarkan kita memeriksa isi memori saat program sedang berhenti. Delve adalah debugger standar komunitas Go, dibuat khusus untuk memahami goroutine, defer, dan struktur internal runtime Go. Pada chapter ini kita akan memasang Delve, menyiapkan program target, lalu menjalankan sesi debugging nyata dengan breakpoint dan pencetakan variabel.
Memasang Delve #
Delve didistribusikan sebagai module Go, jadi pemasangannya cukup satu perintah go install dari repositori resminya:
go install github.com/go-delve/delve/cmd/dlv@latestPerintah tersebut mengunduh source code Delve, mengompilasinya, lalu menaruh binary dlv di $GOPATH/bin (biasanya ~/go/bin). Pastikan direktori itu berada di PATH Anda, lalu verifikasi pemasangan:
dlv versionOutput yang Dihasilkan:
Delve Debugger
Version: 1.27.2
Build: $Id: 360e7b2181d3da54115aaee4f569954bca95cfe3 $Menyiapkan Program Target #
Berkas contoh.go di bawah halaman menghitung upah lembur Budi: jam ke atas 40 mendapat bonus setengah tarif. Program ini berjalan mulus dan keluar 0, tetapi angka 2.600.000 di output akan kita selidiki — apakah perhitungan bonusnya benar-benar sesuai aturan? Mari kita hentikan eksekusi di tengah jalan dan intip variabel-variabelnya:
package main
import "fmt"
// hitungLembur menghitung upah lembur; jam di atas 40 mendapat bonus setengah tarif.
func hitungLembur(jam int, tarif int) int {
upah := jam * tarif
if jam > 40 {
upah += (jam - 40) * tarif / 2
}
return upah
}
func main() {
jamBudi := 48
tarifBudi := 50000
upahBudi := hitungLembur(jamBudi, tarifBudi)
fmt.Println("Upah lembur Budi:", upahBudi)
}Output yang Dihasilkan:
Upah lembur Budi: 2600000Mari kita telaah baris demi baris program di atas:
- Baris 6 (
func hitungLembur): fungsi target debugging; parameterjamdantarifadalah variabel yang akan kita inspeksi. - Baris 7 (
upah := jam * tarif): perhitungan dasar 48 × 50.000 = 2.400.000. - Baris 8–10: blok bonus untuk jam di atas 40 — kandidat kuat sumber kejutan angka, karena menambah 8 × 25.000 = 200.000.
- Baris 15–18:
mainmemanggil fungsi target; breakpoint akan dipasang dihitungLemburdan di barisreturn upah.
Sesi Debugging dengan Breakpoint #
Delve bekerja pada package, bukan berkas tunggal, jadi kita salin program ke folder terpisah yang sudah menjadi module. Sesi berikut dijalankan dari folder itu dan memakai dlv debug:
mkdir -p debugdemo && cp contoh.go debugdemo/main.go
cd debugdemo
go mod init debugdemo
printf 'break main.hitungLembur\ncontinue\nprint jam\nprint tarif\nbreak 11\ncontinue\nprint upah\nstack\ncontinue\nquit\n' | dlv debug --allow-non-terminal-interactive=trueOutput yang Dihasilkan:
Type 'help' for list of commands.
(dlv) Breakpoint 1 set at 0x4b6384 for main.hitungLembur() ./main.go:6
(dlv) > [Breakpoint 1] main.hitungLembur() ./main.go:6 (hits goroutine(1):1 total:1) (PC: 0x4b6384)
1: package main
2:
3: import "fmt"
4:
5: // hitungLembur menghitung upah lembur; jam di atas 40 mendapat bonus setengah tarif.
=> 6: func hitungLembur(jam int, tarif int) int {
7: upah := jam * tarif
8: if jam > 40 {
9: upah += (jam - 40) * tarif / 2
10: }
11: return upah
(dlv) 48
(dlv) 50000
(dlv) Breakpoint 2 set at 0x4b63cf for main.hitungLembur() ./main.go:11
(dlv) > [Breakpoint 2] main.hitungLembur() ./main.go:11 (hits goroutine(1):1 total:1) (PC: 0x4b63cf)
6: func hitungLembur(jam int, tarif int) int {
7: upah := jam * tarif
8: if jam > 40 {
9: upah += (jam - 40) * tarif / 2
10: }
=> 11: return upah
12: }
13:
14: func main() {
15: jamBudi := 48
16: tarifBudi := 50000
(dlv) 2600000
(dlv) 0 0x00000000004b63cf in main.hitungLembur
at ./main.go:11
1 0x00000000004b6413 in main.main
at ./main.go:18
2 0x0000000000450d27 in runtime.main
at /home/z/tools/go/src/runtime/proc.go:302
3 0x0000000000489b21 in runtime.goexit
at /home/z/tools/go/src/runtime/asm_amd64.s:1264
(dlv) Upah lembur Budi: 2600000
Process 6451 has exited with status 0
(dlv) Membaca Alur Sesi #
Sesi di atas memperlihatkan pola kerja debugger secara utuh. Perintah break main.hitungLembur memasang breakpoint pertama di pintu masuk fungsi; continue menjalankan program sampai titik itu, dan Delve menampilkan cuplikan source code dengan penanda => pada baris aktif. Perintah print jam dan print tarif mencetak nilai parameter (48 dan 50000) tanpa mengubah apa pun. Breakpoint kedua dipasang lewat break 11 — nomor baris pada berkas aktif — lalu print upah mengungkap nilai 2600000 tepat sebelum dikembalikan, dan stack menampilkan call stack: hitungLembur dipanggil dari main baris 18, yang dipanggil runtime.main. Terakhir, continue kedua membiarkan program selesai dan mencetak output aslinya.
| Perintah Delve | Singkat | Fungsi |
|---|---|---|
break main.fn / break 11 | b | Pasang breakpoint pada fungsi atau baris |
continue | c | Jalankan sampai breakpoint berikutnya |
next | n | Eksekusi satu baris, lewati pemanggilan fungsi |
step | s | Masuk ke dalam fungsi yang dipanggil |
print x | p | Cetak nilai variabel atau ekspresi |
locals | — | Cetak semua variabel lokal frame aktif |
stack | bt | Tampilkan call stack |
quit | q | Keluar dari sesi |
Debugger menjawab “berapa nilainya sekarang”, tetapi untuk menjawab “jalur mana yang ditempuh program di production” kita butuh jejak yang lebih murah: logging terstruktur — topik chapter berikutnya.
Referensi #
- Delve: Debugger untuk Go — dokumentasi resmi, panduan instalasi, dan daftar perintah.
- Diagnostics — dokumentasi resmi Go tentang strategi debugging dan profiling.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
contoh.go
Unduh berkaspackage main
import "fmt"
// hitungLembur menghitung upah lembur; jam di atas 40 mendapat bonus setengah tarif.
func hitungLembur(jam int, tarif int) int {
upah := jam * tarif
if jam > 40 {
upah += (jam - 40) * tarif / 2
}
return upah
}
func main() {
jamBudi := 48
tarifBudi := 50000
upahBudi := hitungLembur(jamBudi, tarifBudi)
fmt.Println("Upah lembur Budi:", upahBudi)
}