Creating your own health check monitor with Node-RED
Tags: javascript, webdev, productivity, beginners
Published: 2018-12-30 11:04:17

---
title: Creating your own health check monitor with Node-RED
published: true
description: How to create a Node-RED flow to monitor a website with status code and contents checks, sending notifications to email and Slack
tags: javascript, webdev, productivity, beginners
cover_image: https://thepracticaldev.s3.amazonaws.com/i/s7tgqlxl8k98axt8fcmh.png
---

If you are running your own blog, a SaaS application or a forum, you probably have encountered uptime/health monitors such as https://uptimerobot.com and their competitors (there are plenty of them: https://alternativeto.net/software/uptimerobot). In this short tutorial we will build our own simple (but flexible, that you can extend well beyond of what other tools can offer).

Our website health monitor will be:

1. Querying 3 websites
2. Checking their response status codes and contents
3. Rate-limiting notifications
3. Sending notifications to both email and Slack

The flow looks like this: 

![the flow](https://thepracticaldev.s3.amazonaws.com/i/s7tgqlxl8k98axt8fcmh.png)

## What is Node-RED?

From https://nodered.org/:

> Node-RED is a programming tool for wiring together hardware devices, APIs and online services in new and interesting ways. It provides a browser-based editor that makes it easy to wire together flows using the wide range of nodes in the palette that can be deployed to its runtime in a single-click.

Getting started guide can be found [here](https://nodered.org/docs/getting-started/).

Even though my preferred language is Go, I find working with Node-RED a lot of fun :)

## Step 1: Time ticker

Time ticker is a simple **inject** node from the **input** category. Configure *interval* based on your needs, we will be adding some message rate limiting so you can even set it to 1 or 5 seconds. In my example I set it to 30s:

![configure ticker](https://thepracticaldev.s3.amazonaws.com/i/5pnvmkfolmg11idaqa42.png)

We don't care about topic or payload, it can be injecting anything. The only thing we need from it is to trigger further actions. 


## Step 2: Making requests

To make requests will be using **http request** node from the **function** category. 

![http request node configuration](https://thepracticaldev.s3.amazonaws.com/i/vfmsi95exuo1gdpef9s2.png)

As you can see, it's really straightforward. No additional configuration here is required. This node will make a GET request and return a message that will have multiple fields but we only care about:

* **statusCode** - we will check this to be 200.
* **responseUrl** - we will incorporate it into the warning message.
* **payload** - this is the actual response body that contains the HTML. We will check whether it contains a certain phrase that we know should be there.

## Step 3: Validating responses

In this step we will add a simple HTTP status code validation (if the website is down, you won't get 200 response). However, sometimes you can still get 200 (from your reverse proxy displaying an empty page) or just website update going wrong. In those cases you will want to check the response body to get some specific phrases or keywords that should be there.

#### Checking response status code

To validate response status code we will use a **switch** node from the **function** category:

![switch node config to check status code](https://thepracticaldev.s3.amazonaws.com/i/5ns0thxfuf4x3tygkvx0.png) 

#### Checking response body contents

To check response body contents I couldn't find "doesn't contain" option in the switch, so I just inverted the logic and chose second output like this:

![switch node config for 'does not contain' path](https://thepracticaldev.s3.amazonaws.com/i/3jmv495dghdx8qjta171.png)

Then, we just connect the second output (leaving first one empty) and we get what we want :) 

## Step 4: Generate payloads

This step is really up to you and what you want to display. For the **Slack** payload we need to format a simple JSON message so we will use a **function** node from the **function** category. 

The function for the bad response body looks like:

```javascript
return {
    payload: `{"response_type": "in_channel", "text": "[WARNING] ${msg.responseUrl} URL returned unexpected contents, please investigate" }`,
    topic: msg.topic
}
```

And for the wrong status code:


```javascript
return {
    payload: `{"response_type": "in_channel", "text": "[WARNING] ${msg.responseUrl} responded with status code '${msg.statusCode}'" }`,
    topic: msg.topic
}
```

Email doesn't need to be JSON payload so it looks like:

```javascript
return {
    payload: `[WARNING] ${msg.responseUrl} responded with status code '${msg.statusCode}'`,
    topic: msg.topic
}
```

You can try adding more information based on what triggered the flow. In this case we want to differentiate payloads based on whether the status code or the response body contents were unexpected. 

## Step 5: Slack and email notifications

Before setting up notification nodes, I would really recommend adding rate-limiting to your flow as a stream of emails/Slack messages will be distracting you at the worst possible time :)

Rate limit can be added through a **delay** node from the **function** category. Configuration looks like:

![rate limit config](https://thepracticaldev.s3.amazonaws.com/i/7gyiv1nh70ees5293ps2.png)

> TIP: if you add a rate-limit per topic, your messages will not appear. After the first message, it will wait for the full duration to receive any new messages and will only display them then. You could, however, create a separate delay for each website, to rate-limit events there. 

As for notifications, there are many ways. I chose two: Slack and email. For Slack notifications, we create an **http request** node that will send the payloads (that we generated in the previous step) to an 'incoming webhooks URL' such as `https://hooks.slack.com/services/............`. You can read about them here: https://api.slack.com/incoming-webhooks. 

For email, we will use an **email** node from the **social** category. For gmail users, you can generate an 'App Password' here: https://support.google.com/accounts/answer/185833. 


## ./wrap_up 

While there are plenty of monitoring services that have free tiers, they usually can't match the flexibility of Node-RED when it comes to testing specific features. With Node-RED we can:

* Set whatever frequency of checks we want
* Do multiple actions on the websites or use different, non-HTTP protocols 
* Integrate into whatever notification system we have (send webhooks, Slack, Telegram, Twilio or even create a new ticket in our internal issue tracker)

Obviously, there are also downsides, such as:

* Even though it's easy, you actually have to create these flows instead of just supplying a URL to that 3rd party service
* Those services usually have multiple deployments of their applications around the world so the datacentres, where they are hosting their apps can fail without ruining their business (if your RPI with Node-RED dies, you won't get warnings unless you monitor your RPI too, which is totally doable :) ). 

I would suggest having a mix of public SaaS offerings (you can have a free tier on them) and your own custom monitoring applications that do better, deeper tests of your main services. You can also register a monitor in uptimerobot to test your Node-RED monitoring app. It is highly unlikely that your Node-RED instance, uptimerobot, and your SaaS application would fail at the same time without you getting notified :) 

## What's next

In the next post, I will demonstrate how to create a lot more interesting, an asynchronous flow that would be doing an end-to-end test of a SaaS application.