Your backup script stopped running in March. You found out in July.
That is the problem both of these tools exist to solve. A cron job pings a URL when it finishes. No ping, no news, and something tells you.
Healthchecks.io does that one job well. Central Logging does it as one feature of a log server. This page is about which shape you want, and it starts by saying what Healthchecks.io is better at, because that list is not short.
Healthchecks.io is open source and you can self-host it for free. It is a Django application under a BSD licence. There is also a hosted free tier that covers a lot of hobby projects.
So if cron monitoring is all you need, do not buy anything. Run their project, or use the free tier, and be done.
The case for Central Logging is only interesting if you also want log aggregation, uptime checks and host monitoring, and you would rather run one binary than a Python app with a database next to three other tools.
This is a real design split, not a feature-list difference.
Healthchecks.io asks you to declare the schedule. You give it a cron expression or a period, plus a grace time. It knows the job should have run at 03:00, it waits out the grace, then it alerts. It knows this before the job has ever run once.
Central Logging works it out from the pings. It keeps the last 100 complete pings for a job, takes the median gap between them, and expects the next one at last ping plus that median. Drift past that by more than 20% and the job is unhealthy. The check runs every minute.
Neither is strictly better.
Learned schedules mean there is nothing to configure. No cron expression to keep in sync with the actual crontab, which is a class of bug in itself — a job rescheduled to hourly and a monitor still expecting daily is a false alarm generator. Add the ping to the job, and the monitor exists.
Declared schedules are precise, and they work from the first run. Central Logging needs at least two completed pings before it has any idea what normal looks like, and a job with genuinely irregular timing gives it a wobbly baseline. A job that has pinged once is never considered late.
If your jobs run on a regular clock, the learned approach saves you configuration and drifts into correctness. If your jobs are irregular, or if you need alerting to be right on the very first missed run, declare the schedule and use Healthchecks.
| Healthchecks.io | Central Logging | |
|---|---|---|
| Deploy | Hosted, or self-host a Django app + database | One binary |
| Schedule | You declare cron expression + grace | Learned from ping history |
| First-run coverage | Yes | Needs 2+ completions |
| Ping states | start, success, fail, exit codes, log body | start, complete, fail, exit codes |
| Per-run detail captured | Full output, in the ping body | A 500-character message, plus numeric metrics that are charted |
| Notification channels | Email, SMS, and a long list of integrations | Slack, Telegram, Pushover |
| Log aggregation | No | Yes |
| Uptime monitoring | No | Yes |
| Host monitoring | No | Yes |
| Licence | BSD open source, or hosted plans | $187 once |
Create one API key in Central Logging. Job names are made up on the spot — no registration step per job.
curl "https://logs.example.com/p/YOUR-API-KEY/nightly-backup?state=complete"
Wire it to the job so it only fires on success:
0 3 * * * /usr/local/bin/backup.sh && curl -fsS "https://logs.example.com/p/YOUR-API-KEY/nightly-backup?state=complete"
Send start at the top of the job if you want the attempt on record even when the job dies partway:
curl "https://logs.example.com/p/YOUR-API-KEY/nightly-backup?state=start"
/usr/local/bin/backup.sh
curl "https://logs.example.com/p/YOUR-API-KEY/nightly-backup?state=complete"
The job page then shows the detected run frequency, when the next check-in is due, and the last ten pings with their state, time and source IP. Full details in cron monitoring.
A ping can also carry a short message, an exit status and numbers. What it cannot carry is the job’s whole output. Healthchecks.io accepts that in the request body and shows it beside the run. Central Logging keeps output in log sources instead.
A job that knows it failed should say so. Send state=fail and the notification goes out within a minute:
/usr/local/bin/backup.sh || curl -fsS "https://logs.example.com/p/YOUR-API-KEY/nightly-backup?state=fail&status_code=$?&message=backup+failed"
The status_code and message travel with the alert, so the message you get names the job and says what broke.
A job that fails every run does not message you every run. The first failure notifies. The next stays quiet until the job completes successfully, or until a day has passed.
The second way is the ping that never arrives. A job killed by the OOM killer sends nothing, so the lateness check is what catches it — on the job’s own timescale. An hourly job is roughly twelve minutes late before it fires. A daily job is closer to five hours.
That is the same shape as Healthchecks.io grace periods, with one difference worth knowing: Healthchecks lets you set the grace per job. Central Logging derives it from the job’s own history and you cannot tune it. If a specific job needs a tighter window than 20% drift, declare the schedule in Healthchecks instead.
When any alert fires you get a message naming the job and linking to it, and a recovery message when it checks in again.
A ping can carry more than a state. Add metric=name:value pairs and the job page charts each one across the last 100 runs:
curl "https://logs.example.com/p/YOUR-API-KEY/nightly-backup?state=complete&status_code=0&metric=duration:418.44&metric=tables:3319"
That is how you notice a backup getting slower months before it starts timing out. Healthchecks.io captures the run’s output text; Central Logging captures its numbers and plots them. Different answers to “what happened on this run” — pick the one you would rather read.
Here is the thing single-purpose cron monitoring cannot do.
A job fails. You get the alert. Now you want to know why — and the output of that job is somewhere else. Another tab, another tool, another login, and you are matching timestamps by hand.
In Central Logging the job’s logs are in the same place as the job’s health. Pipe the output to the ingest endpoint:
/usr/local/bin/backup.sh 2>&1 | curl -X POST --data-binary @- \
https://logs.example.com/api/v1/ingest_logs/YOUR-SOURCE-TOKEN
Then the alert, the run history and the actual error output are one search apart, on the same clock. The cron monitoring guide walks through the whole setup.
That is the entire pitch. Not that the cron monitoring is better — it is simpler, and it gives you less control over when a late job counts as late. The pitch is that it sits next to your logs, your uptime checks and your host check-ins, in one process you already run.
Use Healthchecks.io if cron monitoring is the only thing you need, if you need email or SMS alerts, if your jobs run on irregular schedules, or if a failing job has to page someone within seconds.
Use Central Logging if you are already going to run something for logs, and you would rather that same binary watch your cron jobs, your websites and your servers than add three more services to maintain.
The free download is the complete product, not a trial. Add one ping to one cron job and see whether the consolidation is worth it to you.
14-day refund if you buy and it does not fit.
💌 Get notified on new features and updates