Using Perl Dancer and Docker to create simple monitoring system

I needed a simple system to monitor events. I wanted to have a system where I can specify that object with some name is 'ok' or 'fail'. And I wanted the system to be able to expire statuses. In case there is no data for the object for a long time then the status should be automaticly changed to 'unknown' — to handle situations when script that sends data breaks.

I looked for several systems, but none suited me well, so I've written my own very simple solution with the name 'curry' (it is named after delicious indian dish, not after Haskell Curry =)

Here is the source code — https://github.com/bessarabov/curry

The system is a web server that is powered by Dancer and the system is bundled into an image with Docker.

I really like this way of creating web apps with Dancer & Docker. Every time there is a new commit in git report Docker Hub automatically builds new image.

Here is the power of Docker, to run curry you need to install Docker and when you have docker installed you need to enter just one (!!!) command to have curry up and running:

docker run --publish 15000:3000 bessarabov/curry:1.0.0

This command downloads image from Docker Hub and runs it. This will create web server on port 15000 on your Docker (in case of linux the Docker usually works on 127.0.0.1, is case of mac you can find our Docker ip with the command boot2docker ip and in case of windows read the docs).

This way of running is super simple and it works pretty well to play a bit with this project, but in production you should do several more things. First of all you need to create persistent storage for curry. Curry stores all its data in sqlite database stored in file. To make persistend storage you should store that file outside the docker container (more details in the docs). The other thing that you may like to do in prodoction environment is to add authorization and to run it on https.

So, we have curry up and running, I would like to show several real life examples.

Setting the object with the name 'zero_inbox' to 'ok':

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/set?path=zero_inbox&status=ok&expire=1d"

You can see that we also specified "expire=1d". You must specify this parameter with your first request. The "X-Requested-With" header is used to prevent CSRF attacks.

Let's set one more object:

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/set?path=jenkins&status=fail&expire=1d"

So now we have information about statuses of two object. Curry has several endpoints that allows get information about current situation.

With endpoint "get" you can get info about all objects with problems:

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/get"

It will return:

{
   "success" : true,
   "result" : {
      "status" : "fail",
      "objects" : [
         {
            "path" : "jenkins",
            "status" : "fail"
         }
      ]
   }
}

True value for "success" tells us that endpoint worked fine and gave us answer that we can see in "result" value. "result.status" is "fail" that means that we have some objects with statues "fail" or "unknown". In the "result.objects" we have an array with the broken objects.

There is also an endpoint "get_all". It has the exact answer structure, but gives information about all objects:

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/get_all"

{
   "success" : true,
   "result" : {
      "status" : "fail",
      "objects" : [
         {
            "path" : "jenkins",
            "status" : "fail"
         },
         {
            "path" : "zero_inbox",
            "status" : "ok"
         }
      ]
   }
}

Lets set that jenkins is fixed (as you can see for the second request we can not specify "expire"):

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/set?path=jenkins&status=ok"

Now we have two objects in curry and all of them have "ok" status. We can check that with "get" endpoint:

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/get"

{
   "success" : true,
   "result" : {
      "status" : "ok",
      "objects" : []
   }
}

There is one more endpoint in curry that allow inspecting the current situation. It is endpoint "get_object" that returns all known info about the object:

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/get_object?path=jenkins"

{
   "success" : true,
   "result" : {
      "path" : "jenkins",
      "status" : "ok",
      "expire" : "1d",
      "history" : [
         {
            "status" : "fail",
            "dt" : "2015-02-09 14:23:23"
         },
         {
            "dt" : "2015-02-09 14:33:41",
            "status" : "ok"
         }
      ]
   }
}

So this is all that curry can do. It is just a simple storage of the objects statuses. There is no webinterface — one can use JSON endpoint and add it to existing dashboards.

So, here is my tiny project and I would be extremely happy to hear from you what do you think. Please you the comments, or write GitHub Issue or email me.

Leave a comment

About Ivan Bessarabov

user-pic I blog about Perl.