.NET custom instrumentation

New Relic collects and reports information on web browser transactions and background tasks. New Relic normally produces complete information right out of the box without any need to modify your application code. However, if New Relic does not support your framework, you may need to add custom instrumentation.

New Relic uses method tracers to implement custom instrumentation. A method tracer is a software probe that you can put on a method of any class. New Relic's .NET agent loads the instrumentation directives that define which methods should be traced from all xml files in the extensions directory, and CoreInstrumentation.xml defines the agent's built-in instrumentation set.

Collecting too many metrics can impact the performance of both your application and New Relic. To avoid potential data problems, try to keep the total number of unique metrics introduced by custom instrumentation under 2000.

Add custom instrumentation

Extension files define a number of tracer factories in an instrumentation element. Each tracer factory contains match elements which define the assembly, fully qualified class name, and method name to match. To define new custom instrumentation:

  1. Create a new .xml file in the extensions directory located in C:\ProgramData\New Relic\.NET Agent\Extensions. The .NET agent reads every xml file in this extensions directory to define its instrumentation set.
  2. Using an XML-aware editor such as Visual Studio, edit your custom instrumentation file to specify the methods you want to instrument. Use the tracer definitions in the distributed xml files and the sample as an example.

    Do not modify the distributed xml files. These files are overwritten whenever the agent is upgraded.

  3. Validate your .xml instrumentation file against extension.xsd (located in the extensions directory).
  4. Restart the host process for your application. If your app is IIS-hosted, restart IIS. Otherwise, restart the host process (for example, the WFC service) or your application.

If you are creating custom instrumentation for a non-IIS application (such as a console application or background process) you must also create custom transactions to contain the methods you instrument. Custom methods instrumented outside of a transaction will not be reported to New Relic.

Ignore a transaction

You can stop a transaction from being reported via a custom instrumentation file. Whenever an ignored method is called, the .NET agent ignores the entire parent transaction. This is the same as calling IgnoreTransaction(). To do so, add custom instrumentation, and add a tracerFactory whose name is NewRelic.Agent.Core.Tracer.Factories.IgnoreTransactionTracerFactory:

  <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.IgnoreTransactionTracerFactory">
    <match assemblyName="System.Web.Extensions" className="System.Web.Handlers.ScriptResourceHandler">
     <exactMethodMatcher methodName="Throw404" />
    </match>
  </tracerFactory>

Example MyInstrumentation.xml

This example instruments two methods and ignores another method:

  • Instrument: CustomInstrumentDemo.Controllers.FirstController.FirstExample()
  • Instrument: CustomInstrumentDemo.Controllers.SecondController.SecondExample()
  • Ignore: CustomInstrumentDemo.Controllers.SecondController.ThirdExample()
  • Instrument: CustomInstrumentDemo.Controllers.SecondController.FourthExample(int id, string name)

To implement this custom instrumentation scheme, use the following example file and instrumented methods:

Example custom instrumentation file

The following is an example custom instrumentation file named MyInstrumentation.xml:

<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
  <instrumentation>
    <!-- instrument CustomInstrumentDemo.Controllers.FirstController.FirstExample and creates metric named Custom/Foo1 -->
    <tracerFactory metricName="Custom/Foo1">
      <match assemblyName="CustomInstrumentDemo" className="CustomInstrumentDemo.Controllers.FirstController">
        <exactMethodMatcher methodName="FirstExample" />        
      </match>
    </tracerFactory>
     <!-- instrument CustomInstrumentDemo.Controllers.SecondController.SecondExample -->
    <tracerFactory>
      <match assemblyName="CustomInstrumentDemo" className="CustomInstrumentDemo.Controllers.SecondController">
        <exactMethodMatcher methodName="SecondExample" />
      </match>
    </tracerFactory>
    <!-- ignore CustomInstrumentDemo.Controllers.SecondController.ThirdExample -->
    <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.IgnoreTransactionTracerFactory">
      <match assemblyName="CustomInstrumentDemo" className="CustomInstrumentDemo.Controllers.SecondController">
        <exactMethodMatcher methodName="ThirdExample" />
      </match>
    </tracerFactory>
    <!-- instrument CustomInstrumentDemo.Controllers.SecondController.FourthExample and creates metric named Custom/{value},
         where {value} is the value of the first string parameter of the instrumented method
         (in this case, the first string parameter is "name"). -->
    <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.CustomSegmentTracerFactory">
      <match assemblyName="CustomInstrumentDemo" className="CustomInstrumentDemo.Controllers.SecondController">
        <exactMethodMatcher methodName="FourthExample" />
      </match>
    </tracerFactory>
  </instrumentation>
