Troubleshooting IIS - friendly reinterpretation of HTTP Status Codes and Win32 errors.
Recently I investigated an IIS issue. As part of my investigation I had to analyze W3 logs. While doing so, I realized that IIS 7.0 introduced so many sub-status codes that I was not able to reinterpret them in my head any more. Luckily, I recalled that logparser had an ability to perform variety of transformations. So I gave it a try. Below is a query that made my life easier. Some of you may find it similarly useful.
Logparser SQL script
select cs-uri-stem, STRCAT(STRCAT(TO_STRING(sc-status),'.'),TO_STRING(sc-substatus)) as ss, CASE ss when'200.0' then'HttpStatusOk' when'201.0' then'HttpStatusCreated' when'204.0' then'HttpStatusNoContent' when'206.0' then'HttpStatusPartialContent' when'207.0' then'HttpStatusMultiStatus' when'301.0' then'HttpStatusMovedPermanently' when'302.0' then'HttpStatusRedirect' when'307.0' then'HttpStatusMovedTemporarily' when'304.0' then'HttpStatusNotModified' when'400.0' then'HttpStatusBadRequest' when'400.1' then'HttpStatusInvalidDestination' when'400.2' then'HttpStatusInvalidDepth' when'400.3' then'HttpStatusInvalidIf' when'400.4' then'HttpStatusInvalidOverwrite' when'400.5' then'HttpStatusInvalidTranslate' when'400.6' then'HttpStatusInvalidRequestBody' when'400.7' then'HttpStatusInvalidContentLength' when'401.0' then'HttpStatusUnauthorized' when'401.1' then'HttpStatusBadLogon' when'401.2' then'HttpStatusDeniedConfig' when'401.3' then'HttpStatusDeniedResource' when'401.4' then'HttpStatusDeniedFilter' when'401.5' then'HttpStatusDeniedApplication' when'403.0' then'HttpStatusForbidden' when'403.1' then'HttpStatusExecAccessDenied' when'403.2' then'HttpStatusReadAccessDenied' when'403.3' then'HttpStatusWriteAccessDenied' when'403.4' then'HttpStatusSSLRequired' when'403.5' then'HttpStatusSSL128Required' when'403.6' then'HttpStatusIPAddressReject' when'403.7' then'HttpStatusCertRequired' when'403.8' then'HttpStatusSiteAccessDenied' when'403.9' then'HttpStatusTooManyUsers' when'403.11' then'HttpStatusPasswordChange' when'403.12' then'HttpStatusMapperDenyAccess' when'403.13' then'HttpStatusCertRevoked' when'403.14' then'HttpStatusDirBrowsingDenied' when'403.16' then'HttpStatusCertInvalid' when'403.17' then'HttpStatusCertTimeInvalid' when'403.18' then'HttpStatusAppPoolDenied' when'403.19' then'HttpStatusInsufficientPrivilegeForCgi' when'403.20' then'HttpStatusPassportLoginFailure' when'403.21' then'HttpStatusSourceAccessDenied' when'403.22' then'HttpStatusInfiniteDepthDenied' when'404.0' then'HttpStatusNotFound' when'404.2' then'HttpStatusDeniedByPolicy' when'404.3' then'HttpStatusDeniedByMimeMap' when'404.4' then'HttpStatusNoHandler' when'404.5' then'HttpStatusDeniedByUrlSequence' when'404.6' then'HttpStatusDeniedByVerb' when'404.7' then'HttpStatusDeniedByFileExtension' when'404.8' then'HttpStatusHiddenSegment' when'404.9' then'HttpStatusFileAttributeHidden' when'404.10' then'HttpStatusRequestHeaderTooLong' when'404.11' then'HttpStatusUrlDoubleEscaped' when'404.12' then'HttpStatusUrlHasHighBitChars' when'404.13' then'HttpStatusContentLengthTooLarge' when'404.14' then'HttpStatus404UrlTooLong' when'404.15' then'HttpStatusQueryStringTooLong' when'404.16' then'HttpStatusStaticFileDav' when'404.17' then'HttpStatusPreconditionedHandler' when'404.18' then'HttpStatusDeniedByQueryStringSequence' when'404.19' then'HttpStatusDeniedByFilteringRule' when'405.0' then'HttpStatusMethodNotAllowed' when'406.0' then'HttpStatusNotAcceptable' when'407.0' then'HttpStatusProxyAuthRequired' when'409.0' then'HttpStatusConflict' when'412.0' then'HttpStatusPreconditionFailed' when'413.0' then'HttpStatusEntityTooLarge' when'414.0' then'HttpStatusUrlTooLong' when'415.0' then'HttpStatusUnsupportedMediaType' when'416.0' then'HttpStatusRangeNotSatisfiable' when'417.0' then'HttpStatusExpectationFailed' when'423.0' then'HttpStatusLockedError' when'424.0' then'HttpStatusFailedDependency' when'500.0' then'HttpStatusServerError' when'500.16' then'HttpStatusUNCAccess' when'500.19' then'HttpStatusBadMetadata' when'500.21' then'HttpStatusHandlersModule' when'500.22' then'HttpStatusAspnetModules' when'500.23' then'HttpStatusAspnetHandlers' when'500.24' then'HttpStatusAspnetImpersonation' when'501.0' then'HttpStatusNotImplemented' when'502.0' then'HttpStatusBadGateway' when'502.1' then'HttpStatusTimeout' when'502.2' then'HttpStatusPrematureExit' when'502.3' then'HttpStatusForwarderConnectionError' when'503.0' then'HttpStatusServiceUnavailable' when'503.2' then'HttpStatusAppConcurrent' when'504.0' then'HttpStatusGatewayTimeout' when'507.0' then'HttpStatusInsufficientStorage' END as w3-status-details, CASE sc-win32-status WHEN 0 then'' WHEN 2148074254 then 'handshake in progress' ELSE WIN32_ERROR_DESCRIPTION(sc-win32-status) END as win32-error, sc-win32-status from u_ex*.log |
What does the above query do?
- it concatenates the HTTP Status and HTTP Substatus and then translates it to a readable string. Some of the text translations will be easier to understand than others. I harvested all the sub-statuses known to IIS 7.0. But there may be other sub-statuses raised by other handlers.
- it attempts to translate sc-win32-status to a readable string.
- In the case of SEC_E_NO_CREDENTIALS error (2148074254) it will interpret error as "handshake in progress". This error will be seen when windows Authentication is used and actual authentication requires additional roundtrip between client and server. Intermediate responses from server have status 401, sub-status 1 and Win32 error is set to 2148074254.
Steps to use the query
- If you don't have logparser on your machine yet then install it from:
http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-8d975cf8c07^&displaylang=en.
The default install location of logparser v2.2 is "C:\Program Files\Log Parser 2.2\" for X86 or "C:\Program Files (x86)\Log Parser 2.2\" for AMD64 - save the above logparser SQL statement to a file w3log_suberrors.sql.
- run the following command to execute the query using the rather convenient data grid. Example assumes the default W3C logging format.
logparser file:w3log_suberrors.sql -o:DATAGRID -rtp 20 - (optional) customize to fit your needs
- the set of fields you want to observe,
- choice of log files (in the "from" clause)
- logging format (though it will require you to modify the field names)
Please let me know if you have suggestions what else to reinterpret to make the log analysis little bit easier.