IIS logs record every request to your websites: who requested what, when, the status code, and how long it took. They’re the first place to look when a site is slow, errors appear, or bots hammer the server. They also fill the disk if you never clean them up.
Where are the logs?
Default location:
C:\inetpub\logs\LogFiles\W3SVC<SiteID>\u_exYYMMDD.log
Find a site’s ID and log folder:
Get-Website | Select-Object Name, Id, @{n='LogDir';e={$_.logFile.directory}}
Other useful logs:
- HTTPERR logs (
C:\Windows\System32\LogFiles\HTTPERR): requests rejected by HTTP.sys before reaching IIS (bad requests, timeouts, app pool down). - Failed Request Tracing logs (if enabled): detailed traces of specific failures.
- Event Viewer → System and Application logs, for app pool crashes. See Windows Event Viewer errors.
Understanding the W3C format
Each line has the fields listed in the #Fields: header, for example:
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2026-10-01 08:15:02 10.0.0.5 GET /pricing/ - 443 - 198.51.100.7 Mozilla/5.0… - 200 0 0 46
| Field | Meaning |
|---|---|
c-ip |
Client IP (or the proxy’s IP, see below) |
cs-uri-stem / cs-uri-query |
Path and query string |
sc-status / sc-substatus |
HTTP status, e.g. 404.0, 500.19, 401.2 |
time-taken |
Milliseconds to process and send the response |
Times are in UTC by default.
Real client IPs behind Cloudflare or a load balancer
Behind a proxy, c-ip is the proxy’s address. Add the X-Forwarded-For header as a custom field: IIS Manager → site → Logging → Select Fields → Add Field → Source type “Request Header”, Source X-Forwarded-For. (For Cloudflare, CF-Connecting-IP also works.)
Quick analysis with PowerShell
$log = Get-ChildItem C:\inetpub\logs\LogFiles\W3SVC1\*.log | Sort-Object LastWriteTime | Select-Object -Last 1
$lines = Get-Content $log.FullName | Where-Object { $_ -notmatch '^#' }
# top client IPs (c-ip is field 9 in the header above, zero-based index 8)
$lines | ForEach-Object { ($_ -split ' ')[8] } | Group-Object | Sort-Object Count -Descending | Select-Object -First 10
# errors (sc-status 5xx)
$lines | Where-Object { ($_ -split ' ')[11] -like '5*' } | Select-Object -First 20
Adjust the field indexes to match your #Fields line.
Log Parser 2.2 (a free Microsoft tool) runs SQL queries on logs:
LogParser "SELECT TOP 10 cs-uri-stem, COUNT(*) AS Hits, AVG(time-taken) AS AvgMs FROM C:\inetpub\logs\LogFiles\W3SVC1\u_ex*.log GROUP BY cs-uri-stem ORDER BY Hits DESC" -i:W3C
For dashboards, ship logs to a log platform (Grafana Loki, ELK/OpenSearch, or a hosted service), or analyse them with GoAccess on another machine.
What to look for
- Slow pages: high
time-taken. Investigate the app, database, or external calls. - 5xx errors: app crashes, misconfiguration (500.19), app pool stopped (503). See host ASP.NET on IIS.
- 404 floods on paths like
/wp-login.phpor/.env: vulnerability scanners. Block abusive IPs at the firewall. See Windows Server firewall with PowerShell. - One IP with huge request counts: a bot or scraper. Rate-limit it, or block it.
Rotation and cleanup
IIS creates a new file daily (by default), but never deletes old ones. Clean up with a scheduled task:
Get-ChildItem C:\inetpub\logs\LogFiles -Recurse -Filter *.log |
Where-Object LastWriteTime -lt (Get-Date).AddDays(-30) | Remove-Item -Force
See Windows scheduled tasks with PowerShell and Windows disk cleanup.
Optional: enable NTFS compression on the log folder (logs compress very well), or move logs to a second volume.
Quick reference
| Item | Value |
|---|---|
| Location | C:\inetpub\logs\LogFiles\W3SVC<ID>\ |
| Format | W3C, UTC times |
| Pre-IIS rejects | C:\Windows\System32\LogFiles\HTTPERR |
| Real IP behind proxy | Custom field X-Forwarded-For |
| Query tool | Log Parser 2.2 / PowerShell |
| Cleanup | Scheduled task, delete files older than N days |
Related: install IIS and IIS URL Rewrite.