Access Log Parser: Nginx & Apache Combined Log Analyzer
Paste a day of Nginx or Apache output into this parser and read back status distribution, top paths, bot share, client IPs, and traffic by hour. The widget accepts the standard combined and common log formats, flags every line it cannot read, and refuses JSON or virtual-host logs with a clear reason. Each step runs locally in the browser, so a file full of customer IPs stays on your machine. When the numbers look right, export the parsed rows as CSV for a spreadsheet or a ticket.
Analyze Log Lines in Your Browser
Parsing runs in this tab. Nothing is uploaded.How It Works
A combined line carries nine fields in a fixed order: the client IP, an identity field, the authenticated user, a bracketed timestamp, the quoted request line, a status code, a byte count, then the quoted referer and user agent. Common format stops after the byte count, so those files carry no referer or agent to read. Detection samples the first 50 non-empty lines and settles on combined or common once more than half of them match. Lines that open with a JSON object or lead with a host:port column stop the run with one stated reason.
Bot labels come from the user agent. The rule list matches search crawlers, AI crawlers, social preview fetchers, SEO tools, scripted clients such as curl and Python requests, headless browsers, security scanners, and monitoring pings, and the first hit supplies the name and category shown in the panels. A Mozilla user agent with no rule hit counts as a browser, while anything else is recorded as unclassified.
The hour chart buckets each entry by the hour digit inside its bracketed timestamp, giving 24 columns that follow the offset the server logged. The CSV writer emits one row per parsed entry with the columns ip, time, method, path, query, status, bytes, referer, and user_agent, escaping quotes and commas so a spreadsheet opens the file cleanly.
Before and After: Raw Lines Turn Into Counts
203.0.113.42 - - [22/Oct/2026:09:15:04 +0000] "GET /pricing HTTP/1.1" 200 5312 "https://example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/131.0.0.0"
format: combined · 4 lines · 4 parsed
total requests: 4
unique IPs: 3
bot share: 25.0% {"ts":"2026-10-22T09:15:04Z","client":"203.0.113.42","route":"/pricing","status":200}
These are JSON-structured logs. This parser reads Apache/Nginx common and combined text lines. Use Cases
Four situations cover most of what teams look for after pasting a file. Each row pairs a moment you would recognise with the panels that answer it, so you can move straight to the relevant numbers instead of reading every table on the page.
| Team | Situation | What to read |
|---|---|---|
| Web operations | A release shipped and error pages climbed the same afternoon | The 5xx list in the errors panel, then paths whose error counts are rising |
| Content and SEO | A new AI crawler started fetching pages last month | Bot request share, the bot breakdown rows, and the browser count beside them |
| Security | One address is hammering old or hidden URLs | Top client IPs with their bot hits, then the 404 list showing what is probed |
| Traffic review | Hotlinks or broken referrers keep appearing in reports | The referer column in the exported CSV, grouped by host inside a spreadsheet |
Common Mistakes
- Rewriting timestamps to UTC or trimming them to seconds before pasting. The hour bucket is read from the raw bracketed stamp, so a converted time moves every request into the wrong column.
- Treating the user agent as proof of who is calling. It is a self-reported string, so a crawler can drop its token and a browser can rename itself to Googlebot.
- Pasting vhost lines that keep a host:port column in front of the IP. Those lines are refused outright, and stripping that first column is the fix.
- Reading the top paths list without the error counts beside it. A busy path can hide hundreds of 404s while a quiet one fails on every single request.
- Comparing bot share across files that mix common and combined format. Common lines carry no user agent, so those requests fall into unclassified and pull the share down.
- Assuming every 404 is a broken link worth fixing. Scanners, old bookmarks, and expired campaigns produce a steady stream of them, so read that list beside the top paths before filing a bug.
Best Practices
- Sample a whole day, or a full week when traffic is light. A ten-minute slice mostly shows your own refreshes and one unlucky crawler.
- Export the CSV before you close the tab. The spreadsheet can then sort by status, filter by path, or pivot on hour without reopening the log.
- Read the issue panel before quoting a total. Skipped lines and format refusals explain most gaps between these numbers and a dashboard.
- Re-check the bot share after each major crawler launch. New AI fetchers arrive with unfamiliar names, and a jump that looks like a traffic surge is often one bot.
- Keep the raw log file beside your notes. The page holds data only while it is open, so the original file is what lets you repeat the analysis later.
- Read the bytes column next to request counts. A handful of large downloads can dominate bandwidth while leaving the request totals almost unchanged.
Frequently Asked Questions
Which log formats does this tool read?
The parser accepts the two text formats Nginx and Apache write by default: common format stops at the byte count, while combined format adds the quoted referer and user agent. Detection samples the first 50 non-empty lines and picks a format when most of them match. JSON-structured lines are refused with an explanation, and lines leading with a host:port column are refused the same way. A few bad lines in an otherwise good file are listed one by one instead of failing the run.
What goes into the summary row?
The summary row shows total parsed requests, unique client IPs, the bot share as a percentage of parsed requests, and the counts of 4xx and 5xx responses. Unique IPs are counted across every parsed entry rather than taken from the top list, so one busy address cannot hide the true figure. Bytes served appears as a sixth chip, while the skipped-line count is reported in the issue panel below. Each chip is recomputed on every parse.
How are bots classified?
Every user agent is matched against a rule list covering search crawlers, AI crawlers, social preview fetchers, SEO tools, scripted clients, headless browsers, security scanners, and uptime monitors. The first matching rule supplies the name and category shown in the agent and bot panels. A user agent containing Mozilla with no rule hit counts as a browser, and anything else is unclassified. Since the string is self-reported, read it as a strong hint rather than proof of identity.
Does my log file get uploaded?
No. Choosing a file only reads its text into the textarea, and parsing, statistics, and CSV building all run in this tab. No request carries your log lines, and nothing is written to storage. Logs containing customer IPs or internal paths can be pasted here, and closing the tab discards the input along with the generated CSV.
Why are some lines reported as skipped?
A line is skipped when it does not follow the common or combined shape, which usually means broken quoting, a half-written line, or an extra quote inside the request field. The issue panel lists the first ten failures with their line numbers, then gives a count for the rest. When the whole file is refused, such as a JSON export, the panel shows that single reason and no entries are parsed. Totals only cover the lines that parsed, so read the panel before comparing figures.
What does the CSV export contain?
The download button saves access-log-entries.csv with one row per parsed entry and nine columns: ip, time, method, path, query, status, bytes, referer, user_agent. The time column holds the converted ISO timestamp when the bracketed time could be read and the raw stamp otherwise. Query strings stay separate from the path, so a spreadsheet can group by endpoint without splitting cells. The copy button puts the same CSV text on the clipboard.
How is the hour chart built?
Each bracketed timestamp adds one count to a bucket named by its hour digit, so the chart has 24 columns labelled 00 through 23 in the offset the server logged. Empty buckets keep a two-pixel bar, which holds the label row steady. A timestamp that cannot be read still counts toward totals but contributes no hour. A chart with no height at all usually means the timestamps were rewritten before pasting.