Ignore persistent SignalR connections in New Relic
Asked Answered
S

8

29

Where should I call NewRelic.Api.Agent.NewRelic.IgnoreApdex() or NewRelic.Api.Agent.NewRelic.IgnoreTransaction() in my SignalR hubs to prevent long-running persistent connections from overshadowing my application monitoring logs?

New Relic Screenshot of SignalR dominating monitoring

Scala answered 21/11, 2012 at 9:50 Comment(0)
C
9

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.

Calbert answered 21/11, 2012 at 18:1 Comment(7)
Calling IgnoreTransaction should also remove the transaction from Apdex calculation (effectively calling IgnoreApdex).Paperboy
Yeah I was thinking about that this morning, I'll remove the IgnoreApdex call from the sample.Calbert
It worked perfectly. I just had some trouble getting the HttpModule to run on my development server via web.config, so I added a PreStart event using WebActivator to explicitly load it.Scala
This won't work well in the next version as the handler will change. It's not good to rely on internal details like that in general :)Undesigned
So with this in mind, will there be an extensibility point to get at this level? Should I file an issue on GitHub?Calbert
The updated solution ignored all NewRelic transactions. Found link to exclude only signalROverfeed
looks like the link @Overfeed posted has a trailing slash which GitHub doesn't like. proper link: darrenkopp.com/posts/2014/05/07/Ignoring-SignalR-in-NewRelicBritton
M
16

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.

Mckean answered 11/11, 2014 at 12:43 Comment(4)
for completeness, what should be the name of this file?Humble
@ArthurStankevich You can name it like you want it. Just make sure it ends with .xml. See the New Relic DocumentationJakie
any ideas on how to make this work with an Azure website as we don't have access to the file systemArborization
@CamLangsford it's easy. from open Azure Portal and go to the Web App. Now look for App Service Editor which will open your whole code base, ready for editing. Now browse to newrelic\extension and add IgnoreSignalR.xml there. If you dont find that portal, it means you havent setup New Relic in this Web App. Easiest solution I found is to instal New Relic Azure Site Extension siteextensions.net/packages/NewRelic.Azure.WebSitesLepus
C
9

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.

Calbert answered 21/11, 2012 at 18:1 Comment(7)
Calling IgnoreTransaction should also remove the transaction from Apdex calculation (effectively calling IgnoreApdex).Paperboy
Yeah I was thinking about that this morning, I'll remove the IgnoreApdex call from the sample.Calbert
It worked perfectly. I just had some trouble getting the HttpModule to run on my development server via web.config, so I added a PreStart event using WebActivator to explicitly load it.Scala
This won't work well in the next version as the handler will change. It's not good to rely on internal details like that in general :)Undesigned
So with this in mind, will there be an extensibility point to get at this level? Should I file an issue on GitHub?Calbert
The updated solution ignored all NewRelic transactions. Found link to exclude only signalROverfeed
looks like the link @Overfeed posted has a trailing slash which GitHub doesn't like. proper link: darrenkopp.com/posts/2014/05/07/Ignoring-SignalR-in-NewRelicBritton
C
8

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.

Capet answered 21/2, 2014 at 18:22 Comment(1)
This is way better, no need to re-deployMandell
P
5

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);
    }

}
Pedro answered 8/4, 2013 at 11:38 Comment(1)
eh, no i'd block all signalr trafficUndesigned
S
1

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>
Stepha answered 31/3, 2016 at 13:50 Comment(1)
How to check SignalR version in my web application?Picayune
V
1

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.

Valerlan answered 13/12, 2017 at 12:45 Comment(0)
C
0
    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);
    }
Contrail answered 24/2, 2014 at 13:12 Comment(0)
M
0

I was unable to ignore ASP.NET Core SignalR requests with NewRelic extensions XML files. So, inspired by @Pali's answer, this middleware is working for ASP.NET Core SignalR :

public class IgnoreSignalrNewRelicMiddleware
{
    private readonly RequestDelegate _next;

    public IgnoreSignalrNewRelicMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        //This will block all signalr request, but we can configure according to requirements
        if (httpContext.Request.Path.Value?.Contains("/signalr") ?? false)
        {
            // Tell NewRelic to ignore this particular transaction
            NewRelic.Api.Agent.NewRelic.IgnoreTransaction();
            NewRelic.Api.Agent.NewRelic.IgnoreApdex();
        }

        // Call the pipeline ...
        await _next(httpContext);
    }
}
Marikomaril answered 27/7, 2022 at 13:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.