Vinícius Silva
Vinícius Silva Author of @iviniciusls | Application Developer & DevOps @ IBM | Graduated in System Analysis and Development @ FATEC | Indaiatuba, SP - Brazil.

Creating a bot for monitoring applications with Telegram, NodeJS and Amazon Lambda

Creating a bot for monitoring applications with Telegram, NodeJS and Amazon Lambda

One of the greatest features on Telegram, in my humble opinion (and I know there’s a lot of them there), is the possibility of creating some useful customizable bots through some cool APIs. And, of course, NodeJS has packages to wrap these APIs. So why wouldn’t we use it in our favor to get some monitoring advantage on our applications? So let’s see an quick way to do that!

Some time ago when I was developing a simple application to a small client (so consider that it wasn’t worth for both of us to invest in a robust infrastructure and setup) I thought: What is the simplest thing I can do to monitor my application using a bot to notify me? Then I found Telegram Bots and decided to implement a quick job to simple perform a request to each application that I had and check if the application is up and running. And using NodeJS is really simple to do that!

Let’s do it

First of all we need to create two .ini files on root:

  • config.ini will contain the list of the URLs to be monitored:
    1
    2
    3
    4
    
    // config.ini
    [monitor]
    urls[]=https://www.viniciusls.com.br
    urls[]=https://about.me/vinicius.silva
    
  • telegram.ini will contain the bot information generated by Telegram. Read more [here] on how to create a Telegram bot:
    1
    2
    3
    
    // telegram.ini
    token=<TELEGRAM_BOT_TOKEN_ID> #Token generated by BotFather when your bot was created on Telegram;
    chatId=<TELEGRAM_CHAT_ID> # Identifier of a chat between you and your bot on Telegram.
    

We are ready to start coding. We will start by importing some libraries:

1
2
3
4
5
const fs = require('fs'); // Used to read ini files containing the list of applications to be monitored and Telegram configuration
const ini = require('ini'); // Used to parse .ini file into JSON
const path = require('path'); // Using to obtain the path for the .ini files
const request = require('request'); // Used to perform the request to each endpoint to be monitored
const Telegram = require('telegraf/telegram'); // Telegram API Wrapper (you can use any other of your preference)

Now we need to create a function and export it. First step inside this function will be to read the .ini files containing the configuration needed:

1
2
3
exports.handler = (event, context, callback) => {
    const config = ini.parse(fs.readFileSync(path.resolve('./config.ini'), 'utf-8')); // This is the .ini file containing the list of URLs to be monitored. First we resolve its path, then we read it (no need to be asynchronous in this example) and finally we parse it to a JSON object
    const telegramConfig = ini.parse(fs.readFileSync(path.resolve('./telegram.ini'), 'utf-8')); // This is the .ini file containing the Telegram Bot configuration. First we resolve its path, then we read it (no need to be asynchronous in this example) and finally we parse it to a JSON object

Let’s instantiate the Telegram object using the token that we read from telegram.ini file:

1
    const telegram = new Telegram(telegramConfig.token);

Save the URLs list to a const just to make it easily to read:

1
    const urls = config.monitor.urls;

And we are ready to iterate over this list, perform a request, wait for the status code to notify if any of them is down or responding with any error:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    for (const url of urls) {
        console.log(`Trying to request ${url}...`);

        request.get(url, (err, res, body) => { // Perform a simple GET request to the URL. I'd recommend you to implement a simple URL returning a cool message or even a test database response (to check if database connectivity is working).
            if (res && res.statusCode === 200) { // If statusCode === 200, then the request is successful, so no need to be alerted (but you can if you wanna)
                return;
            }

            const date = new Date(); // Get server timestamp

            const message = `The application located at ${url} is DOWN on ${date}!`; // Create a cool message to be sent on the alert

            console.log(message);
            // Call telegram bot to send message alerting that the application is down!
            telegram.sendMessage(telegramConfig.chatId, message)
                .then(() => {
                    console.log('Message sent to Telegram Bot');
                    
                    callback(null, `Message about ${url} sent to Telegram Bot`); // Call the callback received as handler function parameter
                })
                .catch(() => {
                    callback(new InternalError(`Error on sending message! Message: ${message}`)); // Call the callback received as handler function parameter
                });

            // You can also do this way (nowadays I'd prefer this approach)
            //try {
            //    await telegram.sendMessage(telegramConfig.chatId, message);
            //
            //    console.log('Message sent to Telegram Bot');
            //        
            //    callback(null, `Message about ${url} sent to Telegram Bot`); // Call the callback received as handler function parameter
            //} catch (e) {
            //    callback(new InternalError(`Error on sending message! Message: ${message}. Error: ${e}`));  // Call the callback received as handler function parameter
            //}
        });
    }
}; // Closing the exports.handler function

Aaaaand… That’s it! Your bot is ready to work. You can run it by calling node -e 'require("./app").handler()';

But how can I put this online to run it every x minutes? Well, of course you can add it as a crontab entry in your server. But this is not a good practice as your server might be down (and that can be the same reason your application is down) so you won’t be notified. So you can add it as a crontab entry in another server to make it more realiable, right? Yes, maybe. I mean, it’s better than the first option. But I’d prefer to add this in a Function service provider like Amazon Lambda or IBM Cloud Functions. A Function service provider is a service where you can run your functions without servers and just pay by execution or by hours of execution or by scalling resources and has all the infrastructure security of these excelent companies paying a lower value than you would if you decide to take a server to run it. For this kind of script that we implemented which is simple and uses a minimum amount of resources, you’ll probably not be charged if you use these services. At least Amazon supports it on their Free Tier within forever. In fact, you can play a lot with Amazon Lambda (and I’d recommend you to do that, you’ll learn a lot of cool things) as they offer 1 million free requests per month (forever) on their Free Tier. I didn’t test this function with IBM Cloud Functions, but feel free to test it.

How to deploy if on Amazon Lambda?

All you’ll need is Amazon S3, Amazon Lambda and Amazon CloudWatch Events. Just follow these steps:

  • If you don’t have the project, you can download the project as .zip from my GitHub repo;
  • Enter into project directory and run npm install;
  • Create a file called telegram.ini containing the following:
    1
    2
    
      token=<TELEGRAM_BOT_TOKEN_ID> #Token generated by BotFather when your bot was created on Telegram;
      chatId=<TELEGRAM_CHAT_ID> # Identifier of a chat between you and your bot on Telegram.
    
  • Configure all URL’s that will be monitored by the bot on config.ini file;
  • Zip the project folder using zip -r9 <your_zip_name>.zip *
  • Send the zip to Amazon S3 (it’s mandatory due to the zip size (~14MB));
  • Configure a cron using Amazon CloudWatch Events to Amazon Lambda function that you’ve created.

P.S.: If you have doubt on how to do any of these steps on Amazon, please comment it. I’ll post some screenshots and additional steps here in this same post soon.

And it’s done, you should have your script running now on the frequency you defined and sending a message to your bot to warn you in case of any errors on any URL that you add to be monitored :)

Check it out on GitHub

You can check and test this implementation by cloning my repo on GitHub. Feel free to implement more features on this and test as much as you like! :)

Conclusion

So, that’s it! I hope I could help you to add a quick monitoring tool to your stack, improving your coverage around your applications. Feel free to ask me anything about this subject or any other subject that you wanna see here in this space using the comments section below :) See ya!

Follow me on Twitter/LinkedIn

If you liked my content or wanna get in contact with me, please take a moment to follow me on Twitter and LinkedIn.

comments powered by Disqus