I ran across a great article the other day on HN about how to log client-side errors using Google Analytics. This is brilliant, and I've already implemented it for my biggest site. I'd like to hope everyone is logging their server-side errors too! Sadly, I bet many web developers aren't because I know that I wasn't doing it for years. When I first did, I quickly realized it was an invaluable tool for ensuring the robustness of my websites, because I immediately became aware of several page errors and bugs I had no idea existed in my apps. What happens when a user gets an error on your site? Do you have a system in place to tell you about it? Because I guarantee you can't test every possible use case on your webapp if it's even moderately complex. Here's how I monitor server-side errors in IIS.
You can define a custom error page for an individual website, or for all sites on your web server. To do it for just one site, you right-click the website in IIS Manager, and visit the Custom Errors tab. To do it for all sites, right-click the Web Sites folder in IIS Manager and go to the same tab: Custom Errors.
Scroll down in the list until you find the entry for the 500 HTTP Error. Hit the Edit button, then change the Message type to "URL" and the File to "/500.asp" (or whatever you'd like as the name of the page to handle the error).
You then have to create this page, of course (or ideally create it before you assign it as the handler for the 500 errors). What I did was define "/500.asp" as the custom 500 error handler for all sites on my web server, then create an identical, short 500.asp page for each site that uses an include directive to another common 500.asp page outside of any website folder. So, each website has a 500.asp page in its root that has only this code:
This code points to a file outside the web root, namely C:\Inetpub\500.asp. This master 500 controller page has the real error logging code:
<% set objErrorInfo = Server.GetLastError SERVER_NAME = Request.ServerVariables("SERVER_NAME") PATH_INFO = Request.ServerVariables("PATH_INFO") QUERY_STRING = Request.ServerVariables("QUERY_STRING") PAGE_URL = "http://" & SERVER_NAME & PATH_INFO if left(QUERY_STRING,4) = "404;" then PAGE_URL = mid(QUERY_STRING,5) PAGE_REL = replace(replace(PAGE_URL,"http://" & SERVER_NAME & ":80",""),"http://" & SERVER_NAME,"") PAGE_URL_SHORT = replace(replace(PAGE_URL,"http://",""),":80/","/") errorStringStr = objErrorInfo.File & _ ", line: " & objErrorInfo.Line & _ ", error: " & objErrorInfo.Number & " " & objErrorInfo.Description & _ ", " & objErrorInfo.ASPDescription & objErrorInfo.Category errorLog "Error on " & PAGE_URL_SHORT & "<br /><br />" & _ "Page: " & page & " (" & PAGE_REL & ")<br />" & _ errorStringStr & "<br /><br />" & _ "Failed Query: " & session("error_query") & "<br /><br />" session("error_query") = "" %> <h1>Oops! An error occurred. ☹</h1> <p>Sorry for the inconvenience! A notification has been sent to the administrative team with details about the error so we can try to fix it as soon as possible.</p> <h2>Error Details</h2> <%=errorStringStr%>
The function errorLog is defined elsewhere that records the error information to a database table so I can review it later. You could also have it send you an email about the error, or do something else to record or notify you about the error.
IIS actually calls the Server.Transfer method to the 500.asp page when an error occurs, so any variable information is lost as it calls a new page - so I store extra information about the database query that was attempted in Session("error_query") so I can access and record it on the error page.
You can define a custom error page for a 404 (page not found) error in the same way. This has two benefits: first, you can provide a predefined 404 page that is much friendlier than the default IIS 404 page, and second, you can use the 404 page to handle custom, dynamic URLs for pages on your site.
For example, if you don't want .html or .asp extensions on pages on your site, or want to specify page URLs programmatically, this is a good way to do it. When someone accesses www.yourdomain.com/todays-blog-post, it will get redirected to the custom 404 page which can then lookup your database to find and return the blog post matching that URL. If there is no actual blog post with that URL, then the custom 404 page can return page headers indicating that it is a 404 error and a friendly message that the page was not found.
You can also on your custom 404 page (assuming it is an actual 404, if it couldn't find a dynamic page on your site with the given custom URL) provide additional resources to the user who may have arrived at an expired link or mistyped what they wanted. You can put a sitemap on your 404 page, or inline a Google Custom Search engine that will let them search your site for what they want. As long as you have sufficient content on your page so that they can get contextual information, google even lets you put adsense ads on your 404 page.