[Monitoring] MonitisのTransaction監視(custom location)が結構面白い with Docker

# What is Monitis?
- SaaSの監視サービスです。競合はUptrendsとか、Pingdomとか、かな？？  
http://www.monitis.com/

どちらかというと多分後者の競合さん達よりマイナーなサービスだと思います(Monitisさんごめんさい :bow:)

# What is Transaction Monitoring?
<img width="1145" alt="スクリーンショット 2016-08-05 2.17.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/19942/6507fa9e-ecc2-2a73-ef0c-0f84969f2493.png">


いわゆるEnd-2-Endのサービス監視のことです。MonitisのTransaction Monitoringの紹介ページはここらへん。
https://www.monitis.com/support/end-user-monitoring/transaction-monitoring
Monitisは現状Firefoxにのみ対応した専用のPluginをインストールすることで、画像のようにSelenium的にブラウザの動作を記録してscriptを作ったり、IDE的にここで0から作ることもできます。
ここで作ったscriptは自動的にMonitisのダッシュボードに送られ、それを使って監視アイテムを作ることが可能。

簡単な例) qiita.com/login を開く -> ログインする -> 特定のElementsの存在可否を調べる

のような実際のユーザのブラウザ上での挙動をエミュレートして、各機能が最終的な描画レベルできちんと動作しているか、また各動作(Step)にかかった処理時間はどのくらいか？ などを記録、監視します。

**※大事な事なので先に言いますが**、いわゆる開発段階におけるブラウザを使った単体/結合テスト（Seleniumとか）とやること自体は変わりません。が、今回の目的は本番環境に対して継続的にそうしたTransaction監視を行い、意図しない動作があった場合には簡単にアラートを上げる事ができるSaaSを使ってみよう！という点にありますのでご承知おきください。

ぶっちゃけここらへんの監視に対する世の中の関心ってあまり高くはないですよね。
先程も言いましたが、今風の会社ならどこも当たり前に開発のテスト段階でブラウザを使った何かしらのテストが動いているので、わざわざ監視する必要あるの？みたいな。えぇ、ちゃんとやってれば必要ないことがほとんどだと思います…。

# SaaSを使うことの利点
これはサービスによっても様々変わってきますが、例えばMonitisやUptrendsのようなSaaSの監視サービスの場合、
location/checkpoint（監視サーバ） が世界中にあります。
これにより、国内からだけでなく、アジアやヨーロッパ、アメリカなど他大陸のクライアントから自身のサービスにアクセスした際のレスポンスや挙動を継続的に監視することができます。
また、ダッシュボードが比較的充実しているので、可視化やアラートのSlack連携などは設定1つですぐに行うことができます。

# Transaction監視(custom location) のcustom locationってつまり何？
ようやく本題に入ってきました。今回私がMonitisを気に入ったのは、このcustom locationの機能がサポートされていたからです。
これはつまり、先ほどSaaSを使うメリットで紹介した監視サーバ（location/checkpoint）を自分で用意することができる！という機能です。

何が嬉しいかというと、自分で用意したサーバをSaaSのダッシュボード上から1つのlocationとして登録することができるので、インターネットには公開されていないイントラのWebサービス（内部NW）に対して監視を行うことができる！！！という点です。

<img width="798" alt="スクリーンショット 2016-08-05 2.29.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/19942/fa7fbd39-b82b-432a-963e-b4c1a1c849d1.png">

この画像のLocationは自分で作ったサーバにMonitisが提供しているAgentをインストールすることで追加することができるようになります。AgentはLinux/Windowsに対応しています。

**このサーバは内部NWへアクセスすることができるので、イントラのWebサービスに対してAgentがTransaction Monitoringを行うことができます。**
**サーバにインストールしたAgentは自ら定期的にMonitisのAPIに向けてpushで通信をしており、その際に新たな監視アイテムが登録されていれば定義をダウンロード、実行間隔ごとにローカルのFirefoxとAgentが内包しているSeleniumを使って監視を行い、結果をMonitisへ送信、もしシナリオが失敗した場合は失敗時のスクリーンショットも送信してくれます。
そのため、サーバは特にポートを開けたりする必要はありません！セキュアです！**

