Articles
cfGlobalping: ping, dig, and curl your site from anywhere on Earth - in CFML
Run a ping, traceroute, mtr, DNS lookup, or HTTP check from real machines in real locations
Here's a problem I run into all the time. I push a DNS change, swap a cert at the edge, or tweak a Fastly config, and then I want to know one thing: does it actually work out there? Not from my server. Not from my laptop on the Central Coast. From Frankfurt. From Tokyo. From some eyeball network in Sãn Paulo that's nowhere near my datacenter.
From a single box you only ever see one vantage point. And the internet has a nasty habit of looking perfectly healthy from where you're standing while being quietly broken somewhere you can't see.
Globalping solves the vantage-point problem. It's a free, community-run network of probes scattered around the world, built by the folks at jsDelivr, and it'll run a ping, traceroute, mtr, DNS lookup, or HTTP check from real machines in real locations. They publish a CLI that does all of this from the command line.
What it didn't have was a clean way to call it from ColdFusion. So I wrote one: cfGlobalping.
What it is
GlobalPing.cfc is a thin wrapper around the Globalping CLI. You give it the path to the binary, call a method like ping() or http(), and instead of scraping raw text output you get back a typed struct you can actually loop over. No regex archaeology, no parsing terminal formatting by hand. Just data.
It runs on Adobe ColdFusion 2016+ or Lucee 5.4+, it's a single CFC with no external dependencies, and it's Apache-2.0 licensed.
The one thing it needs that isn't CFML is the Globalping CLI installed on the server. An API token is optional - you'll work fine anonymously, but a token gets you higher rate limits, and the CFC handles it for you (more on that below, because I did something deliberate there).
Getting started
Drop GlobalPing.cfc into your project and instantiate it:
gp = new GlobalPing(
exePath = "C:\tools\globalping.exe", // required: full path to the CLI binary
token = "", // optional: API token
tempDir = gettempdirectory(), // optional: temp dir for token scripts
timeout = 30 // optional: process timeout in seconds
);
On Windows that exePath points at globalping.exe; on Linux it's usually something like /usr/local/bin/globalping. Everything except exePath has a sensible default.
The methods
There are five measurement methods - ping(), dns(), http(), traceroute(), and mtr() - plus a limits() helper for checking your quota.
Every method returns a struct with success, error, and raw keys at minimum, so the first thing you ever do is check success. The measurement methods add the metadata you'd expect (id, type, status, target, probesCount, timestamps) and a results array with one entry per probe.
A basic ping
gp = new GlobalPing( exePath = "/usr/local/bin/globalping" );
result = gp.ping( target = "cloudflare.com", from = "Europe", limit = 3 );
if ( result.success ) {
for ( var r in result.results ) {
writeoutput( r.probe.city & ": avg=" & r.result.stats.avg & "ms<br>" );
}
}
That from parameter is where the magic lives. It takes a country ("US", "Germany"), a city ("London"), a continent ("Europe", "NA"), an ASN ("AS15169"), a network name ("Cloudflare"), a comma-separated list ("US,Germany,Japan"), or one of the magic keywords like "cdn" or "eyeball". Default is "world" - give me whatever probes you've got.
Checking a cert from five continents
This is the one I actually reach for. After any change at the edge, I want to confirm the cert real users are being handed is the right one, everywhere - not just whatever my origin thinks it's serving.
result = gp.http( target = "mycfml.com", method = "HEAD", from = "world", limit = 5 );
for ( var r in result.results ) {
var tls = r.result.tls;
writeoutput( r.probe.city & " - expires " & tls.expiresAt & " (" & tls.issuer.O & ")<br>" );
}
The http() method hands back a rich tls struct: issuer, subject, protocol, cipher, key type and bits, the fingerprint256, valid-from and expires-at dates, the lot. If you've ever had a CDN node lagging behind on a cert rotation, you know exactly why seeing this per-probe matters. You also get full timings (dns, tcp, tls, firstByte, download) so you can see where the slowness is, not just that it exists.
DNS lookups that don't lie to you
result = gp.dns( target = "example.com", type = "MX", limit = 3 );
for ( var r in result.results ) {
for ( var answer in r.result.answers ) {
writeoutput( answer.value & "<br>" );
}
}
It supports the full spread of record types - A, AAAA, CNAME, MX, NS, TXT, SOA, PTR, CAA, and the DNSSEC family. Run a lookup right after a cutover from a handful of countries and you'll watch propagation happen in real time instead of guessing.
traceroute, mtr, and a fast latency mode
traceroute() and mtr() give you per-hop detail - resolved hostnames and addresses, ASN, RTT timings, and for MTR the full stats including jitter. One gotcha worth knowing: the latency=true shortcut that the other methods support is not available for traceroute or mtr; ask for it there and you'll get success=false back rather than a surprise.
That latency mode, by the way, is handy when you don't care about per-packet detail and just want a quick min/max/avg summary:
result = gp.ping( target = "8.8.8.8", from = "world", limit = 5, latency = true );
for ( var r in result.results ) {
writeoutput( r.probe & " min=#r.min#ms max=#r.max#ms avg=#r.avg#ms<br>" );
}
Knowing your limits
result = gp.limits();
writeoutput( "Remaining: " & result.measurements.remaining & " tests" );
Tells you how many tests you've got left this hour and when the counter resets - anonymous or authenticated, depending on whether you configured a token.
The token thing I actually care about
When you hand the CFC an API token, the obvious lazy implementation is to shove it onto the command line as an argument. Don't do that. Anything on the command line shows up in process listings, and now your token is sitting there for anyone with a ps or Task Manager to read.
So cfGlobalping doesn't do that. When a token is present, it writes a tiny temporary wrapper script - a .bat on Windows, a .sh on Unix - that sets GLOBALPING_TOKEN as an environment variable and then invokes the CLI. The token never touches the argument list, and it never appears in a process listing. The temp script gets deleted in a finally block whether the call succeeds or blows up, so you're not leaving credential crumbs on disk either.
It's a small thing. It's also the kind of small thing that's the difference between a wrapper I'd run in production and one I wouldn't.
Where this earns its keep
A few real uses from my own stack:
- Post-deploy edge verification. Change something at the CDN or WAF layer, then hit your own hostname with
http()fromfrom="world"and confirm the cert, status code, and timings look right everywhere - not just from origin. - DNS propagation, watched live. Run
dns()across a spread of countries after a record change instead of refreshing some third-party web tool. - Latency from the networks that matter.
from="eyeball"or a specific ASN tells you what actual consumer connections experience, which is rarely what your datacenter-to-datacenter numbers suggest. - Routing weirdness. When a region reports slowness,
mtr()from that region shows you the hop where it falls apart.
And because it all comes back as structs, you can drop any of this straight into a scheduled task, a dashboard, a Slack alert, or a cfchart. It's just CFML at that point.
Grab it
The repo's here: github.com/JamoCA/cfGlobalping. Single CFC, Apache-2.0, README with the full parameter reference and return shapes for every method, plus a demo.cfm to poke at.
It's early days - a couple of commits in - so if you put it through its paces and find a rough edge, open an issue or send a PR. I'd genuinely like to hear how it behaves on stacks that aren't mine.