Google Spread Sheet + Slackで簡単にサーバ監視する (http)

# 残念なお知らせ
下記で毎分間隔でサーバを監視していましたが、Googleから下記のような警告と共に実行されなくなってしまいました。
***サービスで 1 日に使用しているコンピュータ時間が長すぎます***


<img width="590" alt="Screen Shot 2016-06-03 at 1.58.29 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/47327/3e2420e1-6189-b734-04a3-2b4afdd977e1.png">

さすがに無料でこれだけ使おうとすると怒られてしまうようです。
間隔を延ばしたりサイト数を減らすことで軽減はされるかと思います。

# はじめに
サーバ監視大変ですね。
最近だとSlackで通知させるのが流行ってるそうですね。
Zabbixなどで監視していたのですが、小さいチームだと運用コストが掛かってしまうのでもっと簡単にできないか、ということでトライしてみました。

![Screen Shot 2016-03-04 at 3.32.54 PM.png](https://qiita-image-store.s3.amazonaws.com/0/47327/9c1703ec-f38d-0a32-dec9-f57d2dbe76cb.png)
![Screen Shot 2016-03-04 at 3.33.13 PM.png](https://qiita-image-store.s3.amazonaws.com/0/47327/9e18ee45-ad26-33f0-07b4-ab9cb2e3c242.png)

「Google Spread Sheet + Slackでサーバ監視できる！」みたいな記事はいくつか見つけていてワクワクしていたのですが、うまく行かなかったので組み合わせて完結させました。

# Google Spread SheetとGoogle Apps Script (GAS)
当初はHerokuでhubotを動かしてみたのですが色々と大変でした。
もうちょっと簡単にできないかなーと思って探したところ、Google Spread SheetとGoogle Apps Scriptを組み合わせて無料でそこそこアッサリ動きました。
スプレッドシートでの管理ですのでホスト、ページの追加なども簡単に行えます。
特にチームのマネージャさんにも簡単に扱ってもらえそうなのが良いなと思っています。
今まではPHPやZabbixで監視していたのですがマネージャさんには敷居が高く、エンジニアが設定、改修していました。
Google Spread Sheetであれば初回にエンジニアが設定すればいいので凄く便利です。


# 作業
手順のまとめです。

1. スプレッドシートを作る
2. SlackのTokenを取得してスプレッドシート内に記載
3. スクリプト(GAS)の設定
4. トリガの設定

## スプレッドシートを作る
Googleスプレッドシートを作成します。
GASから操作するためにシートに「targets」と名前を付けておきます。

A列にURL、B列に正常なレスポンスコード、C列にSlackに通知するチャンネル名を記載します。

![Screen Shot 2016-02-16 at 7.32.40 PM.png](https://qiita-image-store.s3.amazonaws.com/0/47327/cd2897c9-35e6-e303-b5b8-272e0a548d3b.png)
それぞれ1行目はラベルとしてあります。
2行目以降をスクリプトに読ませるようにしました。

F列1行目にはSlackのTokenを入れる箇所にしました。

## SlackのTokenを取得

Slackから投稿したいチームのTokenを取得します。
https://api.slack.com/docs/oauth-test-tokens

xoxoで始まる文字列です。

![Screen_Shot_2016-02-29_at_2_33_42_PM.png](https://qiita-image-store.s3.amazonaws.com/0/47327/79ffc729-5807-c262-24f4-b2d890742831.png)

これを先ほどのF列1行目に入れておきます。

## スクリプトの作成
「ツール > スクリプトエディタ」を選択してスクリプトエディタを起動します。

メニューから「リソース > ライブラリ」選択し、Library Keyに「M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO」を入力して「選択」します。
「バージョン」は現段階で最新版の「22」を選択します。

![Screen Shot 2016-03-04 at 3.14.02 PM.png](https://qiita-image-store.s3.amazonaws.com/0/47327/a5dd58c0-bb16-fe1e-3ad4-d4cb2db82b21.png)


コードの本文には以下のコードを書きます。

```js
function checkSites() {
  var sheet = SpreadsheetApp.getActive().getSheetByName('targets');
  for ( var i = 2; i < sheet.getLastRow() + 1; i++ ) {
    var url = sheet.getRange(i, 1).getValue();
    var codeShouldBe = sheet.getRange(i, 2).getValue();
    var channel = sheet.getRange(i, 3).getValue();
    if ( url != '' ) {
      var statusCode = checkStatusCode(url);
      if ( codeShouldBe != statusCode ) {
        postSlackMessage(channel, url, statusCode, codeShouldBe);
      }
    }
  }
}

function checkStatusCode (url) {
  try {
    var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
    Logger.log(url + ': ' + response.getResponseCode());
    return response.getResponseCode();
  } catch (error) {
    if ( response !== undefined) {
      Logger.log(url + ': ' + response.getResponseCode());
      return response.getResponseCode();
    } else {
      Logger.log(url + ': ' + 'Webserver down')
      return 0;
    }
  }
}

// thanks! http://tech.camph.net/slack-bot-with-gas/
function postSlackMessage(channel, url, statusCode, codeShouldBe) {
  var token = SpreadsheetApp.getActive().getSheetByName('targets').getRange('F1').getValue();
  //Browser.msgBox(token);
  
  var slackApp = SlackApp.create(token); //SlackApp インスタンスの取得
  var message = 'Hey! ' + url + ' returns ' + statusCode + '. (Expected code is ' + codeShouldBe + ')';
  message += 'This message thrown by ' + (SpreadsheetApp.getActiveSpreadsheet()).getUrl();
  
  var options = {
    channelId: channel, //チャンネル名
    userName: "WatchDog", //投稿するbotの名前
    message: message //投稿するメッセージ
  };
 
  slackApp.postMessage(options.channelId, options.message, {username: options.userName});
}
```

スプレッドシートへのアクセスなどの認証が必要なので、手動で実行しておきます。
メニューの「実行」から「checkSites」を選びます。

![Screen Shot 2016-03-04 at 3.20.41 PM.png](https://qiita-image-store.s3.amazonaws.com/0/47327/39470504-06bf-46c0-516f-8f36bc40aa07.png)


以下のようなアラートが出たら承認しておきます。

![Screen Shot 2016-03-04 at 3.17.32 PM.png](https://qiita-image-store.s3.amazonaws.com/0/47327/fc0d815b-f507-c510-22e5-03ddcc8bff3c.png)

スプレッドシート側のステータスコードを500などに書き換えて、アラートが飛ぶか確かめます。

![Screen Shot 2016-03-04 at 3.19.31 PM.png](https://qiita-image-store.s3.amazonaws.com/0/47327/d5acf166-2130-cf0d-11ce-c847b03386af.png)

うまくいけばこんな感じでアラートが飛んできます。

## トリガの設定
監視用に毎分の設定をしておきます。
「リソース > 全てのトリガー」を選択し、「新しいトリガーを追加」します。
実行は「checkSites」、「時間主導型」で「分タイマー」「一分ごと」にしておきます。

以上で一分おきに対象サイトをチェックしてくれます。

# 補足
## うまく動かない時
うまく動かない時にはスクリプトエディタ側の「表示 > ログ」を見るとエラーが出ていたりします。

![Screen Shot 2016-03-04 at 3.22.43 PM.png](https://qiita-image-store.s3.amazonaws.com/0/47327/5c6c20a6-1bc7-a872-cf37-b3d5e15b40d8.png)

コードの特定の箇所に

```js
Logger.log('hoge');
```
のように書くとデバッグに便利です。

## 開発時のテストツールとして
僕はサイトの開発、運用初期段階から携わることが多いので、その際にはスプレッドシートにページ一覧を列挙しておき、簡易的なページチェックツールとしても使っています。
特にインフラエンジニアとしては細かいリダイレクトの設定の際に簡易的なテストツールとしても使えますので便利です。
(とはいえ、3xxのリダイレクトには今のところ反応せず、リダイレクト先の200などを取ってしまっています)

# 注意
エンジニア向けには言うまでもありませんが、このスクリプトではサイトへのアクセスを行うため、倫理的に許される範囲での運用にしましょう。
人のサイトへチェックなどはやめましょう。
あまりやりすぎるとたぶんGoogleに怒られる気がします。

# 参考サイト

> Slack BotをGASでいい感じで書くためのライブラリを作った
> http://qiita.com/soundTricker/items/43267609a870fc9c7453#botとして動かしてみる

> 初心者がGASでSlack Botをつくってみた
> http://tech.camph.net/slack-bot-with-gas/

ほぼ上述のサイトのおかげで出来ました。