例) Dropboxのログインシナリオでメアド入力先のElementsが見つからなかった場合のエラー時スクリーンショットがAgentからダッシュボードに送られてきている様子
<img width="1303" alt="スクリーンショット 2016-08-04 19.20.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/19942/19c0e236-4e26-b52a-80e4-33f3f99880c6.png">

# これを応用すれば、箱物アプライアンスの管理コンソールとかもいける？？
そうです。
例えば箱物アプライアンスがあったとして、ブラウザから設定などが行える管理コンソール機能をアプライアンスが持っているとします。管理コンソールにはダッシュボードがあり、APIを通じてクラウド上のバックエンドシステムと繋がっていたりする。
しかし当然管理コンソールには社内NWからしかアクセスできないので、一般的なSaaSからは到達性が無く監視することはできません。

が、前述したようなMonitisのcustom locationを使えば、それが実現できたりします。

# ではcustom locationを作ってみましょう。
## 注意事項
Monitis公式のインストールガイドは下記です。今回はLinuxを使います。

- Linux  
http://www.monitis.com/support/server-device-monitoring/install-linux-agent
- windows  
http://www.monitis.com/support/server-device-monitoring/install-windows-agent

## requirements
今回私はめんどくさかったのでMac上のDockerを使って公式のUbuntu 14.04イメージを使って環境を作りました。
素のUbuntuコンテナに最低限インストールしないといけないのは、下記のパッケージです。

```
Oracle java8
xvfb
fonts-takao-pgothic
firefox (Version 46.0.1)
```

まずSeleniumがjavaを必要とするのでjava7以上、GUIは使いたくないのでxvfbを使ってfirefoxを仮想エミュレートさせます。
デフォルトでは日本語が豆腐文字になるので、fonts-takao-pgothicをインストールしておくとよいと思います。
**※サーバはインターネットへのアクセスがあることが前提です**

### Firefox 47以上だとSelenium動かない問題
はい、前述のパッケージを見て何でFirefoxはlatestバージョン使わないの？と思われた方、すみません。
これはMonitis側も把握している問題ですが、おそらくFirefox 47からの仕様変更で、MarionetteDriverを使わないといけなくなったことに起因しているのだと思います。おそらくじきに対応してくれると思いますが、現状はSupportも46.0.1を使ってくれと言ってきました。

参考：http://stackoverflow.com/questions/37693106/selenium-2-53-not-working-on-firefox-47

## インストール
もし同じようにDockerで試したいという方がいれば、下記を参考にするとよいと思います。
https://github.com/dockerfile/java/blob/master/oracle-java8/Dockerfile

↑に加えて、Firefoxのダウンロードとパス通し、

```
# cd /tmp && wget http://ftp.mozilla.org/pub/mozilla.org/firefox/releases/46.0.1/linux-x86_64/en-US/firefox-46.0.1.tar.bz2 && tar xvf firefox-46.0.1.tar.bz2 -C /usr/local && rm -f /tmp/firefox-46.0.1.tar.bz2
# ln -s /usr/local/firefox/firefox /usr/bin/firefox
# firefox -v
Mozilla Firefox 46.0.1
```

xvfbをインストールしたら、バックグラウンドで起動

```
# export DISPLAY=:1
# nohup Xvfb :1 &
```

Monitis Agentをダウンロード/インストールします。

```
# cd /tmp && wget https://dashboard.monitis.com/downloader/smart-agent-linux-64bit.tar.gz && tar xvf smart-agent-linux-64bit.tar.gz -C /usr/local && rm -f /tmp/smart-agent-linux-64bit.tar.gz
# cd /usr/local/smartagent
# ./smagent.sh conf
```

