Request ID untuk Nginx dan PHP - Ikuti Satu Request Melalui Log
Sebuah request PHP gagal, tetapi petunjuk yang terlihat tersebar di beberapa tempat. Nginx mencatat status dan durasi dalam satu file. PHP mencatat exception di tempat lain. Beberapa request mungkin mencapai route yang sama dalam detik yang sama. Event aplikasi mana yang terkait dengan baris access log yang sedang diperiksa?
Request ID menawarkan jawaban yang sengaja dibuat sederhana: buat satu identifier opaque di batas web server, teruskan ke PHP, lalu sertakan dalam setiap catatan yang relevan untuk request tersebut. Nilai ini tidak menjelaskan penyebab kegagalan dengan sendirinya. Ia membuat bukti yang ada lebih mudah dihubungkan.
Artikel ini menyusun pola terbatas tersebut untuk Nginx dan PHP-FPM. Contohnya tidak menganggap header dari client sebagai sumber tepercaya, tidak memasukkan data personal ke dalam identifier, dan tidak menyebut satu ID sebagai “distributed tracing.”
Masalahnya Adalah Korelasi, Bukan Kekurangan Log
Log web server dan aplikasi menjawab pertanyaan yang berbeda. Access log Nginx dapat menunjukkan kapan sebuah request selesai, status HTTP-nya, dan berapa lama pemrosesannya. Kode aplikasi mengetahui operasi mana yang gagal dan alasannya. Menurut OWASP Logging Cheat Sheet, application logging menambahkan konteks yang sering tidak tersedia dalam infrastructure logging saja.
Waktu, path, dan alamat client dapat membantu mencocokkan keduanya, tetapi ketiganya merupakan join key yang lemah. Request yang berjalan bersamaan bisa memiliki nilai-nilai tersebut secara identik. Request ID menyediakan penghubung yang lebih langsung:
Nginx access log:
request_id=91f... status=500 request_time=0.184
PHP application log:
request_id=91f... event=profile_update_failed
Sifat yang berguna di sini adalah konsistensi. Nilai yang sama muncul di setiap titik pengamatan untuk satu request. ID tersebut sebaiknya tetap menjadi identifier, bukan berubah menjadi wadah untuk username, alamat email, alamat IP, timestamp, atau deskripsi error.
Berikan Satu Sumber Tepercaya untuk ID
Nginx menyediakan variable bawaan $request_id. Dokumentasi core module menjelaskan nilainya sebagai 16 random bytes yang direpresentasikan dalam bentuk hexadecimal. Ini memberikan nilai buatan server yang praktis untuk stack kecil sebelum PHP menangani request.
Batas kepercayaan penting di sini. Client publik dapat mengirim header bernama X-Request-ID, tetapi menerimanya tanpa perubahan memungkinkan nilai berulang, menyesatkan, atau malformed masuk ke log. Ada arsitektur yang sah ketika reverse proxy tepercaya meneruskan correlation atau trace context yang sudah ada. Arsitektur seperti itu membutuhkan trust policy yang eksplisit. Baseline yang lebih sederhana di sini berbeda: Nginx membuat ID lokal yang authoritative dan meneruskannya ke PHP melalui FastCGI parameter khusus.
Kontrak yang dihasilkan cukup singkat:
- Nginx membuat nilainya.
- Nginx menuliskannya ke access log.
- Nginx meneruskan nilai yang sama ke PHP-FPM.
- Application log menyertakannya tanpa mengubah nilainya.
- Nilai tersebut tidak pernah dipakai untuk authentication, authorization, atau idempotency.
Masukkan Request ID ke Access Log Nginx
Nginx log module memungkinkan sebuah log_format bernama memuat variable. Modul tersebut juga mendukung escape=json, yang melakukan escape terhadap karakter yang tidak boleh tampil tanpa escape di dalam string JSON.
Format ringkas dapat dideklarasikan dalam context http:
log_format correlated escape=json
'{"time":"$time_iso8601",'
'"request_id":"$request_id",'
'"method":"$request_method",'
'"uri":"$uri",'
'"status":$status,'
'"request_time":$request_time}';
access_log /var/log/nginx/app-access.log correlated;
Format ini sengaja tidak mencatat query string. Query parameter kadang memuat token, kata pencarian, alamat email, atau data lain yang tidak semestinya masuk ke log rutin. Menghilangkannya bukan privacy policy yang lengkap, tetapi langkah tersebut merupakan default data minimization yang berguna. URI dan metadata lain masih dapat bersifat sensitif, sehingga akses dan retention log tetap membutuhkan keputusan tersendiri.
JSON escaping juga bukan lapisan keamanan ajaib. Ia melindungi struktur format output ini, sementara OWASP secara terpisah menyarankan sanitization untuk event data dari trust zone lain dan mengecualikan secret serta identifier sensitif. Request ID tidak dapat menutupi praktik mencatat password atau access token ke log.
Teruskan Nilai Buatan Server ke PHP
Di dalam location PHP, teruskan nilainya sebagai FastCGI parameter yang eksplisit:
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param REQUEST_ID $request_id;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
Path socket tersebut hanya placeholder: instalasi Debian umumnya menyertakan versi PHP dalam nama file itu, sedangkan sistem lain mungkin memakai TCP atau path berbeda. Nilainya harus sesuai dengan PHP-FPM pool yang benar-benar digunakan. Baris terpenting adalah fastcgi_param REQUEST_ID $request_id;. Dokumentasi FastCGI module menyatakan bahwa directive tersebut dapat meneruskan parameter dengan nilai yang memuat variable Nginx.
PHP biasanya menyediakan nilai dari server dan execution environment melalui $_SERVER, walaupun manual PHP mengingatkan bahwa entry yang tersedia bergantung pada web server. Dengan konfigurasi Nginx di atas, kode bootstrap aplikasi dapat mengambil nilai tersebut satu kali:
<?php
$requestId = $_SERVER['REQUEST_ID'] ?? 'missing';
error_log(sprintf(
'[request_id=%s] event=profile_update_failed',
$requestId
));
Manual error_log() menjelaskan bahwa destination bergantung pada konfigurasi PHP dan message type yang dipilih. Aplikasi nyata mungkin sudah memiliki logger dengan structured context. Jika demikian, tambahkan request_id ke context itu daripada menyebarkan pemanggilan langsung error_log() ke seluruh business code.
Nilai fallback tersebut bersifat diagnostik, bukan ID pengganti. Kemunculan missing memberi tahu operator bahwa request tidak melewati konfigurasi yang diharapkan atau aplikasi dijalankan melalui SAPI lain, misalnya CLI. Membuat ID kedua yang tidak berhubungan di PHP justru menyembunyikan celah konfigurasi tersebut dan memutus korelasi dengan Nginx.
Mengembalikan ID Dapat Membantu Proses Support
Jika pembaca atau API client perlu melaporkan suatu identifier, Nginx dapat mengembalikan nilai yang sama dalam response header:
add_header X-Request-ID $request_id always;
Dokumentasi Nginx headers module menyatakan bahwa add_header menerima variable, sedangkan always menambahkan field tersebut tanpa bergantung pada status response. Hal ini berguna ketika response yang perlu diperiksa justru berupa error.
X-Request-ID adalah konvensi lokal dalam contoh ini, bukan security header standar. Mengembalikannya bersifat opsional. Jika nilai tersebut diekspos, support tool perlu memperlakukannya sebagai search key, bukan bukti bahwa sebuah laporan autentik. Siapa pun yang menerima response dapat mengetahui ID-nya, dan nilai tersebut tidak boleh membuka akses ke data atau tindakan tertentu.
Verifikasi Seluruh Jalur, Bukan Hanya Syntax
Rollout yang hati-hati memiliki dua tingkat. Pertama, validasi konfigurasi Nginx dengan command dan prosedur service yang sesuai untuk sistem tersebut sebelum melakukan reload. Path socket hasil salin-tempel atau directive dalam context yang salah sebaiknya gagal pada tahap ini, bukan saat terjadi insiden.
Kedua, kirim satu controlled request ke test route yang aman lalu bandingkan tiga tempat:
- Response header, jika diaktifkan.
- Entry pada access log Nginx.
- Event application log yang sengaja dibuat dari request yang sama.
Ketiganya harus memuat nilai yang sama. Setelah itu, uji application error path yang aman untuk dipicu. Terakhir, uji apa yang terjadi ketika logging destination tidak tersedia atau penuh. OWASP secara eksplisit menyarankan pemeriksaan terhadap kegagalan logging, permission, ketahanan terhadap injection, dan resource exhaustion. Korelasi tidak dapat diandalkan jika salah satu sisi diam-diam berhenti mencatat.
Pemeriksaan ini tidak perlu mencetak secret atau membuang seluruh request body ke log hanya untuk membuktikan bahwa logging bekerja. Event name yang tetap dan request ID sudah cukup untuk correlation test.
Pahami Hal yang Tidak Disediakan Pola Ini
Pola ini tidak otomatis menaruh ID di mana-mana
Konfigurasi tersebut menghubungkan access log Nginx dengan event PHP yang secara eksplisit menyertakan REQUEST_ID. Ia tidak otomatis menambahkan nilai itu ke setiap error message Nginx, warning PHP, database query, queue job, atau outbound HTTP request. Setiap batas tambahan membutuhkan penanganan context yang disengaja.
Pola ini bukan distributed tracing
W3C Trace Context Recommendation mendefinisikan traceparent dan tracestate untuk meneruskan hubungan trace melintasi berbagai komponen. Nilai traceparent memuat trace ID, parent ID, flags, dan version. Model tersebut dapat merepresentasikan rantai operasi dan hubungan parent-child. Satu request ID Nginx yang disalin ke PHP tidak dapat melakukannya.
Untuk monolith kecil, keterbatasan itu mungkin dapat diterima. Jika satu tindakan di browser menyebar ke beberapa service, queue, dan background worker, mengadopsi tracing system standar biasanya lebih koheren daripada menciptakan semakin banyak makna untuk X-Request-ID. ID lokal masih dapat berguna, tetapi perannya harus tetap eksplisit.
Pola ini tidak membuat log otomatis tepercaya atau aman
Sebuah identifier membantu menghubungkan catatan; ia tidak membuktikan bahwa setiap catatan lengkap, tidak diubah, atau memiliki atribusi yang benar. Log membutuhkan akses terbatas, rotation, aturan retention, monitoring, dan perlindungan dari perubahan. Isinya juga perlu disiplin. OWASP menyarankan agar password, access token, session identifier, connection string, encryption key, dan data personal sensitif tidak dicatat secara langsung.
Ada pula tradeoff privasi yang lebih tenang: korelasi berguna justru karena ia menghubungkan berbagai event. Pertahankan identifier dalam bentuk opaque, jangan menurunkannya dari informasi pengguna, dan simpan catatan yang saling terhubung hanya selama tujuan operasional atau keamanannya masih memerlukan.
Penghubung Kecil Antara Dua Sudut Pandang yang Berguna
Request ID bekerja paling baik ketika tetap membosankan. Nginx membuat nilai opaque, mencatatnya bersama metadata request, lalu meneruskannya ke PHP. Aplikasi menambahkan nilai itu ke event yang bermakna. Operator kemudian dapat berpindah dari “ada error 500 sekitar waktu ini” menjadi “catatan-catatan ini menjelaskan request yang sama.”
Ini adalah peningkatan sederhana, bukan observability platform. Pola ini tidak menggantikan event design yang cermat, safe logging, monitoring, atau distributed tracing ketika sistem tumbuh melintasi batas proses. Namun, untuk aplikasi Nginx dan PHP berukuran kecil, satu identifier tepercaya dapat mengubah dua log terpisah menjadi percakapan yang jauh lebih berguna.
