NGINX Observability
Observability: Access Logs, Error Logs, Metrics, and Tracing
Memahami access log, error log, structured logging, request ID, upstream timing, Prometheus exporter, OpenTelemetry, dashboard, dan alerting.
Part 020 — Observability: Access Logs, Error Logs, Metrics, and Tracing
1. Tujuan Part Ini
NGINX sering menjadi layer pertama yang melihat request dan layer terakhir yang melihat response sebelum keluar ke client.
Artinya, saat production incident terjadi, NGINX bisa menjadi:
sumber kebenaran awal
atau titik buta terbesar
Jika observability NGINX buruk, banyak masalah terlihat seperti:
backend Java lambat
Kubernetes error
client network unstable
cloud load balancer bermasalah
Padahal root cause bisa berada di:
wrong location routing
timeout chain
upstream connection failure
request body terlalu besar
client disconnect
TLS handshake issue
auth subrequest timeout
Ingress annotation conflict
DNS resolver stale
Part ini membahas observability NGINX sebagai production debugging layer: access log, error log, structured logging, metrics, tracing, correlation ID, dashboard, alerting, dan cara membaca sinyal tanpa tersesat.
2. Mental Model: Four Signals at the Proxy Layer
Observability NGINX perlu menjawab empat pertanyaan:
| Signal | Pertanyaan |
|---|---|
| Traffic | Berapa request masuk, ke host/path mana, dari siapa? |
| Errors | Error apa, di layer mana, dan seberapa sering? |
| Latency | Waktu habis di client, NGINX, auth, upstream, atau response transfer? |
| Saturation | Apakah NGINX, upstream, atau connection pool kehabisan kapasitas? |
Di NGINX, sinyal ini datang dari:
access log
error log
metrics endpoint
Ingress controller metrics
NGINX Plus API jika digunakan
OpenTelemetry/tracing jika tersedia
cloud load balancer metrics
Kubernetes events
application logs
Senior engineer harus bisa menggabungkan semua itu menjadi timeline request.
3. Access Log vs Error Log
Access log menjawab:
request apa yang terjadi?
status apa yang dikirim?
berapa lama?
upstream mana yang dipakai?
berapa besar body/response?
client siapa?
Error log menjawab:
apa yang gagal secara internal?
DNS resolve gagal?
connect upstream refused?
upstream timed out?
client sent invalid header?
SSL handshake gagal?
file permission salah?
config/module issue?
Access log bersifat request-centric.
Error log bersifat event/problem-centric.
Untuk debugging production, keduanya harus dibaca bersama.
Contoh:
access log: 504, upstream_response_time=30.000
error log: upstream timed out while reading response header from upstream
Interpretasi:
NGINX berhasil connect ke upstream, tetapi upstream tidak mengirim response header sebelum proxy_read_timeout.
4. Minimal Access Log Fields untuk Reverse Proxy
Default combined log sering tidak cukup untuk enterprise debugging.
Field minimum yang sebaiknya ada:
time
request_id
remote_addr / real_client_ip
xff
host
method
uri
status
request_time
upstream_addr
upstream_status
upstream_connect_time
upstream_header_time
upstream_response_time
request_length
body_bytes_sent
referer
user_agent
traceparent
Untuk Java/JAX-RS backend, field terpenting:
request_id
traceparent
host
uri
status
request_time
upstream_status
upstream_response_time
upstream_addr
xff / real client IP
Karena field-field ini membantu membedakan:
client problem
NGINX routing problem
upstream Java problem
Kubernetes Service problem
network problem
5. Example Structured Access Log
Contoh JSON-style log format:
log_format json_combined escape=json
'{'
'"time":"$time_iso8601",'
'"request_id":"$request_id",'
'"remote_addr":"$remote_addr",'
'"x_forwarded_for":"$http_x_forwarded_for",'
'"host":"$host",'
'"method":"$request_method",'
'"uri":"$request_uri",'
'"status":$status,'
'"request_time":$request_time,'
'"upstream_addr":"$upstream_addr",'
'"upstream_status":"$upstream_status",'
'"upstream_connect_time":"$upstream_connect_time",'
'"upstream_header_time":"$upstream_header_time",'
'"upstream_response_time":"$upstream_response_time",'
'"request_length":$request_length,'
'"body_bytes_sent":$body_bytes_sent,'
'"user_agent":"$http_user_agent",'
'"traceparent":"$http_traceparent"'
'}';
access_log /var/log/nginx/access.log json_combined;
Catatan:
escape=json penting untuk mengurangi risiko log rusak oleh karakter khusus.
Jangan log header sensitif seperti:
Authorization
Cookie
Set-Cookie
X-Api-Key
raw JWT
client certificate full PEM
6. Request ID and Correlation ID
Tanpa request ID, debugging distributed system menjadi forensik manual.
Request ID harus konsisten dari edge ke backend:
client/load balancer -> NGINX -> Java/JAX-RS -> downstream services -> logs/traces
Pattern umum:
map $http_x_request_id $req_id {
default $http_x_request_id;
"" $request_id;
}
proxy_set_header X-Request-ID $req_id;
Pertimbangan:
jika client mengirim X-Request-ID, apakah dipercaya?
apakah harus generate ulang di edge?
apakah format dibatasi?
apakah request ID boleh mengandung PII?
apakah semua service log field yang sama?
Untuk external client, sering lebih aman membuat edge-generated request ID dan menyimpan client request ID sebagai field terpisah.
7. Trace Context Propagation
Modern distributed tracing biasanya memakai W3C trace context:
traceparent
tracestate
NGINX dapat meneruskan header tersebut:
proxy_set_header traceparent $http_traceparent;
proxy_set_header tracestate $http_tracestate;
Tetapi meneruskan header saja tidak sama dengan membuat span NGINX.
Ada tiga level capability:
1. NGINX hanya meneruskan trace headers.
2. NGINX/Ingress membuat telemetry via module/exporter tertentu.
3. NGINX Plus/NGINX Ingress Controller/Gateway Fabric menggunakan OpenTelemetry integration jika tersedia.
Internal verification wajib karena kemampuan tracing berbeda antara:
NGINX Open Source standalone
NGINX Plus
community ingress-nginx
F5 NGINX Ingress Controller
NGINX Gateway Fabric
cloud API gateway/service mesh
8. Understanding NGINX Timing Fields
Timing field penting:
| Field | Makna |
|---|---|
$request_time | total waktu request dari NGINX membaca byte pertama sampai log ditulis |
$upstream_connect_time | waktu connect ke upstream |
$upstream_header_time | waktu sampai response header upstream diterima |
$upstream_response_time | waktu menerima response dari upstream |
Interpretasi sederhana:
request_time tinggi, upstream_response_time rendah
-> client lambat membaca response, request body lambat, buffering, atau NGINX/client side issue
upstream_connect_time tinggi
-> network, service endpoint, pod readiness, SYN backlog, security group, DNS/service routing
upstream_header_time tinggi
-> Java service lambat mulai response, DB/external call/thread pool
upstream_response_time tinggi
-> upstream lambat menyelesaikan response, streaming/download/large payload
Untuk retry upstream, field upstream bisa berisi beberapa nilai.
Contoh konseptual:
upstream_addr="10.1.1.10:8080, 10.1.1.11:8080"
upstream_status="502, 200"
upstream_response_time="0.003, 0.120"
Artinya request mencoba upstream pertama, gagal, lalu sukses di upstream kedua.
9. Status Codes That Matter at NGINX Layer
Beberapa status code punya makna proxy-specific:
| Status | Makna umum |
|---|---|
| 400 | request malformed, header invalid, bad host/header/path |
| 401 | authentication required/failed |
| 403 | forbidden by policy, allowlist, authz, file/path rule |
| 404 | route tidak match, wrong location, backend not found |
| 408 | client timeout saat mengirim request |
| 413 | body terlalu besar |
| 414 | URI terlalu panjang |
| 429 | rate limit/throttling |
| 499 | client menutup koneksi sebelum response selesai |
| 500 | internal NGINX/app error tergantung source |
| 502 | bad gateway, upstream invalid/refused/reset/protocol issue |
| 503 | service unavailable, upstream unavailable, overload, maintenance |
| 504 | gateway timeout, upstream tidak merespons tepat waktu |
Status code harus dikorelasikan dengan:
upstream_status
error log
request_time
upstream_response_time
route/host/path
client IP/user-agent
Kubernetes events
application logs
10. Why 499 Deserves Special Attention
499 adalah sinyal penting di NGINX.
Maknanya:
client menutup koneksi sebelum NGINX selesai mengirim response
Penyebab umum:
browser/user membatalkan request
mobile network putus
client timeout lebih pendek dari server timeout
load balancer idle timeout
API client retry sebelum request selesai
backend terlalu lambat
large response lambat dikirim
499 sering tidak muncul di application log sebagai error eksplisit.
Jika 499 meningkat, jangan langsung menyalahkan client. Cek:
apakah upstream latency naik?
apakah timeout client lebih pendek dari proxy/backend?
apakah response besar?
apakah network egress lambat?
apakah deploy baru memperlambat endpoint?
apakah SSE/WebSocket/long polling salah dikonfigurasi?
11. Error Log Levels
NGINX error log memiliki level seperti:
debug
info
notice
warn
error
crit
alert
emerg
Di production, level umum biasanya warn atau error, kecuali sedang investigasi.
Contoh:
error_log /var/log/nginx/error.log warn;
Debug log sangat detail dan bisa mahal.
Gunakan debug log dengan batasan:
time-boxed
scope terbatas
environment terbatas
sampling jika memungkinkan
pastikan tidak bocor data sensitif
Untuk Kubernetes, cek apakah error log dikirim ke stdout/stderr dan dikumpulkan oleh log pipeline.
12. Metrics: What NGINX Should Expose
Metrics yang berguna:
request rate
status code count
latency histogram/summary
active connections
accepted/handled connections
reading/writing/waiting connections
upstream errors
upstream latency
reload count
controller sync errors
config rejected count
TLS handshake errors jika tersedia
rate limit rejection count
NGINX Open Source dapat expose basic status via stub_status jika module tersedia.
Contoh:
location /nginx_status {
stub_status;
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
}
Namun stub_status basic dan bukan full request-level observability.
Untuk Kubernetes, biasanya metrics masuk melalui:
NGINX Ingress Controller metrics endpoint
Prometheus scrape
ServiceMonitor
Grafana dashboard
cloud monitoring integration
13. Prometheus and Ingress Controller Metrics
Dalam Kubernetes, observability NGINX sering bergantung pada controller.
Hal yang perlu dicek:
apakah metrics endpoint aktif?
port metrics berapa?
apakah ServiceMonitor dibuat?
apakah namespace Prometheus dapat scrape?
apakah label selector cocok?
apakah endpoint diamankan?
apakah dashboard membedakan controller metrics dan data-plane metrics?
Metrics ingress yang berguna:
requests by ingress/host/path/status
latency by ingress/service
config reload/reconciliation errors
controller workqueue issue
SSL certificate expiration jika tersedia
upstream/service endpoint availability
Risiko:
label host/path/ingress terlalu high-cardinality
metrics tidak konsisten antar controller
histogram bucket tidak sesuai latency SLO
metrics endpoint publik tanpa proteksi
14. NGINX Plus and Advanced Metrics
Jika environment menggunakan NGINX Plus, observability bisa lebih kaya.
Kemungkinan capability:
NGINX Plus API
upstream zone metrics
active health check state
per-upstream server stats
dashboard
Prometheus integration module
OpenTelemetry module
Tetapi jangan mengasumsikan NGINX Plus.
Internal verification:
apakah image/license NGINX Plus digunakan?
apakah API/dashboard diaktifkan?
apakah endpoint metrics diamankan?
apakah upstream zone dikonfigurasi?
apakah active health check tersedia?
Jika menggunakan NGINX Open Source, beberapa metrics advanced harus diperoleh dari log, exporter, ingress controller, atau platform observability.
15. OpenTelemetry and Tracing Integration
Tracing di NGINX harus dipahami dengan hati-hati.
Kemungkinan mode:
header propagation only
OpenTelemetry module di NGINX Plus
OpenTelemetry di F5 NGINX Ingress Controller
tracing dari API gateway/cloud/service mesh
application-only tracing di Java service
Jika hanya Java service yang membuat span, maka NGINX tidak terlihat sebagai span tersendiri.
Efeknya:
latency antara client dan backend bisa hilang dari trace
502/503/504 dari proxy bisa tidak muncul di trace aplikasi
client disconnect 499 bisa tidak muncul di trace aplikasi
Tracing ideal:
edge span
proxy/upstream span
application span
downstream service span
DB/external call span
Tetapi implementasi ideal harus dibandingkan dengan kemampuan platform aktual.
16. Dashboard Design
Dashboard NGINX yang baik tidak hanya menampilkan CPU dan request count.
Minimal dashboard:
request rate by host/service
status code distribution
4xx by reason/path
5xx by upstream/service
499 trend
502/503/504 trend
p50/p95/p99 request_time
p50/p95/p99 upstream_response_time
upstream_connect_time trend
rate limit rejection
body size / 413
active connections
NGINX pod CPU/memory
reload/config error
TLS certificate expiry if available
Untuk senior debugging, dashboard harus memungkinkan drill-down:
host -> ingress -> path -> service -> pod -> status -> latency
Bukan hanya cluster-wide aggregate.
17. Alerting Strategy
Alert harus actionable.
Contoh alert buruk:
NGINX 5xx > 0
Contoh alert lebih baik:
5xx rate for public-api host > 2% for 5 minutes
504 count for quote-service ingress above baseline
p99 upstream_response_time exceeds SLO for 10 minutes
499 rate doubles while upstream latency also rises
Ingress controller config reload failures > 0
TLS cert expires in less than 14 days
Prometheus scrape for ingress controller failing
Alert harus punya:
owner
severity
runbook
dashboard link
expected first diagnostic step
escalation path
Tanpa runbook, alert hanya noise.
18. Log Sampling and Cardinality Risk
High traffic systems bisa menghasilkan log sangat besar.
Sampling bisa dibutuhkan, tetapi hati-hati.
Jangan sampling buta untuk:
5xx
429
499 spike
security denial
auth failure
large body rejection
TLS/auth incident
High-cardinality risk pada metrics:
full URI dengan ID unik
query string
user ID
tenant ID berjumlah besar
request ID
raw user agent
IP address
Gunakan route template jika tersedia:
/api/quotes/{quoteId}
Bukan:
/api/quotes/123456789?customer=...
Untuk log, full URI sering berguna. Untuk metrics label, full URI bisa merusak Prometheus/cardinality.
19. Sensitive Data and Log Redaction
NGINX berada di edge sehingga bisa melihat data sensitif.
Jangan log:
Authorization header
Cookie
Set-Cookie
API key
raw JWT
password
client secret
full request body
PII di query string jika bisa dihindari
client certificate full content
Masalah umum:
GET endpoint membawa PII di query string
access log menyimpan request_uri penuh
log dikirim ke third-party observability
retention log terlalu panjang
engineer terlalu banyak punya akses log production
Untuk compliance, verifikasi:
log field apa yang dikumpulkan
siapa yang bisa membaca log
berapa lama retention
apakah redaction terjadi sebelum ingest
apakah log bisa digunakan sebagai audit evidence
20. Java/JAX-RS Observability Alignment
NGINX dan Java service harus memakai identitas observability yang sama.
Minimal alignment:
X-Request-ID sama
traceparent diteruskan
client IP semantics jelas
host dan path public vs internal bisa dipetakan
status code backend vs status code NGINX dibedakan
Di Java/JAX-RS log, pastikan ada:
request_id
trace_id
method
route template
status
latency
user/tenant hash jika aman
exception class
upstream dependency timing
Jika NGINX log menunjukkan:
status=504
upstream_status="-"
Kemungkinan request tidak mencapai backend.
Jika menunjukkan:
status=504
upstream_status="200"
Perlu interpretasi hati-hati, bisa ada retry/multiple upstream atau logging sequence yang harus dibaca dengan konteks.
Selalu korelasikan dengan application log berdasarkan request ID/trace ID.
21. Kubernetes Observability
Untuk NGINX di Kubernetes, debugging memerlukan beberapa sumber:
Ingress resource
Ingress Controller pod logs
Controller metrics
Generated NGINX config jika bisa diakses
Kubernetes Service
EndpointSlice
Pod readiness
Events
ConfigMap
Secret/TLS Secret
Cloud load balancer metrics
Command investigasi umum:
kubectl get ingress -A
kubectl describe ingress <name> -n <namespace>
kubectl get svc -n <namespace>
kubectl get endpointslice -n <namespace>
kubectl logs deploy/<nginx-ingress-controller> -n <namespace>
kubectl describe pod <pod> -n <namespace>
Sinyal penting:
Ingress accepted/rejected
annotation invalid
service has no endpoints
pod not ready
TLS secret missing
config reload failed
controller cannot update status
22. Cloud Load Balancer Observability
NGINX bukan satu-satunya edge.
Di AWS/EKS, cek:
ALB/NLB metrics
target group health
TargetResponseTime
HTTPCode_ELB_5XX
HTTPCode_Target_5XX
security group drops
NLB TCP reset metrics jika tersedia
CloudWatch logs jika aktif
Di Azure/AKS, cek:
Application Gateway metrics/logs
Azure Load Balancer health
Front Door/WAF logs
NSG flow logs jika tersedia
Azure Monitor
backend pool health
On-prem/hybrid:
enterprise LB logs
firewall logs
DNS resolver logs
proxy chain logs
certificate appliance logs
Jangan berhenti di NGINX jika request bahkan belum mencapainya.
23. Debugging Patterns by Symptom
High 502
Cek:
error log: connection refused/reset/no live upstream
upstream_connect_time
Service endpoints
Pod readiness
backend protocol mismatch HTTP/HTTPS/gRPC
upstream TLS verification
High 503
Cek:
no endpoints
maintenance/overload
upstream marked unavailable
Ingress default backend
rate/connection exhaustion
controller config issue
High 504
Cek:
proxy_read_timeout
upstream_header_time
Java thread pool/DB latency
external dependency
load balancer idle timeout
retry chain
High 499
Cek:
client timeout
upstream latency
large response
mobile/partner network
LB idle timeout
user cancellation
High 413
Cek:
client_max_body_size
Ingress body size annotation
multipart endpoint
upload path
API contract
24. Observability for Security Events
Security-relevant events:
401/403 spike
429 spike
blocked IP/path
invalid host header
large header/body rejection
mTLS verification failure
TLS handshake error
suspicious user agent
path traversal attempt
request smuggling indicators
WAF block if used
Do not mix all security events into generic 4xx.
Security dashboard should separate:
auth failure
authorization denial
rate limit
WAF/security block
malformed request
client behavior error
This helps avoid two mistakes:
ignoring attack traffic as normal 4xx
escalating normal client validation errors as security incidents
25. Observability PR Review Checklist
Gunakan checklist ini saat review perubahan NGINX/Ingress:
Apakah request ID dipertahankan atau dibuat?
Apakah traceparent/tracestate diteruskan?
Apakah access log punya upstream timing?
Apakah log format JSON valid?
Apakah Authorization/Cookie/API key tidak dilog?
Apakah status 499/502/503/504 terlihat di dashboard?
Apakah metrics endpoint aktif dan diamankan?
Apakah ServiceMonitor/Prometheus scrape ada?
Apakah label metrics tidak high-cardinality?
Apakah alert punya runbook?
Apakah route baru punya observability sebelum production?
Apakah auth/rate limit/security denial punya sinyal terpisah?
Apakah rollback/config reload failure terlihat?
26. Internal Verification Checklist
Untuk konteks CSG/team, verifikasi:
Log format NGINX/Ingress yang digunakan.
Apakah access log aktif di semua environment.
Apakah error log level production sesuai.
Apakah logs dikirim ke platform observability pusat.
Apakah request ID dibuat di cloud LB, NGINX, API gateway, atau aplikasi.
Header correlation apa yang distandardkan.
Apakah traceparent diteruskan sampai Java/JAX-RS service.
Apakah NGINX menghasilkan spans atau hanya meneruskan headers.
Apakah Prometheus scrape aktif untuk ingress controller.
Apakah dashboard membedakan host/ingress/service/status.
Apakah 499 dipantau.
Apakah 502/503/504 punya alert dan runbook.
Apakah TLS/cert expiry dimonitor.
Apakah log redaction sudah memenuhi compliance.
Apakah PII muncul di query string/access log.
Apakah incident notes sebelumnya menunjukkan observability gap.
27. Anti-Patterns
Menggunakan default access log untuk production API kompleks.
Tidak mencatat upstream_response_time.
Tidak punya request ID end-to-end.
Menganggap trace aplikasi cukup untuk proxy failure.
Melog Authorization/Cookie/JWT penuh.
Memakai full URI sebagai metrics label.
Tidak memantau 499.
Menggabungkan semua 4xx sebagai client error biasa.
Mengabaikan error log saat debugging access log.
Metrics endpoint terbuka publik.
Alert tanpa runbook.
Tidak memisahkan NGINX 5xx dari backend 5xx.
Tidak menyimpan enough context untuk incident RCA.
28. Practical Senior Engineer Heuristics
If it is not in logs or metrics, it did not happen operationally.
Access log tells what happened; error log often tells why.
request_time without upstream timing is incomplete.
499 is a customer experience signal, not just client noise.
502/503/504 are different failure classes; do not lump them together.
A trace without edge visibility can miss proxy failures.
Metrics labels should be stable; logs can carry richer detail.
Every production route should be debuggable before it is launched.
Redaction is part of observability design, not an afterthought.
Dashboards should follow the request path: edge -> ingress -> service -> pod -> app.
29. Ringkasan
Observability NGINX adalah kemampuan untuk menjawab:
request masuk dari mana
masuk ke host/path mana
status apa yang keluar
upstream mana yang dipilih
berapa lama connect/header/response
apakah client disconnect
apakah NGINX atau backend yang menghasilkan error
apakah config/ingress/controller sehat
apakah sinyal ini bisa dikorelasikan dengan Java/JAX-RS logs
Target pemahaman senior engineer:
mendesain structured access log
membaca error log dengan konteks
memahami request_time vs upstream timing
membedakan 499/502/503/504
menyambungkan request ID dan trace context
menghindari log leakage
membuat dashboard dan alert yang actionable
menggunakan observability untuk mempercepat RCA
NGINX observability yang baik tidak hanya membuat sistem terlihat. Ia membuat failure dapat dijelaskan, diprioritaskan, dan diperbaiki tanpa debat spekulatif antar tim.
30. Referensi Resmi untuk Diverifikasi
NGINX log module:
https://nginx.org/en/docs/http/ngx_http_log_module.html
NGINX upstream variables:
https://nginx.org/en/docs/http/ngx_http_upstream_module.html
NGINX stub status module:
https://nginx.org/en/docs/http/ngx_http_stub_status_module.html
F5 NGINX Ingress Controller Prometheus metrics:
https://docs.nginx.com/nginx-ingress-controller/logging-and-monitoring/prometheus/
F5 NGINX OpenTelemetry module:
https://docs.nginx.com/nginx/admin-guide/dynamic-modules/opentelemetry/
F5 NGINX Ingress Controller OpenTelemetry:
https://docs.nginx.com/nginx-ingress-controller/logging-and-monitoring/opentelemetry/
You just completed lesson 20 in deepen practice. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.
Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.