Check it out! This guide is meant to walk you through the process of instrumenting a non-IIS application so it can be monitored by the New Relic .NET agent. Keep reading (below) for more context and info:
Custom instrumentation of non-IIS apps can get a bit tricky at times because you have to define not just the methods you want to instrument, but also the transactions that contain them. On top of that, you need to know the assembly name, fully qualified class name, and method name of the method(s) you want to instrument.
This guide is meant to walk you through the process of instrumenting a non-IIS application so it can be monitored by the New Relic .NET agent. I’ll also try to provide a bit of overview on how things work so you can use this info in your own installation.
So, let’s get started!
Why do I need custom instrumentation?
The .NET agent instruments a predefined set of methods for “out of the box” monitoring of IIS-hosted web applications. These methods are built in to the .NET framework and can be relied upon to be present in any IIS-hosted application. However, since the possibilities for what can be contained within non-IIS applications are nearly limitless, the agent needs some configuration in order to know which methods to implement and what defines a transaction.
What are the prerequisites for custom instrumentation?
In order to have the .NET agent successfully monitor a non-IIS application and have the ability to define custom transactions/instrumentation, the following must be true:
- You have the New Relic .NET agent (version 22.214.171.124 or higher) installed.
- The agent’s “Instrument All” feature has been enabled through the installer.
- You have configured the agent to target your application for monitoring.
- You have the ability/authority to restart your application’s host process.
What does custom instrumentation entail?
Two distinct processes are required for successful monitoring of non-IIS applications by the .NET agent:
- Custom Transactions - The process of defining which method(s) will create a transaction when called.
- Custom Instrumentation - The process of defining which method(s) should be instrumented/monitored in a given transaction.
Custom transactions can be thought of as a container that holds all of the information from the instrumented methods and is passed to New Relic as a representation of a complete code path through your application. All instrumented methods must be contained within a transaction in order for them to be passed to New Relic and displayed in your account dashboard. For that reason, custom instrumentation and custom transactions should always be considered together when setting up the .NET agent to monitor non-IIS applications.
Where do I define my custom transactions/instrumentation?
Custom transactions and custom instrumentation are defined in XML files found in
C:\ProgramData\New Relic\.NET Agent\Extensions. There are essentially three files in this folder that you should be aware of and/or familiar with during the process.
CoreInstrumentation.xml - This is one of the files the .NET agent uses to instrument its default transactions/methods for use with standard IIS-hosted applications. You should not edit this file or add custom instrumentation to it because it is over-written whenever the agent is updated and any customizations contained in it will be lost. Mainly you should be aware of this file as an example of correct instrumentation.
CustomInstrumentation.xml - This is where you define all of your custom transactions and the methods they contain (custom instrumentation). The name of this file is up to you (all XML files in the “Extensions” folder will be considered for instrumentation), but CustomInstrumentation.xml is a defacto standard. This file does not exist by default. You will need to create it the first time you set up custom instrumentation. NOTE: You can have multiple files containing custom instrumentation information if you choose.
extensions.xsd - This file is used to validate the XML files you create. It defines what information is valid and what is not in the custom instrumentation XML files. It can be used with free online tools for validating XML data against XSD files. This can be useful when you’re unsure if you’ve made any syntactic errors in your XML file.
Some notes before we get started.
You should never configure custom instrumentation/transactions for methods that do not terminate (such as run() or main()). When you define such a method as the start of a transaction, the transaction never completes because the method never ends. The result is that no complete transaction is ever created, therefore nothing from that transaction is sent to New Relic servers.
Supported database and external calls are instrumented by default by the agent, even in non-IIS applications. However, in order for the data associated with these calls to be displayed in the New Relic interface in a meaningful way, they must be called from within custom transactions which you define.
Be judicious when deciding which and how many custom methods you instrument, as adding too many can add overhead to your application and may cause metric grouping issues in your New Relic dashboard. You should only instrument methods that provide valuable insight into portions of your application you need to monitor.
The .NET agent’s collection cycle is approximately one minute, so you should ensure that your application runs for at least this long before exiting. If your application does not run for more than one minute you will need to add some special configuration to your newrelic.config file in order to force the agent to send data on exit.
Adding a custom transaction
Let’s start by defining a custom instrumentation file to place your configurations in. Open a text editor and past the template below into it, then save it as CustomInstrumentation.xml. This is the bare-bones XML document that you will use to define both your custom transactions and the method calls they contain.
<?xml version="1.0" encoding="utf-8"?> <extension xmlns="urn:newrelic-extension"> <instrumentation> </instrumentation> </extension>
Next we define a custom transaction and place it inside the element of the file you just created.
<tracerFactory name="NewRelic.Agent.Core.Tracer.Factories.BackgroundThreadTracerFactory" metricName="Category/Name"> <match assemblyName="AssemblyName" className="NameSpace.ClassName"> <exactMethodMatcher methodName="MethodName" /> </match> </tracerFactory>
Let’s walk through that a bit to get some context.
<tracerFactory></tracerFactory>- This is the XML element container that tells the .NET agent that you are defining a custom transaction or method. These tags and everything inside them are known as “Tracer Factories”.
name= - The name attribute in this case tells the .NET agent that the method(s) you define in this Tracer Factory should start a transaction when called.
NewRelic.Agent.Core.Tracer.Factories.BackgroundThreadTracerFactory- Use this to declare the start/end of a transaction.
metricName= - This defines the transaction type used for display purposes in the New Relic user interface. Both the category and name must be present and they must be separated by a forward-slash. An example would be “Custom/MyTransaction”.
assemblyName= - The name of the assembly that contains the trigger method.
className= - The fully-qualified class name that contains the trigger method.
<exactMethodMatcher />- This is the XML container for the methods you want to instrument as part of this Tracer Factory. It should contain only one methodName, but you can add multiple elements to your Tracer Factory if you choose.
methodName= - This is the name of the method you want this tracer factory to implement, as it appears in your code. It goes inside a
In the above example you would want to customize the Category/Name, AssemblyName, NameSpace.ClassName, and MethodName values to fit your specific use case.
Putting it all together, your file should now look something like this:
<?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 now have a custom transaction defined for your application that the .NET agent can use to gather metrics on. Next we will add custom instrumentation to this transaction so you can get deeper visibility into what’s happening inside the transaction.
Testing What We’ve Done So Far
Creating custom transactions can be a bit tricky at times and it is good to take the mindset of “start small and build up”. With that in mind, now would probably be a good time to stop and test out what you’ve done so far to make sure it’s working as you expect. Once it’s working we can start adding details to your custom transactions with custom instrumentation. So…
- Save the file you just created (make sure it’s in the Extensions folder).
- Restart the host process for your application (ex. WFC).
- Exercise your application in a way that would call the method you just defined in your tracer factory.
- Wait about 5 minutes for data to be collected to your New Relic account.
- Navigate to your application in the New Relic user interface.
Assuming that you provided valid attributes in your Tracer Factory, you should now see a transaction type drop-down at the top of the Transactions page that allows you to select the Category/Name of the transaction you defined.
If you don’t see your custom transactions, see the “Troubleshooting” section below.
If you just wanted to instrument a single method in your application and you are getting the information you need in your dashboard, you can stop here. If you need to get more detailed information about what is happening inside this transaction, keep going.
Adding Custom Instrumentation to Your Custom Transaction
Good news! Now that all the hard work has been done in the previous section, defining custom instrumentation for your methods should be relatively simple. It’s mainly the same as what we did to define a transaction, with the exception that you leave out the name attribute that defines the start of a transaction.
The example below should look pretty familiar to you at this point, but notice that the name attribute is missing from the
<tracerFactory> <match assemblyName="AssemblyName" className="NameSpace.ClassName"> <exactMethodMatcher methodName="MethodName" /> </match> </tracerFactory>
This is added to your CustomInstrumentation.xml file at the same level as your previous tracer factory (not imbedded within the tracer factory). Now, when your application calls the transaction trigger method you created before, the .NET agent will start a transaction and start timing it. If the new method you just instrumented is called as part of the code chain from the trigger method, the agent will track that one too and include the data it gathers as part of the existing transaction. This is how custom instrumentation adds detail to custom transactions.
The whole file as we’ve instrumented it would look like this:
<?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> <tracerFactory> <match assemblyName="AssemblyName" className="NameSpace.ClassName"> <exactMethodMatcher methodName="MethodName" /> </match> </tracerFactory> </instrumentation> </extension>
Save this file and restart your application’s host process and the .NET agent will now instrument and track the method you just instrumented whenever it is called as part of the code chain of the declared transaction.
Why you shouldn’t instrument every method in your application
You can add as many custom methods as you need to in order to get the level of detail you require (just add more elements under the one we just created), but keep two things in mind when instrumenting methods.
The more methods you instrument, the more the .NET agent has to monitor. This can have a performance impact as the number of instrumented methods grows.
As stated above, in the “Notes Before we get Started” section, adding too many unique metrics can have a major impact on the quality of the information you are able to see in the user interface. Please see the New Relic documentation on Metric Grouping Issues.
Because of this, you should make sure that you are only instrumenting methods that provide valuable insight into how your application is functioning.
Validate your CustomInstrumentation.xml file against the extensions.xsd file in the Extensions directory. There are many free online tools to help you do this. You should be able to find one pretty easily by using your favorite search engine to look for “Validate XML with XSD”. If your file does not validate and you can’t figure out why, contact New Relic support.
If your custom XML file validates but you’re still not getting results, then you should double-check to make sure that you have provided valid assembly, namespace, class, and method names to your Tracer Factories. If you’re not sure about these values you can use the .NET agent’s log files to gather the information you need by following the instructions in this forum post.
There are more custom instrumentation set-up options than are covered in this post. If you find yourself stuck even after following this process you should look through the official documentation on custom instrumentation (there are some links below), ask your specific question in the forums, or reach out to New Relic support.
How to monitor stand alone .Net Application
NewRelic not capturing custom-instrumented async transactions in Non-IIS app
New Relic has not sent data - in Status Monitor
Custom Insturmentation of .Net Framework Console App
Relic Solution: Monitoring Non-IIS applications with the .NET Framework Agent