;

Configuring newrelic In Azure CloudServices

Posted : Wednesday, 20 August 2014 21:58:00

With truRating so close to launch we have just put in place our monitoring service – we looked at the options and newrelic was the stand-out choice. One problem we needed to solve that wasn’t supported natively by newrelic was the ability to dynamically configure application name at deploy time! – the basic portal new relic screen looks as follows showing a list of all Applications.

 

image

 

I have none :-(

IIS Application names (CloudService web roles) are registered via an appsetting:

  <appSettings>

    <add key="NewRelic.AppName" value="LOCAL_APP" />

  </appSettings>

if you want to “promote” this to a cloud setting its bit fiddly as you need to get the cloud package which contains the transforms to set the web.config value. To do this you need to alter any ServiceName.*.cscfg files (the service configuration file for each env) and the ServiceName.csdef (the service definition file) files manually. It looks like Visual Studio doesn’t reliably support much beyond vanilla configuration with these projects but these customisations is fairly niche so I wouldn’t expect it to.

 

To configure this application name to be set from cloud configuration  setting is a three step process:

First the Service Definition file (.csdef).

After installing the new relic nuget package the service definition file should include a startup task for each role in the cloud project:

    5     <Startup>

    6       <Task commandLine="newrelic.cmd" executionContext="elevated" taskType="simple">

    7         <Environment>

    8           <Variable name="EMULATED">

    9             <RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />

   10           </Variable>

   11           <Variable name="IsWorkerRole" value="false" />

   12           <Variable name="LICENSE_KEY">

   13             <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[@name='NewRelic.LicenseKey']/@value" />

   14           </Variable>

   15         </Environment>

   16       </Task>

   17     </Startup>

This startup task will execute as the role initializes and will execute the specified newrelic.cmd file using supplied environment variables. (more on that later) .

Define another environment variable that will be declared based on a cloud configuration value:

    5     <Startup>

    6       <Task commandLine="newrelic.cmd" executionContext="elevated" taskType="simple">

    7         <Environment>

    8           <Variable name="EMULATED">

    9             <RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />

   10           </Variable>

   11           <Variable name="IsWorkerRole" value="false" />

   12           <Variable name="LICENSE_KEY">

   13             <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[@name='NewRelic.LicenseKey']/@value" />

   14           </Variable>

   15           <!-- environment variable indicating name of new relic application as it will apppear on the newrelic Dashboard -->

   16           <Variable name="newrelic_APPLICATION" >

   17             <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[@name='NewRelic_AppName']/@value" />

   18           </Variable>

   19         </Environment>

   20       </Task>

   21     </Startup>

NB: Ideally for consistency I would have used NewRelic.AppName but the xpath query was failing, I think, due to the “.” character.

Next scroll to the ConfigurationSettings section and add the following

   37     <ConfigurationSettings>

   38       <Setting name="TableStorageConnectionString" />

   39       <Setting name="DbConnection" />

   40       <Setting name="RandomSettingOne" />

   41       <Setting name="NewRelic.LicenseKey" />

   42       <Setting name="newrelic_APPLICATION" />

   43       <Setting name="RandomSettingTwo" />

   44     </ConfigurationSettings>

This is all the configuration thats required for the service definition file.

Second the service configuration files. For each environment add/update the ServiceName.<env>.cscfg configuration file

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

    2 <ServiceConfiguration serviceName="MyRoleService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="3" osVersion="*" schemaVersion="2014-01.2.3">

    3   <Role name="MyWebRole">

    4     <Instances count="1" />

    5     <ConfigurationSettings>

    6       <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=false" />

    7       <Setting name="TableStorageConnectionString" value="UseDevelopmentStorage=false" />

    8       <Setting name="DbConnection" value="Server=DBSERVER; Database=Database; Integrated Security=SSPI" />

    9       <Setting name="RandomSettingOne" value="1" />

   10       <Setting name="NewRelic.LicenseKey" value="xxxxxxxxxxxxxxxxxxxxxxxxxx" />

   11       <Setting name="newrelic_APPLICATION" value="LOCAL_APP" />

   12       <Setting name="RandomSettingTwo" value="2" />

   13     </ConfigurationSettings>

   14   </Role>

   15 </ServiceConfiguration>

Create/Update the configuration for each environment and you’re done.

Last the newrelic.cmd file.

This step is optional if you dont mind having a newrelic related appsetting in your application configuration file, anything in developer code that can get changed accidentally will (Sod’s Law) so putting this in the cloud service projects only (and not the target project itself) is worth the effort for the potential error it prevents.

This following files gets added to the .csproj (presumably .vbproj also) as a “copy always” resource.

image

NB versions will differ based on local environment

At role startup the batch file runs and installs all the necessary monitoring software that new relic uses to capture performance metrics.

The top of the file should be something like...

----------

SETLOCAL EnableExtensions

 

for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j

set ldt=%ldt:~0,4%-%ldt:~4,2%-%ldt:~6,2% %ldt:~8,2%:%ldt:~10,2%:%ldt:~12,6%

 

SET NR_ERROR_LEVEL=0

 

:: Comment out the line below if you do not want to install the New Relic Agent

CALL:INSTALL_NEWRELIC_AGENT

 

:: Comment out the line below if you do not want to install the New Relic Windows Server Monitor

CALL:INSTALL_NEWRELIC_SERVER_MONITOR

----------

To dynamically set the appSetting value I opted for a task to execute appcmd.exe from the command file and set the value as a machine level appsetting – changes in red!

----------

SETLOCAL EnableExtensions

 

for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j

set ldt=%ldt:~0,4%-%ldt:~4,2%-%ldt:~6,2% %ldt:~8,2%:%ldt:~10,2%:%ldt:~12,6%

 

SET NR_ERROR_LEVEL=0

 

:: Custom cmd function - execute first

CALL:SET_APP_NAME

 

:: Comment out the line below if you do not want to install the New Relic Agent

CALL:INSTALL_NEWRELIC_AGENT

 

:: Comment out the line below if you do not want to install the New Relic Windows Server Monitor

CALL:INSTALL_NEWRELIC_SERVER_MONITOR

 

IF %NR_ERROR_LEVEL% EQU 0 (

    EXIT /B 0

) ELSE (

    EXIT %NR_ERROR_LEVEL%

)

 

:: --------------

:: Functions

:: --------------

:SET_APP_NAME

 

IF [%newrelic_APPLICATION%] == [] (

    ECHO  no value for APP_MONITOR_NAME -skipping step. >> "d:\tr.log" 2>&1

    GOTO:EOF

)

----------

The custom function first checks if that environment variable newrelic_APPLICATION is set, if not the function is skipped. If the variable is declared then appSetting will be added to the machine config file.  Whizz a few requests through, wait a few mins and bada-bing…

image

N.B. machine.config is used as the structure of the local filesystem in the cloud package has a predicable (but i suspect) changeable path to the virtual root of each application. Using appcmd to set application configuration files requires prior knowledge of the local filesystem. Applying the settings at machine.config level means the value will consistently be available wherever ever the site root is on located on the filesystem.

In summary its a bit of a convoluted setup but what happens is as follows: When the startup task runs, it and passes variables configured for each environment into the newrelic.cmd process. The supplied appsetting value is written to machine.config in the Cloud Service node. This is then read by the NewRelic Agent on first web request. It is also compatible with the loveliness of Azure autoscale – because the configuration is baked into the service package, any new nodes will automatically pull in the correct settings

NB this does not work in the emulator so you need to deploy to “real” Azure to test it out – or run locally in IIS having first installed the .NET Agent and restarted IIS as per the documentation.

newRelic is great – their support isn’t the quickest but its a really good, low maintainence, easy-to-install, monitoring option I would recommend for anyone wanting an affordable enterprise monitoring solution. I set up a billing account but due to a clerical error its the account managed through the Azure portal so we’re not 100% sure we’ll go with it for launch – we are on the trial stage though so provided its resolved soon I have no doubt we’ll use newrelic!

Update 2014-08-20: The problem previously mentioned is, IMHO, down to shortcomings in the Azure Portal AddOn system– we dont have Azure Portal integration but we but we have newrelic for launch, and thats a good place to be :-D

  • (This will not appear on the site)