$1, $2, etc. From each line we need two pieces:
- the status code (to select 5xx responses), and
- the URL (to count how many errors each URL produces).
- $1 = IP
- 3 = the two dashes
- $4 = timestamp (but note: it contains spaces and brackets)
- $5 = request (but it contains method, URL, and protocol separated by spaces)
- $6 = status
- $7 = response size
- the timestamp becomes two fields (e.g., fields 4 and 5),
- the quoted request becomes three fields (e.g., fields 6, 7, and 8).
- $1 = IP
- 3 = the two dashes
- 5 = timestamp (split into two fields)
- $6 = method (e.g.,
"POST) - $7 = URL (e.g., /api/checkout)
- $8 = protocol (e.g., HTTP/2.0”)
- $9 = status code
- $10 = response size
$9 for status and $7 for the URL:
Awk splits on whitespace by default. Quoted sections like the request (
"METHOD URL PROTOCOL") will be split into multiple fields unless you adjust the field separator or account for the split in your indices.500 anywhere on the line?
For example:
500 anywhere — in the status code, in the URL, or in the response size. That produces false positives. For instance, consider these lines:
500 in the URL and the response size; the third line contains 500 in the URL path. Using /500/ as a pattern will match those lines even though their status codes are not 500.
The correct approach is to anchor your match to the status code field. Using field matching avoids accidental matches in other parts of the line:
- Exact match for 500:
- Match the entire 5xx family:
- Do you understand awk fields and how whitespace splitting affects field indices?
- Do you properly anchor your regex or use field equality when matching status codes?
- Can you distinguish between searching the whole line vs matching a specific field?
FS, or more specialized parsers like Perl/Python scripts, or jq for JSON logs), but for many NGINX access logs a careful use of awk field indices (as shown) is sufficient.