Question

I am trying to monitor methods inside a .NET app which is a background process using New Relic for which I know I need to add Custom Instrumentation.

I have re-installed the .NET Agent, and after configuring "Instrument all .NET Applications", and making changes within the app.config and newrelic.config files, I am getting basic data of the background process in the new relic dashboard.

Now, to add Custom Instrumentation, I have added another instrumentation config file inside the extensions directory. Restarted the app, but still can't see the new/custom methods I am trying to monitor.

This is my instrumentation file MyInstrumentation.xml

<?xml version="1.0" encoding="utf-8"?>

<!-- instrument EngineService.BestAgentSolver.Solve inside EngineService.BestAgentSolver -->
<tracerFactory metricName="Cast-a-Net.EngineService.BestAgentSolver.Solve-Metric">
  <match assemblyName="Cast-a-Net.EngineService" className="Cast-a-Net.EngineService.BestAgentSolver">
    <exactMethodMatcher methodName="Solve" />
  </match>
</tracerFactory>

<!-- instrument EngineService.SessonManager.BroadcastLeadCounts inside EngineService.SessionManager -->
<tracerFactory metricName="Cast-a-Net.EngineService.SessionManager.BroadcastLeadCounts-Metric">
  <match assemblyName="Cast-a-Net.EngineService" className="Cast-a-Net.EngineService.SessionManager">
    <exactMethodMatcher methodName="BroadcastLeadCounts" />
  </match>
</tracerFactory>

<tracerFactory metricName="myapp.Web.Controllers.CallListController.ActionResult-Metric">
  <match assemblyName="myapp.Web" className="myapp.Web.Controllers.CallListController">
    <exactMethodMatcher methodName="ActionResult" />
  </match>
</tracerFactory>

Am I missing a step or doing something wrong?

Was it helpful?

Solution

Custom instrumentation in the .NET agent works with web transactions that use the HttpContext object. Our .NET agent API, on the other hand, allows you to collect metrics that can be displayed in a custom dashboard. In particular, RecordMetric, RecordResponseTimeMetric, and IncrementCounter are useful because they work with non-web applications.

Starting with version 2.24.218.0 of the .NET agent however, a new feature can be used to create transactions where the agent would normally not do so. This is a manual process via a custom instrumentation file.

Create a custom instrumentation file named, say CustomInstrumentation.xml, in C:\ProgramData\New Relic.NET Agent\Extensions along side CoreInstrumentation.xml. Add the following content to your custom instrumentation file:

<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
  <instrumentation>
    <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.BackgroundThreadTracerFactory" metricName="Category/Name">
      <match assemblyName="AssemblyName" className="NameSpace.ClassName">
        <exactMethodMatcher methodName="MethodName" />
      </match>
    </tracerFactory>
  </instrumentation>
</extension>

You must change the attribute values Category/Name, AssemblyName, NameSpace.ClassName, and MethodName above:

The transaction starts when an object of type NameSpace.ClassName from assembly AssemblyName invokes the method MethodName. The transaction ends when the method returns or throws an exception. The transaction will be named Name and will be grouped into the transaction type specified by Category. In the New Relic UI you can select the transaction type from the Type drop down menu when viewing the Monitoring > Transactions page.

Note that both Category and Name must be present and must be separated by a slash.

As you would expect, instrumented activity (methods, database, externals) occurring during the method's invocation will be shown in the transaction's breakdown table and in transaction traces.

Here is a more concrete example. First, the instrumentation file:

<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
  <instrumentation>
    <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.BackgroundThreadTracerFactory" metricName="Background/Bars">
      <match assemblyName="Foo" className="Foo.Bar">
        <exactMethodMatcher methodName="Bar1" />
        <exactMethodMatcher methodName="Bar2" />
      </match>
    </tracerFactory>
    <tracerFactory metricName="Custom/some custom metric name">
      <match assemblyName="Foo" className="Foo.Bar">
        <exactMethodMatcher methodName="Bar3" />
      </match>
    </tracerFactory>
  </instrumentation>
</extension>

Now some code:

var foo = new Foo();
foo.Bar1(); // Creates a transaction named Bars in category Background
foo.Bar2(); // Same here.
foo.Bar3(); // Won't create a new transaction.  See notes below.

public class Foo
{
    // this will result in a transaction with an External Service request segment in the transaction trace
    public void Bar1()
    {
        new WebClient().DownloadString("http://www.google.com/);
    }

    // this will result in a transaction that has one segment with a category of "Custom" and a name of "some custom metric name"
    public void Bar2()
    {
        // the segment for Bar3 will contain your SQL query inside of it and possibly an execution plan
        Bar3();
    }

    // if Bar3 is called directly, it won't get a transaction made for it.
    // However, if it is called inside of Bar1 or Bar2 then it will show up as a segment containing the SQL query
    private void Bar3()
    {
        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();
            }
        }
    }
}

Here is a simple console app that demonstrates Custom Transactions:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Custom Transactions");
            var t = new CustomTransaction();
            for (int i = 0; i < 100; ++i )
                t.StartTransaction();
        }
    }
    class CustomTransaction
    {
        public void StartTransaction()
        {
            Console.WriteLine("StartTransaction");     
            Dummy();
        }
        void Dummy()
        {
            System.Threading.Thread.Sleep(5000);
        }
    }

}

Use the following custom instrumentation file:

<?xml version="1.0" encoding="utf-8"?>
<extension xmlns="urn:newrelic-extension">
    <instrumentation>
        <tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.BackgroundThreadTracerFactory" metricName="Background/CustomTransaction">
          <match assemblyName="ConsoleApplication1" className="ConsoleApplication1.CustomTransaction">
            <exactMethodMatcher methodName="StartTransaction" />
          </match>
        </tracerFactory>
        <tracerFactory metricName="Custom/Dummy">
          <match assemblyName="ConsoleApplication1" className="ConsoleApplication1.CustomTransaction">
            <exactMethodMatcher methodName="Dummy" />
          </match>
        </tracerFactory>
    </instrumentation>
</extension>

After running the application a few times you should see a custom transaction in the Other Transactions, Background category. You should see the Dummy segment in the transactions breakdown table and transaction trace.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top