IIS writes a request log for every hit on your Windows VPS by default, but most administrators never open it. The files live under C:\inetpub\logs\LogFiles in a folder named after the site ID (W3SVC1, W3SVC2), and each line is a single request in W3C Extended Log Format. That log answers the three questions that matter on a rented server: which requests are slow, which are failing, and which are trying to break in. This guide shows you how to read those files and turn them into fixes, using tools that are already installed on Windows Server.
Log analysis is one of the cheapest performance upgrades available on a Windows VPS, because it costs nothing and requires no third-party agents. The data is already being written on every request; you just need to query it. If you are still deciding where to host, our comparison table lists Windows VPS plans side by side, including the disk and RAM that determine how many days of logs you can keep online before rotating them to cheaper storage.
Where IIS Writes Log Files and How to Change the Location
Each site in IIS gets its own log directory. The default structure is:
%SystemDrive%\inetpub\logs\LogFiles\W3SVC1— the first site (usually Default Web Site)W3SVC2,W3SVC3— subsequent sites in the order they were created- Files named
u_exYYMMDD.log, one per day by default, rolled at midnight
On a small VPS, logs accumulate on the same disk as the OS, which is exactly where you do not want them. Move the directory to a data volume with appcmd (run as Administrator):
appcmd set config -section:system.applicationHost/sites /[name='Default Web Site'].logFile.directory:"D:\iislogs" /commit:apphost
The /commit:apphost flag writes the change to applicationHost.config, so it survives an IIS reset. Restart the site or run iisreset for the new path to take effect.
Reading the W3C Extended Log Format
A single W3C log line looks like this:
2026-08-05 14:02:11 203.0.113.7 GET /api/orders - 80 - 203.0.113.7 Mozilla/5.0+ 200 0 0 8421 1234
The fields are defined by the #Fields: header at the top of each file. The ones worth memorizing are:
| Field | Meaning | Why it matters |
|---|---|---|
| cs-method | HTTP verb (GET, POST) | POST-heavy traffic points to forms and APIs |
| cs-uri-stem | Requested path | Identifies the slow or failing endpoint |
| sc-status | HTTP status code | 5xx rows are application or pool failures |
| sc-substatus | IIS sub-status | Distinguishes, e.g., 500.19 config errors |
| time-taken | Milliseconds to serve | The single most useful column for tuning |
| cs(User-Agent) | Client string | Flags bots and scanners hitting odd paths |
Note that time-taken measures the full time from the first byte received to the last byte sent, so it includes client-side latency on large downloads. For application performance, filter to dynamic requests such as .aspx, .ashx, and API routes.
Finding Slow Requests with Log Parser and PowerShell
Log Parser 2.2 is a free Microsoft download that queries log files with SQL-like syntax. The query below lists the endpoints whose slowest request exceeded 5 seconds, sorted by worst case:
logparser "SELECT cs-uri-stem, COUNT(*) AS Hits, MAX(time-taken) AS MaxMs FROM C:\inetpub\logs\LogFiles\W3SVC1\u_ex*.log WHERE time-taken > 5000 GROUP BY cs-uri-stem ORDER BY MaxMs DESC" -i:w3c
If you prefer PowerShell, the equivalent is a few lines of Get-Content and Where-Object, skipping comment lines that start with #:
Get-Content C:\inetpub\logs\LogFiles\W3SVC1\u_ex*.log |
Where-Object { $_ -notmatch '^#' } |
ForEach-Object { $f = $_ -split ' '; [pscustomobject]@{ Uri = $f[4]; Ms = [int]$f[13] } } |
Where-Object { $_.Ms -gt 5000 } |
Sort-Object Ms -Descending | Select-Object -First 20
The column index 13 assumes the default field order; adjust it if your #Fields: header differs. Scan one day’s file first — pure PowerShell is slow across thirty files. For recurring checks, schedule the query with Task Scheduler or use Log Parser for anything beyond a few thousand lines.
Status Codes That Signal Real Problems
Not every non-200 response deserves attention, but some status codes are almost always actionable:
- 404 — high volume on random paths is usually a scanner probing for vulnerabilities; a spike on one real URL means a broken link or moved asset.
- 500 — unhandled application exceptions. Pair with Windows Event Log Application errors for stack traces.
- 502 / 503 — the application pool stopped or the backend refused connections; correlate with pool recycling events.
- 401 — failed authentication attempts; repeated bursts from one IP warrant a firewall block.
Count them by code with a one-line Log Parser query: logparser "SELECT sc-status, COUNT(*) FROM C:\inetpub\logs\LogFiles\W3SVC1\u_ex*.log GROUP BY sc-status" -i:w3c. A healthy site shows 90%+ 2xx responses; a sudden 5xx share after a deployment points at the release, not the server.
Rotating Logs and Keeping Disk Use Predictable
IIS rolls logs daily by default, but you control both size and retention. Set a maximum file size (for example 20 MB) so a traffic spike cannot fill the disk, and enable the built-in compression of old log files to cut archive size by roughly 90%. Decide on a retention window — 30 days online is generous for most VPS workloads — and move anything older to offsite storage such as an S3 bucket or a second VPS. A disk that fills with logs takes the whole site down, not just the logging feature, so cap the directory early.
Logs are the fastest way to find slow requests, broken endpoints, and brute-force patterns before they become outages. With the queries above and a sane rotation policy, you get most of what a paid monitoring agent offers. If your current provider’s disk is too small to hold even a week of logs, compare Windows VPS plans side by side and pick one with a separate data volume. For a budget-friendly managed option, InterServer’s Windows VPS plans include enough storage for logs and databases, and the promo code TRYINTERSERVER drops the first month to $0.01 — a cheap way to test a logging setup on a fresh box.



