From 5b3928ce797289978f8c4e60d78eb6769d477dfd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C4=93teris=20Caune?=
curl --header "X-Api-Key: your-api-key" SITE_ROOT/api/v1/checks/
-
curl --header "X-Api-Key: your-api-key" SITE_ROOT/api/v1/checks/
+
{
+{
"checks": [
{
"name": "Filesystem Backup",
@@ -155,13 +155,13 @@ specified value.
}
]
}
-
+
When using the read-only API key, the following fields are omitted:
ping_url
, update_url
, pause_url
, channels
. An extra unique_key
field
is added which can be used to GET
a check in place of the UUID
. The unique_key
identifier is stable across API calls. Example:
{
+{
"checks": [
{
"name": "Filesystem Backup",
@@ -192,7 +192,7 @@ is added which can be used to GET
a check
}
]
}
-
+
curl --header "X-Api-Key: your-api-key" SITE_ROOT/api/v1/checks/<uuid>
-
curl --header "X-Api-Key: your-api-key" SITE_ROOT/api/v1/checks/<uuid>
+
{
+{
"name": "Database Backup",
"tags": "production db",
"desc": "Runs ~/db-backup.sh",
@@ -235,7 +235,7 @@ using the read-only API key) as an identifier.
"schedule": "15 5 * * *",
"tz": "UTC"
}
-
+
Note: the ping_url
, update_url
and pause_url
fields, although omitted, are not
really secret. The client already knows the check's unique UUID and so can easily
construct these URLs by itself.
{
+{
"name": "Database Backup",
"tags": "production db",
"desc": "Runs ~/db-backup.sh",
@@ -259,7 +259,7 @@ construct these URLs by itself.
"schedule": "15 5 * * *",
"tz": "UTC"
}
-
+
curl SITE_ROOT/api/v1/checks/ \
+curl SITE_ROOT/api/v1/checks/ \
--header "X-Api-Key: your-api-key" \
--data '{"name": "Backups", "tags": "prod www", "timeout": 3600, "grace": 60}'
-
+
Or, alternatively:
-curl SITE_ROOT/api/v1/checks/ \
+curl SITE_ROOT/api/v1/checks/ \
--data '{"api_key": "your-api-key", "name": "Backups", "tags": "prod www", "timeout": 3600, "grace": 60}'
-
+
{
+{
"channels": "",
"desc": "",
"grace": 60,
@@ -400,7 +400,7 @@ the limit is 20 checks per account.
"timeout": 3600,
"update_url": "SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc",
}
-
+
curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc \
+curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc \
--header "X-Api-Key: your-api-key" \
--data '{"name": "Backups", "tags": "prod www", "timeout": 3600, "grace": 60}'
-
+
Or, alternatively:
-curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc \
+curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc \
--data '{"api_key": "your-api-key", "name": "Backups", "tags": "prod www", "timeout": 3600, "grace": 60}'
-
+
{
+{
"channels": "",
"desc": "",
"grace": 60,
@@ -524,7 +524,7 @@ field values.
"timeout": 3600,
"update_url": "SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc",
}
-
+
curl SITE_ROOT/api/v1/checks/0c8983c9-9d73-446f-adb5-0641fdacc9d4/pause \
+curl SITE_ROOT/api/v1/checks/0c8983c9-9d73-446f-adb5-0641fdacc9d4/pause \
--request POST --header "X-Api-Key: your-api-key" --data ""
-
+
Note: the --data ""
argument forces curl to send a Content-Length
request header
even though the request body is empty. For HTTP POST requests, the Content-Length
header is sometimes required by some network proxies and web servers.
{
+{
"channels": "",
"desc": "",
"grace": 60,
@@ -569,7 +569,7 @@ header is sometimes required by some network proxies and web servers.
"timeout": 3600,
"update_url": "SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc"
}
-
+
curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc \
+curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc \
--request DELETE --header "X-Api-Key: your-api-key"
-
+
{
+{
"channels": "",
"desc": "",
"grace": 60,
@@ -611,7 +611,7 @@ check that was just deleted.
"timeout": 3600,
"update_url": "SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc",
}
-
+
curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc/pings/ \
+curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc/pings/ \
--header "X-Api-Key: your-api-key"
-
+
{
+{
"pings": [
{
"type": "success",
@@ -680,7 +680,7 @@ number of returned pings depends on account's billing plan: 100 for free account
}
]
}
-
+
curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc/flips/ \
+curl SITE_ROOT/api/v1/checks/f618072a-7bde-4eee-af63-71a77c5723bc/flips/ \
--header "X-Api-Key: your-api-key"
-
+
[
+[
{
"timestamp": "2020-03-23T10:18:23+00:00",
"up": 1
@@ -743,7 +743,7 @@ number of returned pings depends on account's billing plan: 100 for free account
"up": 1
}
]
-
+
curl --header "X-Api-Key: your-api-key" SITE_ROOT/api/v1/channels/
-
curl --header "X-Api-Key: your-api-key" SITE_ROOT/api/v1/channels/
+
{
+{
"channels": [
{
"id": "4ec5a071-2d08-4baa-898a-eb4eb3cd6941",
@@ -776,4 +776,4 @@ number of returned pings depends on account's billing plan: 100 for free account
}
]
}
-
\ No newline at end of file
+
In this example, we run certbot renew
, capture its output, and submit
the captured output to SITE_NAME:
#!/bin/sh
+#!/bin/sh
m=$(/usr/bin/certbot renew 2>&1)
curl -fsS --retry 3 --data-raw "$m" PING_URL
-
+
/fail
EndpointWe can extend the previous example and signal either success or failure depending on the exit code:
-#!/bin/sh
+#!/bin/sh
url=PING_URL
@@ -24,11 +24,11 @@ depending on the exit code:
if [ $? -ne 0 ]; then url=$url/fail; fi
curl -fsS --retry 3 --data-raw "$m" $url
-
+
Finally, all of the above can be packaged in a single line. The one-line version can be put directly in crontab, without using a wrapper script.
-m=$(/usr/bin/certbot renew 2>&1); curl -fsS --data-raw "$m" "PING_URL$([ $? -ne 0 ] && echo -n /fail)"
-
m=$(/usr/bin/certbot renew 2>&1); curl -fsS --data-raw "$m" "PING_URL$([ $? -ne 0 ] && echo -n /fail)"
+
# Sending a HTTP GET request with curl:
+# Sending a HTTP GET request with curl:
curl --retry 3 PING_URL
# Silent version (no stdout/stderr output unless curl hits an error):
@@ -12,7 +12,7 @@ curl -fsS --retry 3 PING_URL
# Sending a HTTP GET request with wget:
wget PING_URL -O /dev/null
-
+
PING_URL
PING_URL/fail
#!/bin/sh
+#!/bin/sh
# Payload here:
/usr/bin/certbot renew
# Ping SITE_NAME
curl --retry 3 "PING_URL$([ $? -ne 0 ] && echo -n /fail)"
-
+
In the below example, certbot's output is captured and submitted via HTTP POST:
-#!/bin/sh
+#!/bin/sh
m=$(/usr/bin/certbot renew 2>&1)
curl -fsS --retry 3 --data-raw "$m" PING_URL
-
+
#!/bin/bash
+#!/bin/bash
API_KEY=your-api-key-here
@@ -62,4 +62,4 @@ register with SITE_NAME the first time they run.
# Finally, send a ping:
curl --retry 3 $URL
-
\ No newline at end of file
+
import requests
+import requests
API_URL = "SITE_ROOT/api/v1/checks/"
SOURCE_PROJECT_READONLY_KEY = "..."
@@ -24,6 +24,6 @@ and the requests library:
r = requests.get(API_URL, headers={"X-Api-Key": SOURCE_PROJECT_READONLY_KEY})
for check in r.json()["checks"]:
- print("Cloning %s" % check["name"])
+ print("Cloning %s" % check["name"])
requests.post(API_URL, json=check, headers={"X-Api-Key": TARGET_PROJECT_KEY})
-
\ No newline at end of file
+
Below is an example of making a HTTP request to SITE_NAME from C#.
-using (var client = new System.Net.WebClient())
+using (var client = new System.Net.WebClient())
{
client.DownloadString("PING_URL");
}
-
\ No newline at end of file
+
Successful responses will have the "200 OK" HTTP response status code and a short and simple string "OK" in the response body.
HEAD|GET|POST PING_ENDPOINT{uuid}
-
HEAD|GET|POST PING_ENDPOINT{uuid}
+
Signals to SITE_NAME that the job has completed successfully (or, for
continuously running processes, is still running and healthy). The uuid
parameter
is unique for each check.
Example
-GET /5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278 HTTP/1.0
+GET /5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278 HTTP/1.0
Host: hc-ping.com
-
+
HTTP/1.1 200 OK
+HTTP/1.1 200 OK
Server: nginx
Date: Wed, 29 Jan 2020 09:58:23 GMT
Content-Type: text/plain; charset=utf-8
@@ -37,23 +37,23 @@ is unique for each check.
Access-Control-Allow-Origin: *
OK
-
+
HEAD|GET|POST PING_ENDPOINT{uuid}/fail
-
HEAD|GET|POST PING_ENDPOINT{uuid}/fail
+
Signals to SITE_NAME that the job has failed. Actively signalling a failure minimizes the delay from your monitored service failing to you receiving an alert.
Example
-GET /5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/fail HTTP/1.0
+GET /5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/fail HTTP/1.0
Host: hc-ping.com
-
+
HTTP/1.1 200 OK
+HTTP/1.1 200 OK
Server: nginx
Date: Wed, 29 Jan 2020 09:58:23 GMT
Content-Type: text/plain; charset=utf-8
@@ -62,12 +62,12 @@ minimizes the delay from your monitored service failing to you receiving an aler
Access-Control-Allow-Origin: *
OK
-
+
HEAD|GET|POST PING_ENDPOINT{uuid}/start
-
HEAD|GET|POST PING_ENDPOINT{uuid}/start
+
Sends a "job has started!" message to SITE_NAME. This is @@ -77,12 +77,12 @@ optional but enables a few extra features:
Example
-GET /5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/start HTTP/1.0
+GET /5bf66975-d4c7-4bf5-bcc8-b8d8a82ea278/start HTTP/1.0
Host: hc-ping.com
-
+
HTTP/1.1 200 OK
+HTTP/1.1 200 OK
Server: nginx
Date: Wed, 29 Jan 2020 09:58:23 GMT
Content-Type: text/plain; charset=utf-8
@@ -91,4 +91,4 @@ optional but enables a few extra features:
Access-Control-Allow-Origin: *
OK
-
\ No newline at end of file
+
Below is an example of making a HTTP request to SITE_NAME from Node.js.
-var https = require('https');
+var https = require('https');
https.get("PING_URL");
-
+
You can also send pings from a browser environment. SITE_NAME sets the
Access-Control-Allow-Origin:*
CORS header, so cross-domain AJAX requests work.
var xhr = new XMLHttpRequest();
+var xhr = new XMLHttpRequest();
xhr.open('GET', 'PING_URL', true);
xhr.send(null);
-
\ No newline at end of file
+
Signalling a start kicks off a separate timer: the job now must signal a success within its configured "Grace Time", or it will get marked as "down".
Below is a code example in Python:
-import requests
+import requests
URL = "PING_URL"
@@ -23,11 +23,11 @@ success within its configured "Grace Time", or it will get marked as "down".
# TODO: run the job here
fib = lambda n: n if n < 2 else fib(n - 1) + fib(n - 2)
-print("F(42) = %d" % fib(42))
+print("F(42) = %d" % fib(42))
# Signal success:
requests.get(URL)
-
+
Let's look at an example:
-$ crontab -l
+$ crontab -l
# m h dom mon dow command
8 6 * * * /home/user/backup.sh
-
+
The above job runs /home/user/backup.sh
every day at 6:08. The backup
@@ -40,10 +40,10 @@ increasingly important as you add more checks to your account.
Finally, edit your cron job definition and append a curl or wget call after the command:
-$ crontab -e
+$ crontab -e
# m h dom mon dow command
8 6 * * * /home/user/backup.sh && curl -fsS --retry 3 -o /dev/null PING_URL
-
+
Now, each time your cron job runs, it will send a HTTP request to the ping URL. @@ -101,7 +101,7 @@ there is an error. Feel free to adjust the curl options to suit your needs.
On modern GNU/Linux systems, you can look up the time zone using the
timedatectl status
command and looking for "Time zone" in its output:
$ timedatectl status
+$ timedatectl status
Local time: C 2020-01-23 12:35:50 EET
Universal time: C 2020-01-23 10:35:50 UTC
@@ -110,4 +110,4 @@ there is an error. Feel free to adjust the curl options to suit your needs.
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
-
\ No newline at end of file
+
Below is an example of making a HTTP request to SITE_NAME from PHP.
-file_get_contents('https://hc-ping.com/your-uuid-here');
-
file_get_contents('https://hc-ping.com/your-uuid-here');
+
Here is a simple PowerShell script that pings SITE_NAME. When scheduled to run with Task Scheduler, it will essentially just send regular "I'm alive" messages. You can of course extend it to do more things.
-# inside a PowerShell script:
+# inside a PowerShell script:
Invoke-RestMethod PING_URL
-
+
Save the above to e.g. C:\Scripts\healthchecks.ps1
.
Then use the following command in a Scheduled Task to run the script:
powershell.exe -ExecutionPolicy bypass -File C:\Scripts\healthchecks.ps1
-
powershell.exe -ExecutionPolicy bypass -File C:\Scripts\healthchecks.ps1
+
In simple cases, you can also pass the script to PowerShell directly, using the "-command" argument:
-# Without an underlying script, passing the command to PowerShell directly:
+# Without an underlying script, passing the command to PowerShell directly:
powershell.exe -command &{Invoke-RestMethod PING_URL}
-
\ No newline at end of file
+
If you are already using the requests library, it's convenient to also use it here:
-# using requests:
+# using requests:
import requests
requests.get("PING_URL")
-
+
Otherwise, you can use the urllib standard module.
-# urllib with python 3.x:
+# urllib with python 3.x:
import urllib.request
urllib.request.urlopen("PING_URL")
-
+
# urllib with python 2.x:
+# urllib with python 2.x:
import urllib
urllib.urlopen("PING_URL")
-
+
You can include additional diagnostic information in the in the request body (for POST requests):
-# Passing diagnostic information in the POST body:
+# Passing diagnostic information in the POST body:
import requests
requests.post("PING_URL", data="temperature=-7")
-
\ No newline at end of file
+
Below is an example of making a HTTP request to SITE_NAME from Ruby.
-require 'net/http'
+require 'net/http'
require 'uri'
Net::HTTP.get(URI.parse('PING_URL'))
-
\ No newline at end of file
+
The below shell script sends either a "success" or "failure" ping depending on command's (certbot in this example) exit code:
-#!/bin/sh
+#!/bin/sh
url=PING_URL
@@ -14,26 +14,26 @@ command's (certbot in this example) exit code:
if [ $? -ne 0 ]; then url=$url/fail; fi
curl --retry 3 $url
-
+
Below is a skeleton code example in Python which signals a failure when the work function returns an unexpected value or throws an exception:
-import requests
+import requests
URL = "PING_URL"
def do_work():
# Do your number crunching, backup dumping, newsletter sending work here.
# Return a truthy value on success.
# Return a falsy value or throw an exception on failure.
- return True
+ return True
-success = False
+success = False
try:
success = do_work()
finally:
# On success, requests PING_URL
# On failure, requests PING_URL/fail
requests.get(URL if success else URL + "/fail")
-
\ No newline at end of file
+