I'm currently consulting over @OnTrees, @OnTrees we use raygun.io for error logging. If you don't know what raygun is - raygun logs errors and produces excellent trending reports. It's a great tool because lets be honest no matter how good your test coverage is exceptions happen.
We use it in production to help prioritise and pinpoint exceptions, raygun is brilliant for this as it shows you a count and when the exception last occurred, everything you need for prioritisation decisions. Raygun is clever enough to know when an exception has been resolved or if it has been reintroduced by a new build, which is a neat feature.
Anyway, that's enough of a pitch, I'm not affiliated with the guys at raygun.io I just like the product, if you want to find out more check out Troy Hunt's post.
For a web application, Raygun4Net logs everything you need for troubleshooting, however, for our single page app it was logging a bit too much. One of the main offenders is Raygun4Net logs HTTP RawData, the problem is with an SPA this is the full json body, which for us will contain sensitive data.
After a bit of research, I found it is trivial to remove Server Variables, Form, Header and Cookie values using the web.config. However, I couldn't find a way to stop the .Net client logging RawData/http body. Raygun4Net is open source, so it was easy to extend.
Below is the extension we use:
Here create a custom RaygunRequestMessage and related extension method to remove the Authorization header, all QueryString, Form, and Cookie values, as well as RawData (including the http body) which was causing us issues with logging sensitive data.
using System.Collections.Generic;
using System.Web;
using Mindscape.Raygun4Net.Messages;
namespace Logging.Extensions
{
public static class Raygun4NetExtensions
{
public static void SetNonSensitiveHttpDetails(this RaygunMessage message)
{
var context = HttpContext.Current;
if (context == null)
return;
HttpRequest request = null;
try
{
request = context.Request;
}
catch (HttpException)
{
}
message.Details.Request = new SensitiveRaygunRequestMessage(request);
}
public class SensitiveRaygunRequestMessage : RaygunRequestMessage
{
public SensitiveRaygunRequestMessage(HttpRequest request) : base(request, new List<string>())
{
//Remove sensitive data that Raygun logs by default
Data.Remove("HTTP_AUTHORIZATION");
Headers.Remove("Authorization");
QueryString = new Dictionary<string, string>();
Form = new Dictionary<string, string>();
Cookies = new List<string>();
RawData = string.Empty;
}
}
}
}
Here we new up a RaygunMessage and then call our SetNonSensitiveHttpDetails extension method which replaces the RaygunRequestMessage with our own SensitiveRaygunRequestMessage.
using System;
using System.Collections.Generic;
using Logging.Extensions;
using Mindscape.Raygun4Net;
namespace Logging
{
public class RaygunLogger
{
private readonly RaygunClient _raygun;
private readonly string _application;
private readonly string _buildNumber;
public RaygunLogger(RaygunClient raygun, string application, string buildNumber)
{
_raygun = raygun;
_application = application;
_buildNumber = buildNumber;
}
public void Error(Exception ex)
{
var message = RaygunMessageBuilder.New
.SetEnvironmentDetails()
.SetMachineName(Environment.MachineName)
.SetExceptionDetails(ex)
.SetClientDetails()
.SetVersion("Build: " + _buildNumber)
.SetTags(new[] {_application})
.SetUserCustomData(new Dictionary<string,string>())
.Build();
message.SetNonSensitiveHttpDetails();
_raygun.Send(message);
}
}
}
It should be easy to customise this extension for your own needs.