Relic Solution: Automatically Set Your Apdex Thresholds With APIs

Introduction

You might be familiar with one or more of the New Relic APIs. But are you using these APIs in a way that gets more done with less effort?
Let’s look at how we can nest some fairly simple API calls together to create a powerful solution.
We will look at a fairly common workflow people encounter while using New Relic and how we can streamline it with our APIs:
Please note we will not be covering the basics of API keys and the API explorer here, if you would like to learn about those then click here.

Automatically Setting Your Apdex Threshold Based on Response Time Percentiles

We will not be covering the basics of Apdex here. If you would like to know more, please visit our doc site

So we know Apdex is a really useful way to understand how well your application or service is performing - but if you have a particularly complex system you may have hundreds or even thousands of services.

What do you do?

You could manually change the app settings for each application or service (which would take quite a bit of time) or you could leave everything at the default value and hope for the best.

If you want to read more about why using the default value is not a good idea, here is a blog post for you.

So what’s the alternative? You guessed it… Enter the API!

First, we want to choose an appropriate Apdex threshold. Without getting too mathematical - using a specific percentile response time for your Apdex threshold will give you a specific Apdex score.

Check out this table:

Target Apdex Score Percentile to Use
0.85 70%
0.88 76%
0.9 80%
0.92 84%
0.94 88%
0.95 90%
0.96 92%
0.98 96%

Simply choose the score you want and take note of the corresponding percentile.

Let’s think about what we want to achieve here and break it down into steps.

  1. Get the details or all our apps/services.
  2. For each app or service, determine the percentile response time we desire (this will use the Insights API).
  3. Update the application settings with that new threshold.
  4. Smile!

Or for those of you who prefer a flow chart:

*please note that “New Relic Data” is a rather radical over-simplification of how things actually work - this is just for illustration.

Disclaimer: I am still pretty new to Node.JS scripting so again I am sure there are more elegant ways to do this - however it is functional.

There are some attributes you will need to set

"YOUR_ADMIN_KEY"; to your Admin API key.
"YOUR_ACCOUNT_ID" to the ID of the account you wish to use.
"YOUR_QUERY_KEY" to your Insights Query Key.

Be sure to set var desiredPercentile =; to whatever value you have chosen from the table above.

var request = require("request");

var adminKey = "YOUR_ADMIN_KEY";
var ACCOUNT_ID = "YOUR_ACCOUNT_ID"
var QUERY_KEY = "YOUR_QUERY_KEY"
var desiredPercentile = 95;
var headers = {
    "Content-Type": "json/application",
    "X-Api-Key": adminKey
};

var options = {
    url: "https://api.newrelic.com/v2/applications.json",
    method: 'GET',
    headers: headers
};

request(options, 
  function(error, response, body) {
    if (error) return onErr(error);
    if (!error && response.statusCode == 200) {
      var result = JSON.parse(body);
      console.log('Number of applications found:'+result["applications"].length);
      for (var i = 0; i < result["applications"].length; ++i) { 
        var application = result["applications"][i];
        console.log("App Settings: "+JSON.stringify(application["settings"]["end_user_apdex_threshold"]));
        var appName  = application["name"];
        var appId = application["id"];
        var browserApdexT = application["settings"]["end_user_apdex_threshold"];
        var RUMEnabled = application["settings"]["enable_real_user_monitoring"];
        console.log("RUM Enabled: "+RUMEnabled);
        var QUERY ='SELECT percentile(duration,'+desiredPercentile+') FROM Transaction WHERE appId =' +application["id"]+' SINCE 1 DAY AGO'
        console.log('QUERY is: '+QUERY);
        getResponseTime(QUERY,appId, appName, browserApdexT, RUMEnabled);
      }
    }
  });

function getResponseTime(QUERY, appId, appName,browserApdexT,RUMEnabled) {

    request({
    uri: `https://insights-api.newrelic.com/v1/accounts/${ACCOUNT_ID}/query?nrql=${QUERY}`,
    json: true,
    headers: {
      'X-Query-Key': QUERY_KEY
    }
  }, (error, response, body) => {
    if (error) {
      isError = true
      lastError = error.toString()
      isRunning = false
      return console.log(error)
    }
    if (response.statusCode !== 200) {
      isError = true
      lastError = JSON.stringify(body)
      isRunning = false
      return console.log(body, response.statusCode)
    }
    var result = JSON.stringify(body["results"]);
    console.log('Result:'+result);
    var duration = result.slice(result.lastIndexOf(":"),result.indexOf("}"));
    duration = duration.replace( /^\D+/g, ''); // replace all leading non-digits with nothing
    if(duration < 0.01){
      //duration = 0.01;
    } 
    console.log('Duration:'+duration);
    setApdexT(duration,appId,appName,browserApdexT,RUMEnabled);
  });
}

function setApdexT(duration,appId,appName,browserApdexT,RUMEnabled){
  console.log("DURATION PASSED: "+duration);

var ApdexT = duration;
console.log("DURATION ROUNDED: "+ApdexT);
var EUApdexT = parseFloat(browserApdexT);

var data = JSON.stringify( { 
  application: 
        { name: appName,
          settings: {
            "app_apdex_threshold": ApdexT,
            "end_user_apdex_threshold": EUApdexT,
            "enable_real_user_monitoring": RUMEnabled 
        } 
      } 
    });

console.log("+++***Settings Payload***+++: "+data);
 var options = { method: 'PUT',
    url: 'https://api.newrelic.com/v2/applications/'+appId+'.json',
    headers: 
    { 
      'X-Api-Key': adminKey,
      'Content-Type': 'application/json' },
    body: data
  };


  request(options, 
  function(error, response, body) {
    if (error) return onErr(error);
    if (!error) {
      var result = JSON.parse(body);
      console.log("ERROR: "+response.statusCode+ " Message: "+response.body);
      }
    });
  }

function onErr(err) {
    console.log(err);
    return 1;
}

We’d love to hear your thoughts on this post and some of the things you have done with New Relic APIs.

Remember, if you are interested in learning more about APIs please check out developer.newrelic.com

Happy automating!

4 Likes