Ping an IP or URL using ICMP ping

If you are looking for a way to ping an IP address or a URL’s domain using ICMP Ping, like you would from the OS command line, here’s some code for an Synthetic API monitor that works well.

Please note that builtin New Relic Synthetic “Ping” monitor actually tries to do an HTTP request, whereas this code does an actual ICMP ping, recording latency and failure rates, which you can graph in Insights.

To use this, create an Synthetic API monitor, paste in the code, and edit the first two variables. The targetName is just a string used in the console output. The target is the thing you want to ping, and it can be an IP address or a URL.

Down towards the bottom you will see where I insert data into Insights for graphing. I have a couple of variables consistent across all my Synthetic monitors called authTime and appTime so that I can separate out the time to authenticate into an application versus the time to load it’s home page. For this monitor, authTime is always zero, since no authentication takes place. Feel free to rename or delete these insights calls to make them work in your monitoring setup.

This code is based on some other ICMP ping code floating around the blogs, and fixes various bugs related to the asynchronous-ness of calls returning promises, and pretties it up a bit.

// **********************************************************
// SNMP ping monitor settings
// **********************************************************
var targetName = "India-PA3020-PRT01"     // Name of device
var target = "14.141.80.162";             // IP address or URL

// **********************************************************
// You should not need to change anything below this line
// unless you want to tune an individual monitor in some manner.
// **********************************************************

// Standard settings
$http.head('https://google.com');                                       // Perform a HTTP HEAD so the NR monitor does not error out. We do not use this data.
var pingInterval = 1000;                                                // How many ms between pings
var numberofruns = 12;                                                  // How many pings you want to perform for each monitor run
var runcount = 0;                                                       // How many pings were done so far
var failedcount = 0;                                                    // How many failures were seen so far
var alertOnFailedPercent = 10;                                          // The maximum percentage of pings that can fail before alerting
var alertOnHighLatency = 700;                                           // The max average latency in ms you will tolerate - gather metrics for a while, then tune this value if needed
var latencyarray = [];                                                  // Record the latency for each ping in an array


// Required modules
var ping = require ("net-ping");                                        // Gives us the ability to SNMP ping
var assert = require('assert');                                         // Gives us the ability to throw an alert+msg based on a condition
var dns = require('dns');                                               // Gives us the ability to do a dns lookup


// URL to IP
var regex = /.*:\/\/.*/;                                                // Examine target to see if we need to convert a url to an IP
if (regex.test(target)) {                                               // does target look like a URL?
    var domain = target.split('/')[2];                                  // Get domain from the Url
    var targetIP = '';                                                  // IP address to ping

    dns.lookup(domain, function (err, addresses, family) {              // Do a DNS lookup
        var msg = "Unable to resolve '" + domain + "' to an IP.";       // Assert error message
        assert.ok(addresses.length > 0, msg);                           // Assert that we got an ip address
        targetIP = addresses;                                           // Got an IP address
        console.log("Pinging",domain,targetIP);                         // Progress message
    });                                                                 // end DNS lookup
} else {                                                                // else we already have an IP address
  targetIP = target;                                                    // just use the IP 
  console.log("Pinging",targetIP);                                      // Progress message
}                                                                       // Done getting the IP address to ping 


// Ping Interval Timer
var runpings = setInterval(function(){                                  // Do this many pings using a timer
  if (runcount < numberofruns) {                                        // If not done yet
      performping();                                                    // Do a ping      
  } else {                                                              // Else we are done
      clearInterval(runpings);                                          // Stop the timer
      calculateresult();                                                // Record the results
  }                                                                           
}, pingInterval);                                                       // Do a ping every pingInterval ms


// Ping
var performping = function() {                                          // Do a single ping
  if (targetIP == '') { return; }                                       // Don't start until DNS resolves the domain to a targetIP
  var session = ping.createSession ();                                  // Create a ping session
	session.pingHost (targetIP, function (error, targetIP, sent, rcvd) {  // Ping the host
  	var ms = rcvd - sent;                                               // Calculate the latency of the ping
    if (error) {                                                        // If the ping errored
        failedcount++;                                                  // Increment the failure count
        console.log('Ping failed for',targetIP);                        // Log a failure to the console
    } else {                                                            // Else
        console.log('Reply from',targetIP,'time =',ms,'ms');            // Log the latency to the console - uncomment for debugging
        latencyarray.push(ms);                                          // Record the latency
	  }
    runcount++;                                                         // Increment the count of pings done
  });
};


// Results
var calculateresult = function() {                                      // Calculate results and issue alerts

  // Progress message
  var latencies = latencyarray.toString();                              // Progress message - latency array to a string
  console.log("Latencies: " + latencies);                               // Progress message - latency array

  // Average latency
	var sum = 0;                                                          // Sum of latencies ignoring failures
	for( var i = 0; i < latencyarray.length; i++ ){                       // Walk through the latency array
    	sum += parseInt( latencyarray[i], 10 );                           // Add them up
	}                                                                     // To get the total
	var latencyavg = sum/latencyarray.length;                             // And divide by the number of latencies to get the average
  console.log("Average latency: " + latencyavg,"ms");                   // Progress Message
  
  // Falure rates
  var failedpercent = Math.round((failedcount/runcount)*100);           // Round failedPercent to an integer
  console.log("Failed count:",failedcount, "out of",runcount);          // Progress Message 
  console.log("Failed percentage: " + failedpercent);                   // Progress Message
  
  // Insights data
  $util.insights.set("failed",failedcount);                             // Add to insights - failed is unique to this type of monitor
  $util.insights.set("failed_percent",failedpercent);                   // Add to insights - failedPercent is unique to this type of monitor
  $util.insights.set('authTime',0);                                     // Add to insights - authTime is standard across all apps
  $util.insights.set('appTime',latencyavg);                             // Add to insights - appTime is standard across all apps

  // Failure Alerts
  var msg = targetName + ' ' + targetIP + ' ' + failedpercent + '% ping failure rate exceeds threshold of ' + alertOnFailedPercent
  assert.ok(failedpercent <= alertOnFailedPercent, msg)                 // Throw an error on unacceptably high failure rates

  // Latency alerts
  var msg = targetName + ' ' + targetIP + ' ' + failedpercent + '% ping latency exceeds threshold of ' + alertOnHighLatency
  assert.ok(latencyavg <= alertOnHighLatency, msg)                      // Throw an error on unacceptably high average latency
};
10 Likes

Hey this is a very creative use of our runtime, excellent work!

1 Like

Several people are going to be happy to see this. Thanks for posting @Erik.Hyypia

2 Likes

How to view the insights data for this script, as it does not appear under SyntheticCheck, also is there any way we can set the accountid,key,eventype ?

@parvathi.ganesan - the insights events generated by $util.insights.set('AttributeName', 'AttributeValue') will show up under the SyntheticCheck event as: 'custom.AttributeName'

This will default to going to the same account that the monitor runs in and will stay in the same event (SyntheticCheck) - This is not configurable.

1 Like

Are there any tips on how to approach resolving this if a ping doesn’t work?

Hi,
is there a way to use this script with a private location that does not have internet access?
so it can’t reach https://google.com.
regards Phil

Hi @philipp.erismann - There is a new version of this which you may find relevant for your situation.