How to Configure IIS Logging and Request Tracing on Windows Server 2022
IIS on Windows Server 2022 provides robust logging and diagnostic capabilities that are critical for monitoring traffic, debugging application errors, and meeting compliance requirements. This guide covers every aspect of IIS logging — choosing the right log format, customizing fields, controlling file rotation, configuring Failed Request Tracing (FREB), and analyzing logs with Log Parser 2.2.
IIS Log Formats Overview
IIS supports four log formats: W3C Extended, IIS, NCSA Common, and Custom. The W3C Extended format is the default and recommended choice because it is flexible — you choose exactly which fields to include — and is supported by virtually all log analysis tools.
The IIS format is a fixed-field format similar to W3C but without the column header lines. NCSA Common is a legacy format originally developed for Apache. Custom format lets you define an arbitrary format string, but it is rarely necessary.
To check or set the log format for a site via PowerShell:
Import-Module WebAdministration
# Check current format
Get-WebConfigurationProperty -Filter "system.applicationHost/sites/site[@name='Default Web Site']/logFile" -Name "logFormat"
# Set to W3C
Set-WebConfigurationProperty -Filter "system.applicationHost/sites/site[@name='Default Web Site']/logFile" -Name "logFormat" -Value "W3C"
Configuring Log File Location and Rotation
By default, IIS writes log files to C:inetpublogsLogFiles. Each site gets its own subfolder named W3SVCn where n is the site ID. You can change the log directory to a different drive or network path for capacity or compliance reasons.
# Change log directory for Default Web Site (site ID 1)
Set-WebConfigurationProperty -Filter "system.applicationHost/sites/site[@name='Default Web Site']/logFile" -Name "directory" -Value "D:IISLogs"
Log rotation (called log file rollover in IIS) can be set to occur hourly, daily, weekly, monthly, or when the file reaches a specified size. Daily rotation is the most common setting.
# Set rollover to daily
Set-WebConfigurationProperty -Filter "system.applicationHost/sites/site[@name='Default Web Site']/logFile" -Name "period" -Value "Daily"
# Or set a maximum file size of 100 MB
Set-WebConfigurationProperty -Filter "system.applicationHost/sites/site[@name='Default Web Site']/logFile" -Name "period" -Value "MaxSize"
Set-WebConfigurationProperty -Filter "system.applicationHost/sites/site[@name='Default Web Site']/logFile" -Name "truncateSize" -Value 104857600
IIS uses UTC time in log file names and in logged timestamps by default. To use local server time instead:
Set-WebConfigurationProperty -Filter "system.applicationHost/sites/site[@name='Default Web Site']/logFile" -Name "localTimeRollover" -Value $true
Selecting Fields to Log in W3C Format
The W3C format supports dozens of fields including client IP, username, server IP, method, URI stem, URI query, status code, bytes sent, bytes received, time taken, user agent, referrer, and more. You can also log custom HTTP request and response headers.
In IIS Manager, navigate to the site, double-click Logging, then click Select Fields. From PowerShell, the logExtFileFlags property is a bitmask that determines which fields are included. The most useful fields for production logging are:
Set-WebConfigurationProperty `
-Filter "system.applicationHost/sites/site[@name='Default Web Site']/logFile" `
-Name "logExtFileFlags" `
-Value "Date,Time,ClientIP,UserName,ServerIP,Method,UriStem,UriQuery,HttpStatus,Win32Status,BytesSent,BytesRecv,TimeTaken,UserAgent,Referer,HttpSubStatus"
To log a custom request header such as X-Forwarded-For (useful when IIS is behind a load balancer):
Add-WebConfigurationProperty `
-Filter "system.applicationHost/sites/site[@name='Default Web Site']/logFile/customFields" `
-Name "." `
-Value @{logFieldName="X-Forwarded-For"; sourceName="X-Forwarded-For"; sourceType="RequestHeader"}
Centralized vs Per-Site Logging
IIS supports two logging modes: per-site logging (the default) and centralized logging. In per-site mode, each site writes to its own log file. In centralized mode, all sites on the server write to a single log file, with an optional siteID field added to each line to identify which site generated the entry.
Centralized logging is configured at the server level in applicationHost.config:
Set-WebConfigurationProperty -Filter "system.applicationHost/log" -PSPath "IIS:" -Name "centralLogFileMode" -Value "CentralW3C"
Set-WebConfigurationProperty -Filter "system.applicationHost/log/centralW3CLogFile" -PSPath "IIS:" -Name "directory" -Value "D:CentralLogs"
Set-WebConfigurationProperty -Filter "system.applicationHost/log/centralW3CLogFile" -PSPath "IIS:" -Name "period" -Value "Daily"
The centralized log includes a cs-sitename or s-sitename field that identifies the site for each entry. This is very useful for servers hosting many small sites where per-site logs would be tedious to manage.
Failed Request Tracing (FREB)
Failed Request Tracing (also called FREB — Failed Request Event Buffering) captures a detailed XML trace of a request’s lifecycle through every IIS module and handler. It is invaluable for diagnosing 500 errors, 403 responses, slow requests, and authentication failures that are difficult to diagnose from regular logs alone.
First, install the Failed Request Tracing feature if it is not already present:
Install-WindowsFeature Web-Http-Tracing
Enable FREB for a site and specify where trace files will be saved:
Enable-WebRequestTracing -Name "Default Web Site" -Directory "C:inetpublogsFailedReqLogFiles" -MaxLogFiles 50
Configuring FREB Rules
A FREB rule specifies which requests to trace. You can trigger tracing based on status code, time taken, or a combination. To trace all requests returning HTTP 500:
Add-WebConfigurationProperty `
-Filter "system.webServer/tracing/traceFailedRequests" `
-PSPath "IIS:SitesDefault Web Site" `
-Name "." `
-Value @{path="*"}
Set-WebConfigurationProperty `
-Filter "system.webServer/tracing/traceFailedRequests/add[@path='*']/failureDefinitions" `
-PSPath "IIS:SitesDefault Web Site" `
-Name "statusCodes" -Value "500"
To trace requests taking longer than 5000 milliseconds (5 seconds), useful for finding slow pages:
Set-WebConfigurationProperty `
-Filter "system.webServer/tracing/traceFailedRequests/add[@path='*']/failureDefinitions" `
-PSPath "IIS:SitesDefault Web Site" `
-Name "timeTaken" -Value "00:00:05"
You can also scope tracing to a specific URL path instead of all requests:
Add-WebConfigurationProperty `
-Filter "system.webServer/tracing/traceFailedRequests" `
-PSPath "IIS:SitesDefault Web Site" `
-Name "." `
-Value @{path="/api/orders*"}
Reading FREB Log Files
FREB produces XML files in the configured trace directory. Each file is named fr000001.xml, fr000002.xml, and so on. IIS also generates an freb.xsl stylesheet in the same directory that transforms the XML into a readable HTML report.
To open a FREB trace in your browser, navigate to the trace directory in File Explorer and double-click a .xml file. The browser will apply the XSL stylesheet and show a color-coded, expandable waterfall view of the request through each module. Red entries indicate modules that returned an error or warning.
The trace shows entries like:
MODULE_SET_RESPONSE_ERROR_STATUS
ModuleName: ManagedPipelineHandler
Notification: EXECUTE_REQUEST_HANDLER
HttpStatus: 500
HttpReason: Internal Server Error
HttpSubStatus: 0
ErrorCode: The operation completed successfully (0x0)
This level of detail is not available anywhere else in IIS and is the fastest way to diagnose application pool crashes, missing authentication, and module configuration errors.
Using Log Parser 2.2 to Analyze IIS Logs
Microsoft Log Parser 2.2 is a free command-line tool that lets you run SQL-like queries against IIS W3C log files. Download it from the Microsoft Download Center and install it. The syntax uses FROM iisw3c as the input format.
Find the top 10 most requested URLs:
logparser "SELECT TOP 10 cs-uri-stem, COUNT(*) AS Hits FROM C:inetpublogsLogFilesW3SVC1*.log GROUP BY cs-uri-stem ORDER BY Hits DESC" -i:W3C
Find all requests that returned HTTP 500 errors with their timestamps and URIs:
logparser "SELECT date, time, c-ip, cs-uri-stem, sc-status, sc-substatus FROM C:inetpublogsLogFilesW3SVC1*.log WHERE sc-status=500" -i:W3C
Find the slowest requests by time-taken, in milliseconds:
logparser "SELECT TOP 20 date, time, cs-uri-stem, time-taken FROM C:inetpublogsLogFilesW3SVC1*.log ORDER BY time-taken DESC" -i:W3C
Count requests per hour to identify traffic peaks:
logparser "SELECT QUANTIZE(TO_TIMESTAMP(date, time), 3600) AS Hour, COUNT(*) AS Requests FROM C:inetpublogsLogFilesW3SVC1*.log GROUP BY Hour ORDER BY Hour" -i:W3C
Real-Time Monitoring with IIS Manager
IIS Manager includes a Worker Processes view that shows currently executing requests in real time. Navigate to the server node in IIS Manager and double-click Worker Processes. You will see each application pool worker process (w3wp.exe), its CPU and memory usage, and the requests it is currently processing.
Click on a worker process and then click View Current Requests to see every in-flight request with its URL, state, time elapsed, module, and verb. This is useful for identifying runaway requests that are consuming resources.
For command-line real-time monitoring, AppCmd.exe provides the same data:
%windir%system32inetsrvappcmd list requests /elapsed:5000
This lists all requests that have been running for more than 5 seconds — a quick way to find hung or slow requests without opening a browser.
Automating Log Archival with PowerShell
For servers with high traffic, IIS logs can grow quickly. A scheduled PowerShell script can compress and archive old logs. The following script compresses log files older than 7 days and deletes archives older than 90 days:
$logRoot = "C:inetpublogsLogFiles"
$archiveRoot = "D:LogArchives"
Get-ChildItem -Path $logRoot -Recurse -Filter "*.log" | Where-Object {
$_.LastWriteTime -lt (Get-Date).AddDays(-7)
} | ForEach-Object {
$dest = $_.FullName.Replace($logRoot, $archiveRoot) + ".gz"
$destDir = Split-Path $dest
if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir | Out-Null }
# Compress using .NET
$srcStream = [System.IO.File]::OpenRead($_.FullName)
$dstStream = [System.IO.File]::Create($dest)
$gz = New-Object System.IO.Compression.GZipStream($dstStream, [System.IO.Compression.CompressionMode]::Compress)
$srcStream.CopyTo($gz)
$gz.Close(); $srcStream.Close(); $dstStream.Close()
Remove-Item $_.FullName
}
# Remove archives older than 90 days
Get-ChildItem -Path $archiveRoot -Recurse -Filter "*.gz" | Where-Object {
$_.LastWriteTime -lt (Get-Date).AddDays(-90)
} | Remove-Item
Schedule this script with Task Scheduler to run nightly. Combining proper log configuration with automated archival, FREB for error diagnostics, and Log Parser for analysis gives you a comprehensive IIS observability stack on Windows Server 2022.