Apa yang diuji Vanya
Vanya tahu bahwa dia akan menguji bundel "nginx + service".
Di sini saya akan segera memberi komentar: bundel semacam itu dipilih untuk artikel ini hanya karena bundel tersebut paling jelas dapat mendemonstrasikan penggunaan berbagai utilitas saat men-debug masalah dan karena sangat mudah dikonfigurasi dan dinaikkan. Dalam istilah nyata, ini bisa berupa layanan atau rangkaian layanan yang membuat permintaan satu sama lain.
Server HTTP default Python SimpleHTTPServer bertindak sebagai layanan, yang, sebagai respons atas permintaan tanpa parameter, menampilkan konten direktori saat ini:
[root@ivan test_dir_srv]# ls -l
total 0
-rw-r--r-- 1 root root 0 Aug 25 11:23 test_file
[root@ivan test_dir_srv]# python3 -m http.server --bind 127.0.0.1 8000
Serving HTTP on 127.0.0.1 port 8000 (http://127.0.0.1:8000/) ...
Nginx dikonfigurasi sebagai berikut:
upstream test {
server 127.0.0.1:8000;
}
server {
listen 80;
location / {
proxy_pass http://test;
}
}
Vanya perlu menguji satu kasus uji: untuk memeriksa bahwa permintaan / berfungsi. Dia memeriksa dan semuanya bekerja:
MacBook-Pro-Ivan:~ ivantester$ curl http://12.34.56.78
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Directory listing for /</title>
</head>
<body>
<h1>Directory listing for /</h1>
<hr>
<ul>
<li><a href="test_file">test_file</a></li>
</ul>
<hr>
</body>
</html>
Tetapi kemudian pada satu titik di bangku tes, pengembang memperbarui sesuatu, dan Vanya menerima kesalahan:
MacBook-Pro-Ivan:~ ivantester$ curl http://12.34.56.78
<html>
<head><title>502 Bad Gateway</title></head>
<body bgcolor="white">
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.14.2</center>
</body>
</html>
Dia memutuskan untuk tidak membuang kesalahan yang tidak dapat dipahami ini kepada pengembang, tetapi untuk mendapatkan akses ssh ke server dan mencari tahu apa yang terjadi di sana. Dia memiliki sedikit pengetahuan di bidang debugging masalah semacam ini, tetapi dia benar-benar ingin belajar, jadi dia mempersenjatai dirinya dengan mesin pencari, logika dan pergi untuk melokalkan bug.
Pikiran pertama Vanya: log
Memang jika terjadi error, maka anda tinggal mencarinya di file log. Tetapi pertama-tama Anda perlu mencari file log itu sendiri. Vanya pergi ke Google dan menemukan bahwa sering kali log ada di direktori / var / log . Memang, direktori nginx ditemukan di sana:
[root@ivan ~]# ls /var/log/nginx/
access.log access.log-20200831 error.log error.log-20200831
Ivan melihat baris terakhir dari log kesalahan dan memahami apa yang salah: pengembang membuat kesalahan dalam konfigurasi nginx, kesalahan ketik merayap ke port hulu.
[root@ivan ~]# tail /var/log/nginx/error.log
2020/08/31 04:36:21 [error] 15050#15050: *90452 connect() failed (111: Connection refused) while connecting to upstream, client: 31.170.95.221, server: , request: "GET / HTTP/1.0", upstream: "http://127.0.0.1:8009/", host: "12.34.56.78"
Kesimpulan apa yang bisa ditarik dari ini? Log adalah teman terbaik penguji dan pengembang saat melokalkan bug. Jika ada beberapa perilaku layanan yang tidak diharapkan, tetapi tidak ada apa-apa di log, maka ini adalah alasan untuk mengembalikan tugas ke pengembangan dengan permintaan untuk menambahkan log. Lagi pula, jika nginx tidak menulis ke log tentang upaya yang gagal untuk menjangkau upstream, maka, Anda tahu, akan lebih sulit untuk mencari masalah?
Pada saat itu, Vanya berpikir: “Bagaimana jika log nginx berada di direktori yang berbeda? Bagaimana saya menemukan mereka? " Dalam beberapa tahun, Vanya akan memiliki lebih banyak pengalaman dengan layanan di Linux, dan dia akan tahu bahwa jalur ke file log sering kali diteruskan ke layanan sebagai argumen baris perintah, atau terdapat dalam file konfigurasi, jalur yang juga sering diteruskan ke layanan sebagai argumen baris perintah. Idealnya, jalur ke file log harus ditulis dalam dokumentasi layanan.
Omong-omong, melalui file konfigurasi Anda dapat menemukan jalur ke file log di nginx:
[root@ivan ~]# ps ax | grep nginx | grep master
root 19899 0.0 0.0 57392 2872 ? Ss 2019 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
[root@ivan ~]# grep "log" /etc/nginx/nginx.conf
error_log /var/log/nginx/error.log warn;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
access_log /var/log/nginx/access.log main;
Bagaimana jika tidak ada apa pun di log?
Di waktu luangnya, Vanya memutuskan untuk memikirkan bagaimana dia akan mengatasi tugas tersebut jika nginx tidak menulis apapun ke log. Vanya tahu bahwa layanan sedang mendengarkan pada porta 8000, jadi dia memutuskan untuk melihat lalu lintas di porta ini di server. Utilitas tcpdump membantunya dalam hal ini . Dengan konfigurasi yang benar, ia melihat permintaan dan tanggapan:
Buang lalu lintas di porta 8000
[root@ivan ~]# tcpdump -nn -i lo -A port 8000
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
09:10:42.114284 IP 127.0.0.1.33296 > 127.0.0.1.8000: Flags [S], seq 3390176024, win 43690, options [mss 65495,sackOK,TS val 830366494 ecr 0,nop,wscale 8], length 0
E..<..@.@..............@.............0.........
1~c.........
09:10:42.114293 IP 127.0.0.1.8000 > 127.0.0.1.33296: Flags [S.], seq 4147196208, ack 3390176025, win 43690, options [mss 65495,sackOK,TS val 830366494 ecr 830366494,nop,wscale 8], length 0
E..<..@.@.<..........@...110.........0.........
1~c.1~c.....
09:10:42.114302 IP 127.0.0.1.33296 > 127.0.0.1.8000: Flags [.], ack 1, win 171, options [nop,nop,TS val 830366494 ecr 830366494], length 0
E..4..@.@..............@.....111.....(.....
1~c.1~c.
09:10:42.114329 IP 127.0.0.1.33296 > 127.0.0.1.8000: Flags [P.], seq 1:88, ack 1, win 171, options [nop,nop,TS val 830366494 ecr 830366494], length 87
E.....@.@..b...........@.....111...........
1~c.1~c.GET / HTTP/1.0
Host: test
Connection: close
User-Agent: curl/7.64.1
Accept: */*
09:10:42.114333 IP 127.0.0.1.8000 > 127.0.0.1.33296: Flags [.], ack 88, win 171, options [nop,nop,TS val 830366494 ecr 830366494], length 0
E..4R/@.@............@...111...p.....(.....
1~c.1~c.
09:10:42.115062 IP 127.0.0.1.8000 > 127.0.0.1.33296: Flags [P.], seq 1:155, ack 88, win 171, options [nop,nop,TS val 830366494 ecr 830366494], length 154
E...R0@.@............@...111...p...........
1~c.1~c.HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.7.2
Date: Mon, 07 Sep 2020 13:10:42 GMT
Content-type: text/html; charset=utf-8
Content-Length: 340
09:10:42.115072 IP 127.0.0.1.33296 > 127.0.0.1.8000: Flags [.], ack 155, win 175, options [nop,nop,TS val 830366494 ecr 830366494], length 0
E..4.@.@..............@...p.11......(.....
1~c.1~c.
09:10:42.115094 IP 127.0.0.1.8000 > 127.0.0.1.33296: Flags [P.], seq 155:495, ack 88, win 171, options [nop,nop,TS val 830366494 ecr 830366494], length 340
E...R1@.@..<.........@...11....p.....|.....
1~c.1~c.<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Directory listing for /</title>
</head>
<body>
<h1>Directory listing for /</h1>
<hr>
<ul>
<li><a href="test_file">test_file</a></li>
</ul>
<hr>
</body>
</html>
09:10:42.115098 IP 127.0.0.1.33296 > 127.0.0.1.8000: Flags [.], ack 495, win 180, options [nop,nop,TS val 830366494 ecr 830366494], length 0
E..4.
@.@..............@...p.13......(.....
1~c.1~c.
09:10:42.115128 IP 127.0.0.1.8000 > 127.0.0.1.33296: Flags [F.], seq 495, ack 88, win 171, options [nop,nop,TS val 830366494 ecr 830366494], length 0
E..4R2@.@............@...13....p.....(.....
1~c.1~c.
09:10:42.115264 IP 127.0.0.1.33296 > 127.0.0.1.8000: Flags [F.], seq 88, ack 496, win 180, options [nop,nop,TS val 830366495 ecr 830366494], length 0
E..4..@.@..............@...p.13 .....(.....
1~c.1~c.
09:10:42.115271 IP 127.0.0.1.8000 > 127.0.0.1.33296: Flags [.], ack 89, win 171, options [nop,nop,TS val 830366495 ecr 830366495], length 0
E..4R3@.@............@...13 ...q.....(.....
1~c.1~c.
^C
12 packets captured
24 packets received by filter
0 packets dropped by kernel
Dengan konfigurasi yang salah (dengan port 8009 di nginx upstream), tidak ada lalu lintas di port 8000. Vanya sangat senang: sekarang meskipun pengembang lupa menulis ke log jika terjadi kesalahan jaringan, Anda masih dapat setidaknya mengetahui apakah lalu lintas menuju ke host atau port yang diinginkan.
Kesimpulan apa yang bisa ditarik dari cerita ini? Meskipun tidak ada log, Linux memiliki utilitas yang dapat membantu mengatasi masalah lokalisasi.
Dan jika bukan jaringan?
Semuanya bekerja dengan baik, tetapi suatu hari Vanya mendapat kesalahan lain, kali ini berbeda:
MacBook-Pro-Ivan:~ ivantester$ curl http://12.34.56.78
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Error response</title>
</head>
<body>
<h1>Error response</h1>
<p>Error code: 404</p>
<p>Message: File not found.</p>
<p>Error code explanation: HTTPStatus.NOT_FOUND - Nothing matches the given URI.</p>
</body>
</html>
Vanya pergi ke server lagi, tetapi kali ini masalahnya tidak terkait dengan jaringan. Log layanan juga mengatakan File tidak ditemukan , dan Vanya memutuskan untuk mencari tahu mengapa kesalahan seperti itu tiba-tiba muncul. Dia tahu bahwa ada proses python3 -m http.server , tetapi dia tidak tahu konten direktori mana yang ditampilkan layanan ini (atau, dengan kata lain, yang merupakan direktori kerja saat ini dari proses ini). Dia menemukan dengan perintah lsof :
[root@ivan ~]# ps aux | grep python | grep "http.server"
root 20638 0.0 0.3 270144 13552 pts/2 S+ 08:29 0:00 python3 -m http.server
[root@ivan ~]# lsof -p 20638 | grep cwd
python3 20638 root cwd DIR 253,1 4096 1843551 /root/test_dir_srv2
Ini juga dapat dilakukan dengan menggunakan perintah pwdx atau menggunakan direktori proc :
[root@ivan ~]# pwdx 20638 20638: /root/test_dir_srv2 [root@ivan ~]# ls -l /proc/20638/cwd lrwxrwxrwx 1 root root 0 Aug 31 08:37 /proc/20638/cwd -> /root/test_dir_srv2
Direktori semacam itu benar-benar ada di server, dan berisi file bernama test_file . Apa masalahnya? Ivan mencari di Google dan menemukan utilitas strace , yang dengannya Anda dapat melihat sistem apa yang memanggil suatu proses ( ngomong - ngomong, ada artikel bagus tentang strace di Habré, dan bahkan tidak satu pun ). Anda dapat memulai proses baru melalui strace , atau menghubungkan dengan utilitas ini ke proses yang sudah berjalan. Opsi kedua cocok untuk Vanya:
Keluaran strace
[root@ivan ~]# strace -ff -p 20638
strace: Process 20638 attached
restart_syscall(<... resuming interrupted poll ...>) = 0
poll([{fd=4, events=POLLIN}], 1, 500) = 0 (Timeout)
poll([{fd=4, events=POLLIN}], 1, 500) = 0 (Timeout)
poll([{fd=4, events=POLLIN}], 1, 500) = 0 (Timeout)
poll([{fd=4, events=POLLIN}], 1, 500) = 0 (Timeout)
poll([{fd=4, events=POLLIN}], 1, 500) = 0 (Timeout)
poll([{fd=4, events=POLLIN}], 1, 500) = 1 ([{fd=4, revents=POLLIN}])
accept4(4, {sa_family=AF_INET, sin_port=htons(57530), sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_CLOEXEC) = 5
clone(child_stack=0x7f2beeb28fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f2beeb299d0, tls=0x7f2beeb29700, child_tidptr=0x7f2beeb299d0) = 21062
futex(0x11204d0, FUTEX_WAIT_PRIVATE, 0, NULLstrace: Process 21062 attached
<unfinished ...>
[pid 21062] set_robust_list(0x7f2beeb299e0, 24) = 0
[pid 21062] futex(0x11204d0, FUTEX_WAKE_PRIVATE, 1) = 1
[pid 20638] <... futex resumed> ) = 0
[pid 20638] futex(0x921c9c, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 27, {1598879772, 978949000}, ffffffff <unfinished ...>
[pid 21062] futex(0x921c9c, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x921c98, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
[pid 20638] <... futex resumed> ) = 0
[pid 20638] futex(0x921cc8, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 21062] futex(0x921cc8, FUTEX_WAKE_PRIVATE, 1) = 1
[pid 20638] <... futex resumed> ) = 0
[pid 20638] futex(0x921cc8, FUTEX_WAKE_PRIVATE, 1) = 0
[pid 20638] poll([{fd=4, events=POLLIN}], 1, 500 <unfinished ...>
[pid 21062] recvfrom(5, "GET / HTTP/1.1\r\nConnection: upgr"..., 8192, 0, NULL, NULL) = 153
[pid 21062] stat("/root/test_dir_srv/", 0x7f2beeb27350) = -1 ENOENT (No such file or directory)
[pid 21062] open("/root/test_dir_srv/", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 21062] write(2, "127.0.0.1 - - [31/Aug/2020 09:16"..., 70) = 70
[pid 21062] write(2, "127.0.0.1 - - [31/Aug/2020 09:16"..., 60) = 60
[pid 21062] sendto(5, "HTTP/1.0 404 File not found\r\nSer"..., 184, 0, NULL, 0) = 184
[pid 21062] sendto(5, "<!DOCTYPE HTML PUBLIC \"-//W3C//D"..., 469, 0, NULL, 0) = 469
[pid 21062] shutdown(5, SHUT_WR) = 0
[pid 21062] close(5) = 0
[pid 21062] madvise(0x7f2bee329000, 8368128, MADV_DONTNEED) = 0
[pid 21062] exit(0) = ?
[pid 21062] +++ exited with 0 +++
<... poll resumed> ) = 0 (Timeout)
poll([{fd=4, events=POLLIN}], 1, 500) = 0 (Timeout)
poll([{fd=4, events=POLLIN}], 1, 500) = 0 (Timeout)
poll([{fd=4, events=POLLIN}], 1, 500^Cstrace: Process 20638 detached
<detached ...>
Biasanya keluaran strace cukup banyak (dan mungkin sangat besar), jadi akan lebih mudah untuk langsung mengarahkannya ke file dan kemudian mencari system call yang diperlukan di dalamnya. Dalam kasus ini, Anda dapat segera mengetahui bahwa layanan mencoba membuka direktori / root / test_dir_srv / - seseorang mengganti namanya dan tidak memulai ulang layanan setelah itu, sehingga mengembalikan 404.
Jika Anda segera memahami panggilan sistem mana yang perlu Anda lihat, Anda dapat menggunakan opsi -e :
[root@ivan ~]# strace -ff -e trace=open,stat -p 20638
strace: Process 20638 attached
strace: Process 21396 attached
[pid 21396] stat("/root/test_dir_srv/", 0x7f2beeb27350) = -1 ENOENT (No such file or directory)
[pid 21396] open("/root/test_dir_srv/", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid 21396] +++ exited with 0 +++
^Cstrace: Process 20638 detached
: « » , strace. , , (, / ), . ltrace.
- ?
Vanya tidak berhenti sampai disitu dan menemukan bahwa ada GNU Project Debugger - GDB . Dengan bantuannya, Anda dapat " memasuki" proses dan bahkan sedikit memodifikasinya. Dan Vanya memutuskan untuk mencoba menemukan kesalahan terakhir menggunakan GDB . Dia menyarankan bahwa karena layanan menampilkan isi direktori, maka Anda dapat mencoba meletakkan breakpoint pada fungsi open () dan melihat apa yang terjadi:
Keluaran utilitas Gdb
[root@ivan ~]# gdb -p 23998
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-119.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Attaching to process 23998
…
… < debugging symbols...>
...
0x00007f2284c0b20d in poll () at ../sysdeps/unix/syscall-template.S:81
81 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
Missing separate debuginfos, use: debuginfo-install keyutils-libs-1.5.8-3.el7.x86_64 krb5-libs-1.15.1-34.el7.x86_64 libcom_err-1.42.9-13.el7.x86_64 libgcc-4.8.5-36.el7.x86_64 libselinux-2.5-14.1.el7.x86_64 openssl-libs-1.0.2k-16.el7.x86_64 pcre-8.32-17.el7.x86_64 zlib-1.2.7-18.el7.x86_64
(gdb) set follow-fork-mode child
(gdb) b open
Breakpoint 1 at 0x7f2284c06d20: open. (2 locations)
(gdb) c
Continuing.
[New Thread 0x7f227a165700 (LWP 24030)]
[Switching to Thread 0x7f227a165700 (LWP 24030)]
Breakpoint 1, open64 () at ../sysdeps/unix/syscall-template.S:81
81 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb) n
83 T_PSEUDO_END (SYSCALL_SYMBOL)
(gdb) n
_io_FileIO___init___impl (opener=<optimized out>, closefd=<optimized out>, mode=<optimized out>, nameobj=0x7f227a68f6f0, self=0x7f227a68f6c0) at ./Modules/_io/fileio.c:381
381 Py_END_ALLOW_THREADS
(gdb) n
379 self->fd = open(name, flags, 0666);
(gdb) n
381 Py_END_ALLOW_THREADS
(gdb) print name
$1 = 0x7f227a687c90 "/root/test_dir_srv/"
(gdb) q
A debugging session is active.
Inferior 1 [process 23998] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/local/bin/python3.7, process 23998
[Inferior 1 (process 23998) detached]
Setelah perintah c ( lanjutkan ) , Vanya meluncurkan curl di konsol lain , menekan breakpoint di debugger dan mulai menjalankan program ini (yaitu, layanan) selangkah demi selangkah. Segera setelah dia menemukan open di beberapa nama path , dia mencetak nilai variabel ini dan melihat " / root / test_dir_srv / ".
GDB adalah alat yang ampuh, dan inilah kasus penggunaan yang paling sederhana. Terkadang ini dapat membantu mereproduksi kasus yang rumit (misalnya, Anda dapat menjeda proses pada waktu yang tepat dan mereproduksi kondisi balapan), ini juga membantu membaca file dump inti.
Bagaimana jika Docker?
Pada satu titik, DevOps memutuskan bahwa layanan tersebut sekarang akan digunakan dengan kontainer Docker, dan semua kasus yang ditemukan Vanya perlu diuji ulang. Vanya mencari di Google berikut ini tanpa masalah:
- Anda dapat menggunakan tcpdump , strace dan gdb di dalam container, tetapi Anda perlu mengingat kapabilitas Linux (ada artikel yang menjelaskan mengapa strace tidak berfungsi dalam container tanpa --cap-add = SYS_PTRACE ).
- Opsi --pid dapat digunakan .
Namun dia bertanya-tanya apakah mungkin untuk melihat semua lalu lintas yang menuju ke container (atau dari container) langsung dari host. Dalam tcpdump memiliki kemungkinan untuk menampilkan antarmuka lalu lintas apa pun (opsi -i ), setiap wadah sesuai dengan satu antarmuka virtual Veth (ini dapat dilihat, misalnya, melalui ifconfig atau ip a ), tetapi bagaimana Anda tahu wadah apa yang sesuai dengan antarmuka? Jika container tidak menggunakan jaringan host , maka di dalamnya akan ada antarmuka jaringan eth0 , yang dapat digunakan untuk berkomunikasi melalui jaringan dengan container dan host lain. Yang tersisa hanyalah menemukan ifindex yang antarmuka pada host cocok dengan antarmuka iflinketh0 dari container (Anda dapat membaca artinya di sini ).
[root@ivan ~]# for f in `ls /sys/class/net/veth*/ifindex`; do echo $f; cat $f; done | grep -B 1 `docker exec test_service_container cat /sys/class/net/eth0/iflink` | head -1
/sys/class/net/veth6c18dba/ifindex
Sekarang Anda dapat menjalankan tcpdump di antarmuka veth6c18dba :
tcpdump -i veth6c18dba
Tetapi ada cara yang lebih mudah: Anda dapat menemukan alamat IP penampung di jaringannya dan mendengarkan lalu lintas di dalamnya:
[root@ivan ~]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' test_service_container
172.17.0.10
[root@ivan ~]# tcpdump -i any host 172.17.0.10
Kesimpulan: debugging dalam container Docker bukanlah masalah besar. Utilitas bekerja di dalamnya, dan Anda dapat menggunakan log buruh pelabuhan untuk membaca log .
kesimpulan
Sebagai insinyur yang bertanggung jawab, Vanya memutuskan untuk menguraikan secara singkat informasi baru untuk dirinya sendiri dalam basis pengetahuan internal. Inilah yang dia tulis:
- Log adalah sahabat manusia. Jika perilaku tak terduga dari layanan ditemui dan pada saat yang sama tidak menulis apa pun ke log, ini adalah alasan untuk meminta pengembang menambahkan log.
- , , . , Linux , .
- tcpdump. , .
- «» strace, ltrace gdb.
- , Docker-.
- /proc/PID. , /proc/PID/fd .
- Utilitas ps , ls , stat , lsof , ss , du , top , free , ip , ldconfig , ldd dan lainnya juga dapat membantu mendapatkan berbagai informasi tentang sistem, file atau proses .
Saya harap cerita ini bermanfaat bagi Anda, dan setidaknya sekali ini akan membantu Anda memahami apa yang terjadi saat Anda men-debug sesuatu di Linux. Jika Vanya melewatkan sesuatu, bagikan di komentar!