Akar Masalah: Schema Drift antara Nginx dan GoAccess
Perubahan direktif log_format pada konfigurasi Nginx sering dilakukan saat tim backend atau SRE membutuhkan metrik baru, seperti $request_time, upstream response header, atau tracing ID. Namun, perubahan ini jarang diuji bersama konfigurasi parser telemetri seperti GoAccess.
GoAccess mengandalkan direktif log-format statis yang memetakan token log baris demi baris menggunakan penanda posisi (seperti %h, %r, %s, atau %^). Jika posisi token bergeser atau format timestamp berubah tanpa sinkronisasi konfigurasi parser, GoAccess akan gagal memproses baris log baru. Hasilnya terjadi schema drift: parser secara diam-diam membuang rekaman data log (data loss), metrik trafik rontok, dan visualisasi analisis menjadi korup di lingkungan produksi.
Sinkronisasi Konfigurasi: Nginx vs GoAccess
Agar parsing akurat, setiap token pada Nginx wajib dipetakan secara simetris ke dalam format GoAccess. Perhatikan contoh format log custom berikut yang menambahkan response time server:
Konfigurasi Nginx (nginx.conf)
log_format custom_telemetry '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time';
access_log /var/log/nginx/access.log custom_telemetry;
Konfigurasi GoAccess (goaccess.conf)
time-format %T
date-format %d/%b/%Y
log-format %h %^ %^ [%d:%t %^] "%r" %s %b "%R" "%u" %T
Penjelasan pemetaan token:
%h: IP klien ($remote_addr).%^: Mengabaikan field yang tidak diperlukan (-dan$remote_user).%d:%t: Tanggal dan jam yang diekstrak dari format$time_localNginx."%r": Request line (method, URI, protokol).%s: Status kode HTTP ($status).%b: Ukuran byte respon ($body_bytes_sent)."%R": Referrer header ($http_referer)."%u": User agent header ($http_user_agent).%T: Response time dalam detik dengan resolusi milidetik ($request_time).
Test Harness: Menghasilkan Log Uji Sintetis di CI
Pola lazim pengujian format log adalah menggunakan unit test dummy, tetapi cara tersebut rentan melewatkan kasus riil (misal: encoding URL oleh Nginx atau perlakuan string kosong). Solusi paling deterministik: jalankan container Nginx resmi di runner CI, terapkan konfigurasi repositori, lalu kirim request sintetis menggunakan curl.
Berikut skrip harness sederhana untuk memicu berbagai skenario HTTP request:
#!/usr/bin/env bash
set -euo pipefail
NGINX_HOST="http://127.0.0.1:8080"
# 1. Request standar GET 200
curl -s -o /dev/null -A "Mozilla/5.0 SyntheticTest" "${NGINX_HOST}/healthz"
# 2. Request POST dengan payload
curl -s -o /dev/null -X POST -d '{"event":"ping"}' -H "Content-Type: application/json" "${NGINX_HOST}/api/v1/event"
# 3. Request 404 Not Found dengan referer
curl -s -o /dev/null -e "https://ref.example.com" "${NGINX_HOST}/non-existent-route"
# 4. Request dengan query string kompleks dan URL encoding
curl -s -o /dev/null "${NGINX_HOST}/search?q=nginx+ci&page=1"
# Pastikan buffer log Nginx telah ditulis ke disk
sync
Automated Validation dan Assertion Gate
GoAccess dapat dijalankan secara headless (tanpa antarmuka TUI) untuk memvalidasi log. Parameter penting yang harus digunakan adalah --invalid-requests-log dan opsi output JSON.
Gunakan script assert berikut sebagai failure-gate di pipeline CI:
#!/usr/bin/env bash
set -euo pipefail
LOG_PATH="/var/log/nginx/access.log"
CONF_PATH="./goaccess.conf"
INVALID_LOG="/tmp/goaccess_invalid.log"
REPORT_JSON="/tmp/goaccess_report.json"
echo "Menjalankan GoAccess validation..."
# Jalankan GoAccess dalam mode parsing JSON
goaccess "${LOG_PATH}" \
--config-file="${CONF_PATH}" \
--invalid-requests-log="${INVALID_LOG}" \
--no-progress \
-o "${REPORT_JSON}"
# Ekstrak data kegagalan parsing
FAILED_REQUESTS=$(jq '.general.failed' "${REPORT_JSON}")
VALID_REQUESTS=$(jq '.general.valid' "${REPORT_JSON}")
echo "Valid records parsed: ${VALID_REQUESTS}"
echo "Failed records: ${FAILED_REQUESTS}"
if [ "${FAILED_REQUESTS}" -gt 0 ]; then
echo "[ERROR] Regresi parser terdeteksi! Terdapat baris log yang tidak cocok dengan skema GoAccess."
echo "Daftar log yang gagal diparsing:"
cat "${INVALID_LOG}"
exit 1
fi
if [ "${VALID_REQUESTS}" -eq 0 ]; then
echo "[ERROR] Tidak ada record log yang berhasil diparsing. Periksa apakah test harness berjalan."
exit 1
fi
echo "[SUCCESS] Seluruh format log Nginx kompatibel dengan konfigurasi GoAccess."
Integrasi pada GitHub Actions Pipeline
Satukan test harness dan script assertion ke dalam satu workflow GitHub Actions:
name: Verify Nginx Log Schema
on:
pull_request:
paths:
- 'nginx/**'
- 'telemetry/goaccess.conf'
jobs:
validate-log-format:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Install Tools
run: |
sudo apt-get update
sudo apt-get install -y goaccess jq curl
- name: Start Nginx Container
run: |
docker run -d --name test-nginx \
-p 8080:80 \
-v $(pwd)/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
-v $(pwd)/logs:/var/log/nginx \
nginx:alpine
sleep 2
- name: Generate Synthetic Traffic
run: |
chmod +x ./scripts/generate_traffic.sh
./scripts/generate_traffic.sh
- name: Assert Log Compatibility
run: |
# Beri hak akses baca ke direktori log yang dimount
sudo chmod -R 755 ./logs
chmod +x ./scripts/validate_goaccess.sh
LOG_PATH="./logs/access.log" CONF_PATH="./telemetry/goaccess.conf" ./scripts/validate_goaccess.sh
Strategi Menjaga Backward-Compatibility
Saat memperbarui log Nginx di sistem skala besar, pertahankan kompatibilitas parser menggunakan prinsip berikut:
- Append-Only Fields: Bila menggunakan log berbasis whitespace/delimeter teks, tambahkan token baru di ujung paling kanan baris log. Jangan pernah menyisipkan field di tengah format yang telah berjalan.
- Gunakan Format JSON untuk Log Kompleks: Jika log memuat lebih dari 10 parameter atau field opsional (seperti auth token status, upstream response time berulang), migrasikan
log_formatNginx ke format JSON native viaescape=json. JSON parser lebih toleran terhadap urutan key baru. - Disiplin Penggunaan Flag
%^: Gunakan token pengabaian%^di GoAccess hanya untuk field metadata yang tidak akan pernah dianalisis, hindari mengabaikan identifier krusial yang dapat memecah integritas metrik.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!