ここから先は対話式のインストールが始まるので、先ほどの公式インストールガイドに従って自身のMonitisアカウント情報などを入力していってください。
http://www.monitis.com/support/server-device-monitoring/install-linux-agent

インストールが無事終わったらエージェントを起動します。

```
# cd /usr/local/smartagent
# ./smagent.sh start
```

起動した後にMonitisのダッシュボードを確認してみてください。Transaction Monitoring追加のStepを進め、下記画像のように作ったcustom locationをセットアップします。

<img width="842" alt="スクリーンショット 2016-08-05 3.26.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/19942/7ac27761-49b8-2334-b4c6-b5a374114225.png">

Testボタンを押すとAgentの次のポーリングのタイミングでブラウザの起動テストが走り、無事起動できればsuccessとなり、custom locationの追加ができます。1,2分待ちましょう。
ここでsuccessしない場合は何かしらサーバ側の問題があります。

### 参考：公式トラブルシューティングガイド
https://www.monitis.com/support/troubleshooting/linux-agent

smagent.confに「LOGLEVEL 10」と書くと詳細なデバッグログが出るので、問い合わせ時や確認時に役立ちます。

## Dockerfileで公開できなくてゴメンね :cry: 
セットアップ簡単ならDockerfile公開しろよ！と言われそうですが、
Monitis Agentの初回インストール時に叩くシェルスクリプトがアクティベートのために対話式でアカウントのメールアドレスやらパスワード入力を求めてくるので、いったんそこはご自身で対応いただければと… :bow:

# 今日はここまで
以上で、ひとまずcustom locationを追加するところまでは完了しました。
あとはFirefoxのMonitisプラグインを使ってSeleniumの記法に従ったscriptを書き、それを今回追加したcustom locationから監視させるようにすればOKです。

# おまけ
custom locationで何かシナリオを動かしてみたい！という時はまずは手始めに下記が動くことを確認してみてください。
私のDocker環境では動作することを確認済みです。
※ログイン情報は各自の環境に合わせて書き換えてくださいね。

尚、このスクリプトを適当な名前で保存し、FirefoxのMonitisプラグインから読み込んで「Save As script on the Cloud」をすればMonitisのダッシュボードからscirptが見えるようになるので、それを使って監視アイテムを追加してみてください。

- qiitaにログインしてログアウトするだけのscript

```html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="selenium.base" href="https://qiita.com/login" />
<title>qiita</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">qiita</td></tr>
</thead><tbody>
<tr>
	<td>open</td>
	<td>https://qiita.com/login</td>
	<td></td>
	<td>false</td>
	<td>open</td>
</tr>
<tr>
	<td>type</td>
	<td>identity</td>
	<td>ここにメールアドレス</td>
	<td>false</td>
	<td>type</td>
</tr>
<tr>
	<td>type</td>
	<td>password</td>
	<td>ここにパスワード</td>
	<td>false</td>
	<td>type</td>
</tr>
<tr>
	<td>click</td>
	<td>commit</td>
	<td></td>
	<td>false</td>
	<td>click</td>
</tr>
<tr>
	<td>waitForElementPresent</td>
	<td>//img[@class='sharedHeader_user_image']</td>
	<td></td>
	<td>false</td>
	<td>waitForElementPresent</td>
</tr>
<tr>
	<td>click</td>
	<td>//a[@class='sharedHeader_user_clickable']</td>
	<td></td>
	<td>false</td>
	<td>click</td>
</tr>
<tr>
	<td>assertElementPresent</td>
	<td>//a[@href='/logout']</td>
	<td></td>
	<td>false</td>
	<td>assertElementPresent</td>
</tr>
<tr>
	<td>click</td>
	<td>//a[@href='/logout']</td>
	<td></td>
	<td>false</td>
	<td>click</td>
</tr>

</tbody></table>
</body>
</html>
```