</extension>
Example methods to be instrumented

This code contains the three methods specified by the custom instrumentation file above:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Threading;

namespace CustomInstrumentDemo.Controllers
{

    public class FirstController : Controller
    {
    
        public ActionResult Foo1()
        {
            ViewBag.Message = "Your Sample Page";

            FirstExample();
            
            return View();
        }

        public void FirstExample()
        {
            int firstVar = 1;
 
            for (int i = 0; i <= 500; i++)
                {
                    firstVar *= 5;
                    Thread.Sleep(50);
                } 

        }
    }

    public class SecondController : Controller
    {

        public ActionResult Foo2()
        {
            ViewBag.Message = "This view will include detailed information on the SecondExample method";

            SecondExample();

            return view;
        }

        public ActionResult Foo3()
        {
            ViewBag.Message = "This view will be ignored because of the includsion of the ThirdExample method";

            ThirdExample();
        }

        public void SecondExample()
        {
            int secondVar = 2;

            using (var connection = new SqlConnection(ConnectionStrings["MsSqlConnection"].ConnectionString))
            {
                connection.Open();
                using (var command = new SqlCommand("SELECT * FROM table", connection))
                using (var reader = command.ExecuteReader())
                {
                    reader.Read();
                }
            }

        }

        public void ThirdExample()
        {
            try
            {
                var ImNotABool = "43";
                bool.Parse(ImNotABool);
            }
            catch (Exception ex)
            {
                NewRelic.Api.Agent.NewRelic.NoticeError(ex);
            }

        }

        public void FourthExample(int id, string name)
        {
            Console.WriteLine("The ID passed in was " + id + " and the name passed in was " + name);
        }
    }
}

Name metrics

Metrics created from tracers will be named using the class name and method name of the matched method. You can override this name with the metricName attribute. Begin metricName with Custom/ (for example, metricName="Custom/OrderSubmissions").

<!-- instruments MyCompany.Order.Submit() and creates a metric named Custom/OrderSubmissions -->
  <tracerFactory metricName="Custom/OrderSubmissions">
  <match assemblyName="MyCompany" className="MyCompany.Order">
    <exactMethodMatcher methodName="Submit" />
  </match
</tracerFactory>

Name transactions

The agent names transactions using the tracer in the transaction with the highest naming priority. Web transactions may be named using the http handler, asp name, MVC controller name, or web service name, depending on the tracers invoked in the transaction's execution. Background transactions with no tracer that explicitly names the transaction are rolled up into a single transaction name. Use the transactionNamingPriority attribute to tell the agent to give a tracer transaction naming priority.

Valid values are 1 to 7, where 7 takes precedence over 1 to 6. Also, the metricName attribute must begin with Custom/ (for example, metricName="Custom/instance").

<!-- instructs the agent to create a metric for MyControllerBase.Execute and to name the transaction using this tracer's metric name -->
<tracerFactory metricName="Custom/instance" transactionNamingPriority="7">
  <match assemblyName="MyCompany" className="MyCompany.MyControllerBase">
    <exactMethodMatcher methodName="Execute" />
  </match>
</tracerFactory>

Instrument async methods in IIS apps

You can instrument asynchronous methods (those declared with the async modifier) for IIS hosted applications. Non-IIS applications are not yet supported. The following XML file instruments the async method Bar3Async and adds it to the enclosing transaction's breakdown table and transaction traces.

<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
  <instrumentation>
    <!-- Instrument 0 or more methods called by the trigger method. These methods appear in the transaction breakdown table and in transaction traces. -->
    <tracerFactory name="NewRelic.Providers.Wrapper.CustomInstrumentationAsync.DefaultWrapperAsync">
      <match assemblyName="Foo" className="Foo.Bar">
        <exactMethodMatcher methodName="Bar3Async" />
      </match>
    </tracerFactory>
  </instrumentation>
</extension>

Troubleshooting

The .NET agent will write a log message to NewRelic.Profiler.####.log (where #### is the PID of the instrumented process) as it rewrites methods. This helps to verify that custom instrumentation is being read and that the proper methods are being instrumented.

Avoid using the name attribute of the tracerFactory element in custom instrumentation. For more information, review the extension.xsd schema file in the agent directory.

For more help

Additional documentation resources include:

Join the discussion about .NET monitoring in the New Relic Online Technical Community! The Technical Community is a public platform to discuss and troubleshoot your New Relic toolset.

If you need additional help, get support at support.newrelic.com.