Ignore persistent SignalR connections in New Relic

Oooh, great question and one I hadn't thought about yet myself. I think what you would have to do is write a custom module, since modules execute before all handlers, that detect that the SignalR AspNetHandler handler is the one being requested and, if so, call the NewRelic IgnoreXXX methods at that point.

Just spitballing (e.g. I haven't tested this) that module might look something like this:

public class SignalRNewRelicIgnoreHttpModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.PostMapRequestHandler += (s, a) =>
            {
                if(HttpContext.Current.Handler is SignalR.Hosting.AspNet.AspNetHandler)
                {
                    NewRelic.Api.Agent.NewRelic.IgnoreTransaction();
                }
            };
    }

    public void Dispose()
    {

    }
}

Then (obviously?) you need to register that module in config like so...

IIS Integrated mode:

<configuration>
  <system.webServer>
    <modules>
        <add name="SignalRNewRelicIgnoreHttpModule" type="WhateverNamespace.SignalRNewRelicIgnoreHttpModule, WhateverAssemblyName" />
    </modules>
   </system.webServer>
</configuration>

IIS Classic mode:

<configuration>
    <system.web>
        <httpModules>
            <add name="SignalRNewRelicIgnoreHttpModule" type="WhateverNamespace.SignalRNewRelicIgnoreHttpModule, WhateverAssemblyName" />
        </httpModules>
    </system.web>
</configuration>

UPDATE: 6/25/2013

As warned by @dfowler in the comments, SignalR has since changed its approach to hosting and instead now relies on Owin based hosting instead. This is great because it decouples SignalR directly from ASP.NET/IIS, but that means the above approach obviously won't work anymore. Instead what you would need to do is to make sure to configure the Owin pipeline with a module like the sample one below (available here in a gist as well) to disable tracing for the pipeline:

public class NewRelicIgnoreTransactionOwinModule
{
    private AppFunc _nextAppFunc;

    public NewRelicIgnoreTransactionOwinModule(AppFunc nextAppFunc)
    {
        _nextAppFunc = nextAppFunc;
    }

    public Task Invoke(IDictionary<string, object> environment)
    {
        // Tell NewRelic to ignore this particular transaction
        NewRelic.Api.Agent.NewRelic.IgnoreTransaction();

        return _nextAppFunc(environment);
    }
}

And then, in your Startup::Configuration method just make sure you add this module to the IAppBuilder before you map any SignalR connections/hubs. That should look something like this:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Use(typeof(NewRelicIgnoreTransactionOwinModule));
        app.MapHubs();
    }
}

Finally, it should be noted that, right now this takes a very simplistic approach that assumes you're not going to have any other Owin requests in your application scope. If you're mixing SignalR into another web app that has other Owin requests this particular module implementation would cause those to be ignored as well, so a more advanced module that maybe checks that the incoming request is actually targeting a SignalR URL would be required. For now, I leave that up to the reader to figure out.

To continue with Micah's answer, here is the custom instrumentation file for ignoring all signalr calls.

Create it to C:\ProgramData\New Relic.NET Agent\Extensions\IgnoreSignalR.xml

<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
    <instrumentation>

        <!-- Optional for basic traces. -->
        <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.IgnoreTransactionTracerFactory">
            <match assemblyName="Microsoft.AspNet.SignalR.Core" className="Microsoft.AspNet.SignalR.PersistentConnection">
                <exactMethodMatcher methodName="ProcessRequest"/>
            </match>
        </tracerFactory>
    </instrumentation>
</extension>

Remember to do iisreset.

It is possible to ignore a transaction via custom instrumentation as well using the IgnoreTransactionTracerFactory. This is particularly useful when you don't want to add the API to your project or when you want to ignore transactions based on a Framework method that you cannot change.

Your custom instrumentation file would look something like:

<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
  <instrumentation>
    <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.IgnoreTransactionTracerFactory">
      <match assemblyName="System.Web.Extensions" className="System.Web.Handlers.ScriptResourceHandler">
        <exactMethodMatcher methodName="Throw404" />
      </match>
    </tracerFactory>
  </instrumentation>
</extension>

If you can find a SignalR framework method that is always called on the request thread (you can only call IgnoreTransaction on the request thread, not on an async thread) you can fill out the assemblyName/className/methodName in the above and it would be the same as calling IgnoreTransaction API inside that method.

This whole issue seems to be caused by the "connect" method on the SignalR controller. I created a hub pipeline module which ignores NewRelic logging by overriding the OnBeforeConnect method.

Somewhere after the maphubs call in your Application_Start() method (global.asax.cs) for your web app, add the following:

GlobalHost.HubPipeline.AddModule(new IgnoreNewRelicConnectionsModule());

Then create this class:

private class IgnoreNewRelicConnectionsModule : HubPipelineModule
{
    protected override bool OnBeforeConnect(IHub hub)
    {
        NewRelic.Api.Agent.NewRelic.IgnoreTransaction();
        return base.OnBeforeConnect(hub);
    }

}

For people using an old version of SignalR here is the xml instrumentation

<tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.IgnoreTransactionTracerFactory">
    <match assemblyName="SignalR.Hosting.AspNet" className="SignalR.Hosting.AspNet.AspNetHandler">
        <exactMethodMatcher methodName="ProcessRequestAsync"/>
    </match>
</tracerFactory>

In SignalR.Core 2.2.2 there are two AuthorizeRequest methods. So New Relic instrument file should looks like this:

<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
    <instrumentation>
        <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.IgnoreTransactionTracerFactory">
            <match assemblyName="Microsoft.AspNet.SignalR.Core" className="Microsoft.AspNet.SignalR.PersistentConnection">
                <exactMethodMatcher methodName="AuthorizeRequest"/>
            </match>
             <match assemblyName="Microsoft.AspNet.SignalR.Core" className="Microsoft.AspNet.SignalR.Hubs.HubDispatcher">
                <exactMethodMatcher methodName="AuthorizeRequest"/>
            </match>
        </tracerFactory>
    </instrumentation>
</extension>

Putting this file to "C:\ProgramData\New Relic.NET Agent\Extensions" resolve problem.

    public Task Invoke(IDictionary<string, object> environment)
    {
        object value = "";

        //Check if the OWIN key is present
        if (environment.ContainsKey("owin.RequestPath"))
        {
            //Get the value of the key
            environment.TryGetValue("owin.RequestPath", out value);
            //This will block all signalr request, but we can configure according to requirements
            if (value.ToString().Contains("/signalr"))
            {
                // Tell NewRelic to ignore this particular transaction
                NewRelic.Api.Agent.NewRelic.IgnoreTransaction();
                NewRelic.Api.Agent.NewRelic.IgnoreApdex();
            }
        }
        return _nextAppFunc(environment);
    }