Dotnet Web API NewRelic Integration
Today I was having a bit more of a play with integrating NewRelic with a dotnet web API, and figured I’d document my findings. It’s worth taking a look at the NewRelic docs if you haven’t seen them already.
It’s worth noting I’d put a quick post together about this last year, but that approach was entirely in Docker, whereas today’s approach is a bit more polished and uses the NewRelic nuget packages.
Nuget
Add the NewRelic nuget packages to your API:
<PackageReference Include="NewRelic.Agent" Version="8.25.214" />
<PackageReference Include="NewRelic.Agent.Api" Version="8.25.214" />
newrelic.config
This has mostly been taken from docs.newrelic.com. You can ignore additional exceptions and http status codes here.
I’ve taken the license key out of here, and instead set those in environment variables below, as this config will be committed to source control.
<?xml version="1.0"?>
<!-- Copyright (c) 2008-2019 New Relic, Inc. All rights reserved. -->
<!-- For more information see: https://newrelic.com/docs/dotnet/dotnet-agent-configuration -->
<configuration xmlns="urn:newrelic-config" agentEnabled="true">
<log level="info"/>
<transactionTracer enabled="true" transactionThreshold="apdex_f" stackTraceThreshold="500" recordSql="obfuscated" explainEnabled="false" explainThreshold="500"/>
<crossApplicationTracer enabled="true"/>
<errorCollector enabled="true">
<ignoreErrors>
<exception>System.IO.FileNotFoundException</exception>
<exception>System.Threading.ThreadAbortException</exception>
</ignoreErrors>
<ignoreStatusCodes>
<code>401</code>
<code>404</code>
</ignoreStatusCodes>
</errorCollector>
<browserMonitoring autoInstrument="true" />
<attributes enabled="true">
</attributes>
<threadProfiling>
<ignoreMethod>System.Threading.WaitHandle:InternalWaitOne</ignoreMethod>
<ignoreMethod>System.Threading.WaitHandle:WaitAny</ignoreMethod>
</threadProfiling>
</configuration>
Environment Variables
Set environment variables for the NewRelic runner. You can do this straight in the Dockerfile, but being as we’re including a license key here, it’s probably best to store these values somewhere more secure. I went with our locked down kubernetes manifest.
- name: "CORECLR_ENABLE_PROFILING"
value: "1"
- name: "CORECLR_PROFILER"
value: "{36032161-FFC0-4B61-B559-F6C5D41BAE5A}"
- name: "CORECLR_NEWRELIC_HOME"
value: "/app/newrelic"
- name: "CORECLR_PROFILER_PATH"
value: "/app/newrelic/libNewRelicProfiler.so"
- name: "NEW_RELIC_LICENSE_KEY"
value: "{YOUR KEY HERE}"
- name: "NEW_RELIC_APP_NAME"
value: "{YOUR API NAME HERE}"
Worth noting I got these variables from here and here.
Dockerfile
Copy the newrelic.config file into your final docker image
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine3.11 AS build
WORKDIR /src
...
# this is here just for context
RUN dotnet build -c Release --no-restore
RUN dotnet publish ./Your.Api/Your.Api.csproj -c Release -o /app/publish --no-restore --no-build
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine3.11 AS final
WORKDIR /app
...
# this is the line you need to include!
COPY ./newrelic.config .
COPY --from=build /app/publish .
...
Ignore Requests In Code
If you need to ignore certain requests, such as calls to your /status
endpoint that are perhaps being made by monitoring software, you can just add this to your controller method:
[HttpGet]
public StatusCodeResult Get()
{
NewRelic.Api.Agent.NewRelic.IgnoreTransaction();
return Ok();
}