To run a simple monitoring on websites or web applications it in most situations enough to use the well established and widely used check_http nagios-plugin or monitoring-plugin. Only in specific or advanced monitoring situations, such as a full end-to-end user simulation, something else is needed.
check_http is great in checking for the web server's and application's response, able to do check for specific response codes or check the response body for a specific string. But this won't work when the site content is loading with a JavaScript; the expected content won't show up in the HTTP response body of the requested site. And as check_http, similar to curl, is not a browser but a script, it is unable to launch the JavaScript and then load the contents.
To solve this problem, an additional monitoring plugin called check_http_load_time was created. This plugin uses PhantomJS in the background.
Note: Unfortunately PhantomJS is no longer an active project since 2023.
PhantomJS is simply explained as "command line browser" and is able to load content similar as a normal browser would do. It can therefore be used to simulate a user accessing a specific URL and load contents using JavaScript, retrieving statistics of the effective load time.
ck@monitoring:~# /usr/lib/nagios/plugins/check_http_load_time.rb -u "https://myapp.example.com/#webview/62" -p /usr/local/bin/phantomjs
OK: https://myapp.example.com/#webview/62 load time: 0.42
Note: The phantomjs package from the Ubuntu repositories never seemed to work correctly, I therefore had the binary from phantomjs.org installed at /usr/local/bin/phantomjs.
Since I integrated this plugin back in 2020, initially on Ubuntu 20.04, the plugin has been successfully used to check specific web applications loading content with JavaScript.
The plugin was fully integrated into our Icinga2 monitoring, featuring it's own CheckCommand (we called it check_http_phantom in our setup).
Fast forward five years. It's 2025 and Ubuntu 20.04 LTS is EOL at the end of April. Time to upgrade to Ubuntu 22.04 or 24.04.
However after the first distribution upgrade to Ubuntu 22.04, monitoring started to alert on all websites using this specific monitoring plugin. A manual launch of the plugin showed the same error as we could see in the alert notifications and in the Icinga2 UI:
ck@monitoring:~$ /usr/lib/nagios/plugins/check_http_load_time.rb -u "https://myapp.example.com/#webview/62" -p /usr/local/bin/phantomjs -v
UNKNOWN: Could not parse JSON from phantomjs
There were two initial thoughts of potential reasons:
The Ruby version turned out to be not a problem at all. The plugin itself could still be executed. An strace on the plugin execution revealed how phantomjs was executed:
ck@monitoring:~$ strace -f -s 1000 -e trace=execve /usr/lib/nagios/plugins/check_http_load_time.rb -p /usr/local/bin/phantomjs -u https://myapp.example.com/#webview/62
execve("/usr/lib/nagios/plugins/check_http_load_time.rb", ["/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd70e299d8 /* 34 vars */) = 0
execve("/home/admck/bin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = -1 ENOENT (No such file or directory)
execve("/home/admck/.local/bin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/local/sbin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/local/bin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/sbin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/bin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = 0
strace: Process 1371139 attached
strace: Process 1371140 attached
[pid 1371140] execve("/bin/sh", ["sh", "-c", "/usr/local/bin/phantomjs --load-images=yes --local-to-remote-url-access=yes --disk-cache=no /usr/lib/nagios/plugins/netsniff.js https://myapp.example.com/#webview/62 'false' 2> /dev/null"], 0x56026c5dfba0 /* 34 vars */) = 0
strace: Process 1371141 attached
[pid 1371141] execve("/usr/local/bin/phantomjs", ["/usr/local/bin/phantomjs", "--load-images=yes", "--local-to-remote-url-access=yes", "--disk-cache=no", "/usr/lib/nagios/plugins/netsniff.js", "https://myapp.example.com/#webview/62", "false"], 0x56123391cc78 /* 34 vars */) = 0
[pid 1371141] +++ exited with 1 +++
[pid 1371140] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=1371141, si_uid=901, si_status=1, si_utime=0, si_stime=1} ---
[pid 1371140] +++ exited with 1 +++
[pid 1371138] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=1371140, si_uid=901, si_status=1, si_utime=0, si_stime=0} ---
UNKNOWN: Could not parse JSON from phantomjs
[pid 1371139] +++ exited with 3 +++
+++ exited with 3 +++
strace also shows the the child process (the phantomjs command) exited with a non-zero exit code. What is happening there?
Let's find out by executing the exact same command:
ck@monitoring:~$ /usr/local/bin/phantomjs --load-images=yes --local-to-remote-url-access=yes --disk-cache=no /usr/lib/nagios/plugins/netsniff.js https://myapp.example.com/#webview/62
Auto configuration failed
140551518091200:error:25066067:DSO support routines:DLFCN_LOAD:could not load the shared library:dso_dlfcn.c:185:filename(libproviders.so): libproviders.so: cannot open shared object file: No such file or directory
140551518091200:error:25070067:DSO support routines:DSO_load:could not load the shared library:dso_lib.c:244:
140551518091200:error:0E07506E:configuration file routines:MODULE_LOAD_DSO:error loading dso:conf_mod.c:285:module=providers, path=providers
140551518091200:error:0E076071:configuration file routines:MODULE_RUN:unknown module name:conf_mod.c:222:module=providers
Yep, that definitely looks like a problem. But does it mean that manually installed phantomjs binary simply won't work anymore on the upgraded Ubuntu 22.04 or later? Or is it something else?
I tried the Ubuntu packaged phantomjs, located under /usr/bin/phantomjs. This package was still installed, although the package doesn't exist any longer in Ubuntu 22.04.
To make the question mark above my head even bigger, it turns out this binary somewhat worked:
ck@monitoring:~$ /usr/bin/phantomjs --load-images=yes --local-to-remote-url-access=yes --disk-cache=no /usr/lib/nagios/plugins/netsniff.js https://myapp.example.com/#webview/62
{
"log": {
"version": "1.2",
"creator": {
"name": "PhantomJS",
"version": "2.1.1"
},
"pages": [
{
"startedDateTime": "2025-04-15T11:46:40.350Z",
"endedDateTime": "2025-04-15T11:46:40.546Z",
"initialResourceLoadTime": 54,
"id": "https://myapp.example.com/#webview/62",
"size": 29861,
"resourcesCount": 4,
"domElementsCount": 32,
"title": "Einen Moment bitte, die Ausgabe wird geladen...",
"jscheckout": null,
"pageTimings": {}
}
]
}
}
TypeError: Attempting to change the setter of an unconfigurable property.
TypeError: Attempting to change the setter of an unconfigurable property.
The phantomjs output was clearly able to open the JavaScript elements on the target URL. However the output at the end contains two TypeError lines, making the whole output an invalid JSON.
Now the UNKNOWN error from the monitoring plugin makes sense: Could not parse JSON from phantomjs. Indeed.
A good old pre-AI-times Internet research for this PhantomJS TypeError led me to a question on StackOverflow. The same two TypeError lines show up in the OP's question from 2020.
A comment, added 3 years later, mentioned that it was a problem with the SSL configuration:
The way I solved it was: export OPENSSL_CONF=/dev/null
I didn't really think that would solve anything, but at the same time I've also ran into big OpenSSL communication issues after an OS/OpenSSL upgrade in the past.
To turn my question mark above my head even bigger, /usr/bin/phantomjs would now return an even different error.
HOWEVER the manually installed binary at /usr/local/bin/phantomjs would now suddenly work!
ck@monitoring:~$ export OPENSSL_CONF=/dev/null
ck@monitoring:~$ /usr/local/bin/phantomjs --load-images=yes --local-to-remote-url-access=yes --disk-cache=no /usr/lib/nagios/plugins/netsniff.js https://myapp.example.com/#webview/62
{
"log": {
"version": "1.2",
"creator": {
"name": "PhantomJS",
"version": "2.1.1"
},
"pages": [
{
"startedDateTime": "2025-04-15T13:56:09.373Z",
"endedDateTime": "2025-04-15T13:56:09.609Z",
"initialResourceLoadTime": 58,
"id": "https://myapp.example.com/#webview/62",
"size": 26643,
"resourcesCount": 4,
"domElementsCount": 32,
"title": "Einen Moment bitte, die Ausgabe wird geladen...",
"jscheckout": null,
"pageTimings": {}
}
]
}
}
No error, no TypeError lines at the end; a valid JSON output!
How would this now show when using the check_http_load_time plugin?
ck@monitoring:~$ /usr/lib/nagios/plugins/check_http_load_time.rb -u "https://myapp.example.com/#webview/62" -p /usr/local/bin/phantomjs
OK: https://myapp.example.com/#webview/62 load time: 0.21
Hurray! The monitoring plugin works again with the OPENSSL_CONF environment variable set to something different than the system default (which is /etc/ssl/openssl.cnf, just FYI).
Of course the actual check is executed by Icinga2 and the environment variable is not defined anywhere. It could be set on the "nagios" system user, which is used in our environment to launch checks, however there's a better solution.
The Icinga2 CheckCommand object allows to include environment variables. This is pretty helpful if you need to set environment variables for proxy access or similar in front of a command. In our situation it helps us to set the OPENSSL_CONF environment variable for this specific check.
Here's an excerpt with the relevant part:
root@icingamaster:~# head /etc/icinga2/zones.d/global-templates/commands/check_http_phantom.conf
object CheckCommand "check_http_phantom" {
import "plugin-check-command"
command = [ PluginContribDir + "/check_http_load_time.rb" ]
env.OPENSSL_CONF = "/dev/null"
arguments = {
After an Icinga2 config reload (systemctl reload icinga2), all the checks using the check_http_load_time plugin turned OK again.
With PhantomJS no longer receiving updates or fixes, something else must come in the future, to replace these kind of HTTP checks with JavaScript loaded content. I'm tending towards real E2E testing tools, such as Selenium or Playwright. I've seen a great presentation at the OSMC 2024 about these E2E tools. But right now I have to stick with the PhantomJS based check - due to lack of time :-/.
No comments yet.
AWS Android Ansible Apache Apple Atlassian BSD Backup Bash Bluecoat CMS Chef Cloud Coding Consul Containers CouchDB DB DNS Database Databases Docker ELK Elasticsearch Filebeat FreeBSD Galera Git GlusterFS Grafana Graphics HAProxy HTML Hacks Hardware Icinga Influx Internet Java KVM Kibana Kodi Kubernetes LVM LXC Linux Logstash Mac Macintosh Mail MariaDB Minio MongoDB Monitoring Multimedia MySQL NFS Nagios Network Nginx OSSEC OTRS Observability Office OpenSearch PGSQL PHP Perl Personal PostgreSQL Postgres PowerDNS Proxmox Proxy Python Rancher Rant Redis Roundcube SSL Samba Seafile Security Shell SmartOS Solaris Surveillance Systemd TLS Tomcat Ubuntu Unix VMWare VMware Varnish Virtualization Windows Wireless Wordpress Wyse ZFS Zoneminder