This article describes how to keep SignalR errors from filling up your ELMAH log.
I maintain a web site that uses SignalR to send notification messages to logged in users and ELMAH to catch unhandled exceptions.
From the SignalR repository: ASP.NET SignalR is a library for ASP.NET developers that makes it incredibly simple to add real-time web functionality to your applications. What is “real-time web” functionality? It’s the ability to have your server-side code push content to the connected clients as it happens, in real-time.
From the ELMAH home page: ELMAH (Error Logging Modules and Handlers) is an application-wide error logging facility that is completely pluggable. It can be dynamically added to a running ASP.NET web application, or even all ASP.NET web applications on a machine, without any need for re-compilation or re-deployment.
After bringing ELMAH up live in the production system and running for a while, I began to realize that almost all of the messages in ELMAH were due to SignalR client disconnects. While it’s true that these are unhandled exceptions in SignalR, they do not cause problems for the user, so I don’t care to review them. Worse yet, the quantity of these messages was so large that they were camouflaging the few errors that I did need to review. Here’s an example (there is an error in here I need to see):
Researching the Problem
I did a bit of searching and didn’t find much useful and as typically happens in software development, more important issues arose so I paused my research.
However, I’m very big on proactive management of systems–I want to know there’s a problem before the users know. I inherited the maintenance of this system and it the level of exception handling and logging was decent, but it is by no means complete. Because of this, ELMAH becomes the last line of defense to keep unhandled exceptions from going unnoticed.
When I started looking into the issue again, I noticed similar complaints on the SignalR issue board. These issues did not have a resolution and had been closed when the SignalR team performed what they called a “backlog bankruptcy” closing most open tickets. So I opened a new SignalR issue and referenced one of the old unresolved tickets.
Within a week, someone from the SignalR team asked me if ELMAH’s “filtering support” would be sufficient to resolve my issue. Hmmmm… In all my searching I never noticed anything about ELMAH filtering.
You can read about ELMAH filtering here, but meh, the documentation is not great. It has a decent number of examples, but it doesn’t put stuff together in a way that made the solution obvious to me. Also, some of the explanation is written out of order, leaving the most important bits of information until the end of the discussion, so with my limited attention span, I moved on.
I found a few StackOverflow articles and was eventually able to piece together a solution to the problem.
First, make sure that you have the web.config set up correctly to enable ELMAH filtering by looking at the top part of this article on the ELMAH site.
Once you have done this, add the following configuration to the web.config file in the “elmah” section:
<elmah> <!-- Other settings omitted for this illustration --> <errorFilter> <test> <or> <and> <equal binding="HttpStatusCode" value="500" type="Int32" /> <regex binding="Exception.Message" pattern="The remote host closed the connection\. The error code is 0x80070057\..*" /> <regex binding="Context.Request.ServerVariables['URL']" pattern="/signalr/.*" /> </and> <and> <equal binding="HttpStatusCode" value="500" type="Int32" /> <regex binding="Exception.Message" pattern="The client disconnected\..*" /> <regex binding="Context.Request.ServerVariables['URL']" pattern="/signalr/.*" /> </and> </or> </test> </errorFilter> </elmah>
The way the filter works is that if the contents of the “test” section evaluates to true, then the entry is filtered out of the log (i.e. it’s not saved to the log). Because of this, I would guess that most real-world filters would have an “<or>” block surrounding multiple conditions just as is shown in this example.
The logic here is that if the error matches this, or this, or this, then ignore it.
The first mistake I made when setting this up was not realizing I needed to surround the “<and>” blocks with the “<or>”. It looked like it was kind of working, because it did filter the first described error message, but not the second. If you make this mistake, the additional “<and>” blocks are just ignored.
When setting up the filters, I wanted to avoid false positive matches that could cause errors I wanted to see to be filtered and lost. I knew that all of the errors I wanted to filter out were caused when accessing URIs starting with “/signalr/”, so I went on a search to try to figure out how to match items in the HTTP context object.
I think this was the article that helped me figure out how to filter on the URI:
This, plus I looked in the “AllXml” column of the ELMAH_Error table in SQL Server to verify which server variable I wanted to use.
Looking at the first of the two “<and>” blocks, here is a description of each piece:
<equal binding="HttpStatusCode" value="500" type="Int32" />
This matches if the status code is 500 (Internal Server Error). Note that ELMAH filtering will treat elements as string unless you set the “type” to something else.
<regex binding="Exception.Message" pattern="The remote host closed the connection\. The error code is 0x80070057\..*" />
This attempts to match the exception message with a regular expression.
<regex binding="Context.Request.ServerVariables['URL']" pattern="/signalr/.*" />
Finally, this is the “secret sauce” that avoids having a false-positive match and dropping an error you didn’t intend. It verifies that the request URL starts with the string “/signalr/”.
This was yet another case of all the pieces being out there somewhere on the Internet, but they weren’t all in one place. My ELMAH log is no longer getting loaded down with SignalR errors and now it’s on to tracking down real issues.
I hope that this article helps someone else out.