Sharing the Stats¶
Junior
Good morning!
Senior
Just about time… We are in trouble!
The report stuff was a complete success, so much so that now Susan has hired a frontend developer to create a custom dashboard to see the stats in real time.
Now we have to provide the backend for the solution.
Junior
And what’s the problem?
Senior
We are not developers! What are we doing writing a backend?
Junior
Just chill out. Can’t be that difficult… What do they need, exactly?
Senior
We have to provide a new endpoint to serve the same data but inJSON
format.
Junior
So, we have half of the work done already!
What about this?
kapow route add /capacitystats - <<-'EOF' echo "{\"memory\": \"`free -m`\"}" | kapow set /response/body EOF
Senior
For starters, that’s not valid
JSON
. The output would be something like:$ echo "{\"memory\": \"`free -m`\"}" {"memory": " total used free shared buff/cache available Mem: 31967 3121 21680 980 7166 27418 Swap: 0 0 0"}You can’t add new lines inside a
JSON
string that way, you have to escape the new line characters as\n
.
Junior
Are you sure?
Senior
See for yourself.
$ echo "{\"memory\": \"`free -m`\"}" | jq parse error: Invalid string: control characters from U+0000 through U+001F must be escaped at line 3, column 44
Junior
jq? What is that command?
Senior
jq is a wonderful tool for working withJSON
data from the command line. With jq you can extract data from aJSON
document and it also allows you to generate a well-formedJSON
document.
Junior
Let’s use it, then!
How can we generate a
JSON
document with jq?
Senior
To generate a document we use the
-n
option:$ jq -n '{"mykey": "myvalue"}' { "mykey": "myvalue" }
Junior
That does not seem very useful. The output is just the same.
Senior
Bear with me, it gets better. You can add variables to the
JSON
and jq will escape them for you.$ jq -n --arg myvar "$(echo -n myvalue)" '{"mykey": $myvar}' { "mykey": "myvalue" }
Junior
Sweet! That’s just what I need.
(hacks away for a few minutes).
What do you think of this?
$ jq -n --arg host "$(hostname)" --arg date "$(date)" --arg memory "$(free -m)" --arg load "$(uptime)" --arg disk "$(df -h)" '{"hostname": $host, "date": $date, "memory": $memory, "load": $load, "disk": $disk}' { "hostname": "junior-host", "date": "Tue 26 Nov 2019 05:27:24 PM CET", "memory": " total used free shared buff/cache available\nMem: 31967 3114 21744 913 7109 27492\nSwap: 0 0 0", "load": " 17:27:24 up 10:21, 1 user, load average: 0.20, 0.26, 0.27", "disk": "Filesystem Size Used Avail Use% Mounted on\ndev 16G 0 16G 0% /dev" }
Senior
That is the output we have to produce, right. But the code is far from readable. And you also forgot about adding the endpoint.
Can we do any better?
Junior
That’s easy:
kapow route add /capacitystats - <<-'EOF' jq -n \ --arg hostname "$(hostname)" \ --arg date "$(date)" \ --arg memory "$(free -m)" \ --arg load "$(uptime)" \ --arg disk "$(df -h)" \ '{"hostname": $hostname, "date": $date, "memory": $memory, "load": $load, "disk": $disk}' \ | kapow set /response/body EOFWhat do you think?
Senior
I’m afraid you forgot an important detail.
Junior
I don’t think so! theJSON
is well-formed and it contains all the required data. And the code is quite readable.
Senior
You are right, but you are not usingHTTP
correctly. You have to set theContent-Type
header to let your client know the format of the data you are outputting.
Junior
Oh, I see. Let me try again:
kapow route add /capacitystats - <<-'EOF' jq -n \ --arg hostname "$(hostname)" \ --arg date "$(date)" \ --arg memory "$(free -m)" \ --arg load "$(uptime)" \ --arg disk "$(df -h)" \ '{"hostname": $hostname, "date": $date, "memory": $memory, "load": $load, "disk": $disk}' \ | kapow set /response/body echo application/json | kapow set /response/headers/Content-Type EOF
Senior
Better. Just a couple of details.
You have to set the headers before writing to the body. This is because the body can be so big that Kapow! is forced to start sending it out.
In cases where you want to set a small piece of data (like the header), it is better not to use
stdin
. Kapow! provides a secondary syntax for these cases:$ kapow set <resource> <value>
Junior
Something like this?
kapow route add /capacitystats - <<-'EOF' kapow set /response/headers/Content-Type application/json jq -n \ --arg hostname "$(hostname)" \ --arg date "$(date)" \ --arg memory "$(free -m)" \ --arg load "$(uptime)" \ --arg disk "$(df -h)" \ '{"hostname": $hostname, "date": $date, "memory": $memory, "load": $load, "disk": $disk}' \ | kapow set /response/body EOF
Senior
That’s perfect! Now, let’s upload this to the Corporate Server and tell the frontend developer about it.