chart.jsでサーバリソースをリアルタイム可視化してみた

#1.はじめに

あるlinuxサーバで原因不明のメモリリークが発生しました。

しかし、そのサーバは陸の孤島にあったのです。

なんとか陸の孤島にたどり着き原因を解明し事なきを得ましたが、
次また問題が発生したときに同じ思いをすることになります。

###「Webでリソース監視しよう。。」

git上に**[デモページ](https://m0nch1.github.io/resource-chart/)**をupしましたので、先にご覧ください。
※本来はphp使ってるのですが、githubなのでhtml化にしてます
※csvは2月20日～22日に3日間で、Display Timeはアクセス時点から一時間前になるようにしてます

#2.構成について

実はこのシステムはWeb/APサーバ3台をロードバランサーで負荷分散していました。

そのため以下のような流れで構成を考えました。

![Flowchart.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174125/40cbeef3-4483-2045-baf9-7e0890b77ee0.jpeg)

各サーバ、cronでシェルスクリプトを毎分実行し、1分毎のリソースをCSVデータに蓄積します。

Webページ本体はWeb/AP03に配置し、AP01とAP02のCSVデータを5分毎にAP03にSSHでコピーします。

そして、集積されたCSVデータより各サーバのリソース情報をChart.jsでビジュアライズ化します。

UIもラクしたかったので、今回は無料版の[MDB（Material Design for Bootstrap）](https://mdbootstrap.com/)を使ってみることにしました。

#3.環境について

- OS => CentOS release 6.9 (Final)
- Kernel =>　2.6.32-696.16.1.el6.x86_64 x86_64
- Shell =>　GNU bash, version 4.1.2(2)-release (x86_64-redhat-linux-gnu)
- Chart.js =>　2.7.3
- Material Design for Bootstrap => MDB FREE: 4.7.1

#4.Chart.jsについて

<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174125/8a4644c0-4990-3b7d-5af6-54d6b32b3940.png" alt="属性" title="タイトル">
</div>

[Chart.js](https://www.chartjs.org/)とは、とってもかわいいグラフがサクッと作成できるJavascriptライブラリ。

Canvas要素を用いて描画しており、様々なグラフを描画することが可能です。
アニメーションもFeel so good.

見た目と使いやすさを兼ね備えたChart.jsでリソース情報を表示してモチベーションをアゲていきます。

#5.リソース情報をCSVデータとして蓄積

cronでシェルスクリプトを一定時間間隔（今回は毎分）で実行し、結果をcsvファイルに蓄積していきます。

シェルスクリプトの中身ですが、
リソース結果を返してくれるコマンドを実行し、その結果からグラフ表示したい部分のみをカンマ区切りに整形します。

そして、整形した一行のデータをcsvファイル下部に追加していきます。

各データの頭には、実行時間（YYYY/MM/DD HH : mm : ss）を付与しておきます。

###取得したいリソース情報を整理

以下コマンドを実行し得られる結果からそれぞれのグラフを描画していきます。

###メモリ使用率

- **freeコマンド**
    - 実メモリの使用量
    - バッファ・キャッシュの容量を加算したメモリの使用量
    - スワップメモリの使用量

```console
[root@localhost ~]# free
             total       used       free     shared    buffers     cached
Mem:       1205392     175156    1030236        468      10796      60060
-/+ buffers/cache:     104300    1101092
Swap:      1015804          0    1015804
```
freeコマンドの見方は以下をご覧ください。

`Mem` 
=> 実メモリのサイズ
`-/+ buffers/cache` 
=> ページキャッシュとバッファキャッシュを考慮したメモリサイズ
`Swap` 
=> スワップに割り当てたサイズ

コマンド結果から以下のリソースをCSVファイルに蓄積していきます。

`Mem:total`
=>実メモリの全容量
`Mem:used`
=>実メモリの使用容量
`-/+ buffers/cache:used`
=>実メモリのusedからbuffersとcachedを引いた容量
`Swap:total`
=>スワップ領域の全容量
`Swap:used`
=>スワップ領域の使用容量

###CPU使用率&スワップ

- **vmstatコマンド**
    - CPUの使用率
    - スワップイン・アウトの情報

```console
[root@localhost ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 1029624  11004  60072    0    0   196     9   51   74  1  2 97  0  0
```

vmstatコマンドの結果から、`swap`と`cpu`の部分を抽出します。

`swap:si`
=>ディスクからスワップインされたメモリ量
`swap:so`
=>ディスクにスワップアウトされたメモリ量

`cpu:us`
=>カーネル以外が使用したCPU使用率
`cpu:sy`
=>カーネルが使用したCPU使用率
`cpu:id`
=>アイドル状態の割合
`cpu:wa`
=>I/Oウェイトにかかった割合
`cpu:st`
=>ゲストOSがリソース要求を行ったが、CPUリソースを割り当ててもらえなかった時間の割合

###ロードアベレージ

- **topコマンド**
    - 実行中のプロセス
    - ロードアベレージの情報

```console
[root@localhost ~]# top -a -b -n 1 | sed -n '8,17p'
 1272 mysql     20   0  368m  27m 5048 S  0.0  2.3   0:00.55 mysqld
 1380 root      20   0  255m 9140 3744 S  0.0  0.8   0:00.30 httpd
 1416 daemon    20   0  591m 9128 1336 S  0.0  0.8   0:00.00 httpd
 1417 daemon    20   0  591m 9128 1336 S  0.0  0.8   0:00.00 httpd
 1415 daemon    20   0  591m 9124 1332 S  0.0  0.8   0:00.00 httpd
 1611 root      20   0  102m 4604 3548 S  0.0  0.4   0:00.07 sshd
 1537 postfix   20   0 81332 4164 3028 S  0.0  0.3   0:00.00 local
 1535 postfix   20   0 81176 3600 2684 S  0.0  0.3   0:00.00 cleanup
 1374 postfix   20   0 81100 3580 2656 S  0.0  0.3   0:00.00 qmgr
 1373 postfix   20   0 81032 3480 2580 S  0.0  0.3   0:00.00 pickup

[root@localhost ~]# top -a -b -n 1 | sed -n "1p" | awk '{print $(NF-2) $(NF-1) $(NF)}'
0.00,0.00,0.00
```

一つ目のコマンドでコマンド実行時のプロセス上位10件を取得しています。
コマンドの詳細は以下になります。

```sh
top -a -b -n 1 | sed -n '8,17p'

=>topコマンドをメモリ使用率順にソートしバッチモードで１回実行し、
　その結果の８行目～１７行目を表示する

-a       # メモリ使用率順にソート
-b       # バッチモード
-n       # 実行回数を指定（上記の場合１回）

sed      # 入力に対してテキスト変換などを行うコマンド
-n       # 指示した行だけを標準出力にする。（上記の場合８～１７行目を出力）
```

二つ目のコマンドでロードアベレージを取得しています。
コマンドの詳細は以下になります。

```sh
top -a -b -n 1 | sed -n "1p" | awk '{print $(NF-2) $(NF-1) $(NF)}'

=>topコマンドをメモリ使用率順にソートしバッチモードで１回実行し、
　その結果の1行目の最終フィールド、最終フィールドから１つ前、２つ前の３つを表示する

awk      # 入力された列に対して、フィールド区切りなどを指定するコマンド
　　　　　　（上記の場合、$(NF)で行の最終フィールドを指定。$(NF-1)は最後から一つ前）
```

###セッション数

- **netstatコマンド**
    - StateがESTABLISHEDのセッション数
    - StateがTIME_WAITのセッション数
    - StateがLISTENのセッション数

```console
[root@localhost ~]# netstat -tan | grep ':80 ' | awk '{print $6}' | grep 'ESTABLISHED' | sort | uniq -c
      1 ESTABLISHED
[root@localhost ~]# netstat -tan | grep ':80 ' | awk '{print $6}' | grep 'LISTEN' | sort | uniq -c
      1 LISTEN
[root@localhost ~]# netstat -tan | grep ':80 ' | awk '{print $6}' | grep 'TIME_WAIT' | sort | uniq -c
      1 TIME_WAIT
```

stateについては以下の通りです。

`ESTABLISHED`
=>TCPでの接続が確立されて、現在通信が行われている状態
`TIME_WAIT`
=>接続終了待ちの状態
`LISTEN`
=>利用可能なポートの待ち受け状態

###シェルスクリプトでCSVファイルを作成＆データ蓄積

各リソース情報の取得コマンドが決まりました！
あとはcronで毎分実行するシェルスクリプトを作成します。

※以下はWebページを配置しているWeb/AP03のシェルスクリプトです。
csvファイルのパスの部分のみ、各サーバ名に変更する必要があります。

```resource_acquisition.sh
#!/bin/bash

DIR='/home/hoge/resources'
CSVDIR='/home/hoge/resources/csv'
TIMESTAMP=`/bin/date '+%Y%m%d%H%M'`

MEMORYARRAY=(`free`)
CPUARRAY=(`vmstat`)
PROSECCARRAY=(`top -a -b -n 1 | sed -n '8,17p'`)
LOADAVARAGE=(`top -a -b -n 1 | sed -n "1p" | awk '{print $(NF-2) $(NF-1) $(NF)}'`)
STATE=(`netstat -tan | grep ':80 ' | awk '{print $6}' | grep 'ESTABLISHED' | sort | uniq -c`)
STATL=(`netstat -tan | grep ':80 ' | awk '{print $6}' | grep 'LISTEN' | sort | uniq -c`)
STATT=(`netstat -tan | grep ':80 ' | awk '{print $6}' | grep 'TIME_WAIT' | sort | uniq -c`)

if [ ! -d $CSVDIR/$(date +%Y) ]; then
   mkdir $CSVDIR/$(date +%Y)
fi

if [ ! -d $CSVDIR/$(date +%Y)/$(date +%Y_%m) ]; then
   mkdir $CSVDIR/$(date +%Y)/$(date +%Y_%m)
fi

if [ ! -d $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d) ]; then
   mkdir $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)
   mkdir $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP01
   mkdir $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP02
   mkdir $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP03
fi

#section "free" command
echo $TIMESTAMP,\
${MEMORYARRAY[7]},\
${MEMORYARRAY[8]},\
${MEMORYARRAY[15]},\
${MEMORYARRAY[18]},\
${MEMORYARRAY[19]} \
>> $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP03/memory.csv

#section "vmstat" command
echo $TIMESTAMP,\
${CPUARRAY[29]},\
${CPUARRAY[30]},\
${CPUARRAY[35]},\
${CPUARRAY[36]},\
${CPUARRAY[37]},\
${CPUARRAY[38]},\
${CPUARRAY[39]} \
>> $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP03/cpu.csv

#section "top" command
cnt=10
incnt=12
PICTMP=()

for i in `seq $cnt`
do
   for j in `seq $incnt`
   do
      PICTMP+=(${PROSECCARRAY[(j-1)]})
   done
done

RESULT=$(echo ${PROSECCARRAY[@]} | sed 's/ /,/g')

echo $TIMESTAMP,\
$LOADAVARAGE,\
$RESULT \
>> $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP03/process.csv

#section "netstat" command
if [ "${STATE[0]}" = '' ]; then ANS1=0;else ANS1=${STATE[0]};fi
if [ "${STATL[0]}" = '' ]; then ANS2=0;else ANS2=${STATL[0]};fi
if [ "${STATT[0]}" = '' ]; then ANS3=0;else ANS3=${STATT[0]};fi

echo $TIMESTAMP,$ANS1,$ANS2,$ANS3 \
>> $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP03/session.csv

```

上部の変数でディレクトリのパスやら、コマンドやらを格納しています。
※コマンド結果を変数に入れることができるのをこの時知りました。。

変数以下のif文でディレクトリがない場合作成し、その後、各リソース情報をcsvファイルに書き込んでいます。

csvファイルはコマンド単位で作成しています。

名前がわかりづらくなってしまいました。。

**vmstatコマンドの結果 => cpu.csv**
**freeコマンドの結果 => memory.csv**
**topコマンドの結果 => process.csv**
**netstatコマンドの結果 => session.csv**

そして、Web/AP01とWeb/AP02にはリソース取得のスクリプトのほかに、以下のシェルスクリプトを仕込みます。

```resource_transfer.sh
#!/bin/bash

DIR='/home/hoge/resources'
CSVDIR='/home/hoge/resources/csv'

cat $DIR/cpu.csv | ssh 192.168.1.1 "cat >> $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP01/cpu.csv"
cat $DIR/memory.csv | ssh 192.168.1.1 "cat >> $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP01/memory.csv"
cat $DIR/process.csv | ssh 192.168.1.1 "cat >> $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP01/process.csv"
cat $DIR/session.csv | ssh 192.168.1.1 "cat >> $CSVDIR/$(date +%Y)/$(date +%Y_%m)/$(date +%m%d)/WebAP01/session.csv"

: > $DIR/cpu.csv
: > $DIR/memory.csv
: > $DIR/process.csv
: > $DIR/session.csv

```

catコマンドとsshコマンドを組み合わせることで、Web/AP03にcsvファイルの内容を送信しています。

**送信データのサイズを一定に保ちファイルの肥大化を防ぐため、下4行の「：＞～」を書いておくことで、送信後にcsvファイルを空に上書きしています。**

そのほかに1年分のリソースを取得した際（1月1日に実行されるcron）のシェルスクリプト等もありますが割愛します。

#6.CSVデータをもとにChart.jsを描画

シェルスクリプトによって作成されたCSVファイルは以下のようになります。（一部抽出）

- freeコマンド

```console
[root@localhost WebAP03]# cat memory.csv
201906051322,1205392,164536,98072,1015804,0
201906051323,1205392,172540,103196,1015804,0
201906051324,1205392,173448,103844,1015804,0
201906051325,1205392,174704,104872,1015804,0
201906051326,1205392,177324,106588,1015804,0
```
- topコマンド

```console
[root@localhost WebAP03]# cat process.csv
201906051322,0.05,0.02,0.00,1274,mysql,20,0,368m,25m,5048,S,0.0,2.2,0:00.07,mysqld,1382,root,20,0,255m,9144,3744,S,0.0,0.8,0:00.02,httpd,1391,daemon,20,0,591m,9132,1336,S,0.0,0.8,0:00.00,httpd,1392,daemon,20,0,591m,9132,1336,S,0.0,0.8,0:00.00,httpd,1390,daemon,20,0,591m,9128,1332,S,0.0,0.8,0:00.00,httpd,1517,postfix,20,0,81332,4164,3032,S,0.0,0.3,0:00.00,local,1515,postfix,20,0,81176,3604,2684,S,0.0,0.3,0:00.00,cleanup,1376,postfix,20,0,81100,3564,2656,S,0.0,0.3,0:00.00,qmgr,1375,postfix,20,0,81032,3480,2580,S,0.0,0.3,0:00.00,pickup,1369,root,20,0,80952,3468,2556,S,0.0,0.3,0:00.01,master
201906051323,0.02,0.02,0.00,1274,mysql,20,0,368m,27m,5048,S,0.0,2.3,0:00.09,mysqld,1382,root,20,0,255m,9144,3744,S,0.0,0.8,0:00.03,httpd,1391,daemon,20,0,591m,9132,1336,S,0.0,0.8,0:00.00,httpd,1392,daemon,20,0,591m,9132,1336,S,0.0,0.8,0:00.00,httpd,1390,daemon,20,0,591m,9128,1332,S,0.0,0.8,0:00.00,httpd,1517,postfix,20,0,81332,4168,3032,S,0.0,0.3,0:00.00,local,1515,postfix,20,0,81176,3604,2684,S,0.0,0.3,0:00.00,cleanup,1376,postfix,20,0,81100,3580,2656,S,0.0,0.3,0:00.00,qmgr,1375,postfix,20,0,81032,3484,2580,S,0.0,0.3,0:00.00,pickup,1369,root,20,0,80952,3468,2556,S,0.0,0.3,0:00.01,master
201906051324,0.00,0.01,0.00,1274,mysql,20,0,368m,27m,5048,S,0.0,2.3,0:00.12,mysqld,1382,root,20,0,255m,9144,3744,S,0.0,0.8,0:00.03,httpd,1391,daemon,20,0,591m,9132,1336,S,0.0,0.8,0:00.00,httpd,1392,daemon,20,0,591m,9132,1336,S,0.0,0.8,0:00.00,httpd,1390,daemon,20,0,591m,9128,1332,S,0.0,0.8,0:00.00,httpd,1517,postfix,20,0,81332,4168,3032,S,0.0,0.3,0:00.00,local,1515,postfix,20,0,81176,3604,2684,S,0.0,0.3,0:00.00,cleanup,1376,postfix,20,0,81100,3580,2656,S,0.0,0.3,0:00.00,qmgr,1375,postfix,20,0,81032,3484,2580,S,0.0,0.3,0:00.00,pickup,1369,root,20,0,80952,3468,2556,S,0.0,0.3,0:00.01,master
201906051325,0.00,0.01,0.00,1274,mysql,20,0,368m,27m,5048,S,0.0,2.3,0:00.15,mysqld,1382,root,20,0,255m,9144,3744,S,0.0,0.8,0:00.04,httpd,1391,daemon,20,0,591m,9132,1336,S,0.0,0.8,0:00.00,httpd,1392,daemon,20,0,591m,9132,1336,S,0.0,0.8,0:00.00,httpd,1390,daemon,20,0,591m,9128,1332,S,0.0,0.8,0:00.00,httpd,1735,root,20,0,102m,4576,3540,S,4.0,0.4,0:00.02,sshd,1517,postfix,20,0,81332,4168,3032,S,0.0,0.3,0:00.00,local,1515,postfix,20,0,81176,3604,2684,S,0.0,0.3,0:00.00,cleanup,1376,postfix,20,0,81100,3580,2656,S,0.0,0.3,0:00.00,qmgr,1375,postfix,20,0,81032,3484,2580,S,0.0,0.3,0:00.00,pickup
201906051326,0.00,0.00,0.00,1274,mysql,20,0,368m,27m,5048,S,0.0,2.3,0:00.17,mysqld,1382,root,20,0,255m,9144,3744,S,0.0,0.8,0:00.04,httpd,1391,daemon,20,0,591m,9132,1336,S,0.0,0.8,0:00.00,httpd,1392,daemon,20,0,591m,9132,1336,S,0.0,0.8,0:00.00,httpd,1390,daemon,20,0,591m,9128,1332,S,0.0,0.8,0:00.00,httpd,1735,root,20,0,102m,4580,3544,S,0.0,0.4,0:00.06,sshd,1517,postfix,20,0,81332,4168,3032,S,0.0,0.3,0:00.00,local,1515,postfix,20,0,81176,3604,2684,S,0.0,0.3,0:00.00,cleanup,1376,postfix,20,0,81100,3580,2656,S,0.0,0.3,0:00.00,qmgr,1375,postfix,20,0,81032,3484,2580,S,0.0,0.3,0:00.00,pickup
```

- vmstatコマンド

```console
[root@localhost WebAP03]# cat cpu.csv
201906051322,0,0,2,5,91,1,0
201906051323,0,0,1,3,95,1,0
201906051324,0,0,1,3,96,1,0
201906051325,0,0,1,2,97,0,0
201906051326,0,0,1,2,97,0,0
```

- netstatコマンド

```console
[root@localhost WebAP03]# cat session.csv
201906051322,0,1,0
201906051323,0,1,0
201906051324,0,1,0
201906051325,0,1,0
201906051326,0,1,0
```

###Chart.jsでCSVをグラフ化

csvデータをChart.jsで表示する方法はとてもカンタンです。
上記のように蓄積されたcsvデータを配列に変換し、そのデータをChart.jsに渡すだけ。

①csv=>配列にする関数を用意

```javascript:csv=>Array
function csv2Array(str) {
    let csvData = [];
    let lines = str.split("\n");
    for (let i = 0; i < lines.length; ++i) {
        let cells = lines[i].split(",");
        csvData.push(cells);
    }
    return csvData;
}
```

②Chart.jsの描画用関数を用意(下記コードはcpuの円グラフ表示用)
html側ではcanvasを用意するだけです。

```html
<canvas id="chart1"></canvas>
```

```javascript:chart.js
let chart1;

function drawCpuPieChart(cpudata) {
    let setLabels = [], setData1 = [], setData2 = [], setData3 = [], setData4 = [], setData5 = [], setData6 = [], setData7 = [];
    
    for (let row in cpudata) {
        setLabels.push(cpudata[row][0]);
        setData1.push(cpudata[row][1]);
        setData2.push(cpudata[row][2]);
        setData3.push(cpudata[row][3]);
        setData4.push(cpudata[row][4]);
        setData5.push(cpudata[row][5]);
        setData6.push(cpudata[row][6]);
        setData7.push(cpudata[row][7]);
    };
    
    let dateLabels = setLabels.map(function(n) {
        return n.substr(-4, 2) + ':' + n.substr(-2);
    });

    let cpuPieChartData = cpudata.filter(function(x) {
        let setTime = document.getElementById('set-time').innerHTML; 
        return x[0].substr(-4) === setTime.replace(':', '');
    });

    let ctx1 = document.getElementById("chart1").getContext("2d");
    ctx1.canvas.height = 360;

    if (cpuPieChartData.length === 0) {
        ctx1.font = 'bold 20px sans-serif';
        ctx1.textAlign = 'center';
        ctx1.fillText('No Data', 170, 200);
    } else {
        if (chart1) { chart1.destroy(); }
        chart1 = new Chart(ctx1, {
            type: 'doughnut',
            data: {
                labels: ["cs","sy","id","wa","st"],
                datasets: [{
                    backgroundColor: [
                        "#FF6384",
                        "#FF9F40",
                        "#FFCD56",
                        "#4BC0C0",
                        "#36A2EB"
                    ],
                    data: [
                        cpuPieChartData[0][3], 
                        cpuPieChartData[0][4], 
                        cpuPieChartData[0][5], 
                        cpuPieChartData[0][6], 
                        cpuPieChartData[0][7]
                    ]
                }]
            },
            options: {
                events: [],
                responsive: true,
                maintainAspectRatio: false,
                title: {
                    display: true,
                    fontSize: 18, 
                    text: 'CPU使用率（サーバ単位）'
                },
                layout: {
                    padding: {
                        bottom: 50,
                    }
                }
            }
        });
    }
}
```

chart1 = new Chart~ の部分でChartオブジェクトをインスタンス化し、引数にデータやグラフのカタチ等を定義することで、様々なグラフを描画できるんです！

注意点として、グラフのデータ更新時（日時変更や時間帯変更時など）if (chart1) { chart1.destroy(); }の部分で既存のオブジェクトがあった場合に明示的に破棄しているところです。

この対応を入れておかないとメモリリークを起こしてしまいます。
~~（メモリリークが原因でこれを作ったのにこれでメモリリークが起きたら本末転倒。。）~~

このほかにも、データだけを更新する方法もあるみたいです。
このほうがいいと思われます。

[chart.jsのデータ更新でメモリリークが発生する問題と解決方法](https://qiita.com/masato_makino/items/cfdb111fecee27fc8667)


③XHRでcsvデータをGETする

```javascript
function createCpuPieGraph() {
    const req = new XMLHttpRequest();
    const cpuGraphPieFilePath = './csv/'+ year + '/' + year + '_' + setMonth + '/' + setMonth + setDay + '/' + targetServer + '/cpu.csv';
    req.open("GET", cpuGraphPieFilePath, true);
    req.onload = function() {
        cpudata = csv2Array(req.responseText);
        drawCpuPieChart(cpudata);
    }
    req.send(null);
}

createCpuPieGraph();

```

あとはcsvファイルをGETし、①で作ったcsvを配列に変換する関数を通して、その結果を②のグラフ描画関数に渡すだけ！
※パス内の変数はセレクトボックスなどでサーバや日付を変更するためあります。

結果、以下のような円グラフが表示されます。

![Server Resources Monitor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174125/f65a1972-ea48-deb8-47cf-13fa18c4368a.png)

###リアルタイムボタン設置
リアルタイムとは名ばかりの、一分毎に最新情報に更新するボタンを設置しました。

実際に使っているシステムでは当日の現在時刻のグラフを表示してくれますが、デモサイトは2月20日～22日の3日分のcsvのみですので、そのcsv内のボタンを押した環境の時刻時点が表示されます

ソースコードは以下です。

```javascript
// Real time button

const rtbtn = document.getElementById('rtbtn');
const statusTxt = document.querySelector('.rtstatus_btn');

function realTimeJob() {
    let date = new Date(); 
    let hour = date.getHours();
    let minute = date.getMinutes();

    if(hour.toString().length == 1) hour = '0' + hour;
    if(minute.toString().length == 1) minute = '0' + minute;
    
    eTime.value = hour + ':' + minute;

    createCpuPieGraph();
    createCpuGraph();
    createProcessGraph();
    createMemoryGraph();
    createSessionGraph();

    timeMater.value = (hour*60) + minute-1;
    materSet.innerHTML = hour + ':' + minute;
    chart1TimeSet.innerHTML = hour + ':' + minute;
    processTimeSet.innerHTML = hour + ':' + minute;
}

let timer;

function timerStart() {
    timer = setInterval(realTimeJob, 60000);
}

function timerEnd() {
    clearInterval(timer);
}

rtbtn.addEventListener('click', function(){
    rtbtn.classList.toggle('on');

    if (rtbtn.classList.contains('on')) {
        statusTxt.textContent = 'ON';
        timerStart();
    } else {
        statusTxt.textContent = 'OFF';
        timerEnd();
    }
});

```

#7.まとめ

今回、Chart.jsを初めて使ってみましたがとても分かりやすく見やすいグラフをさくっと作ることができました。

今回は単純なリソース情報をcsvから表示しただけですが、もっといろんなグラフ形式があるしアニメーションもたくさんあるので、データを可視化したいときは積極的に使っていきたいと思います。