2019年7月21日日曜日

おれおれ APM で Domino の統計情報をグラフ化

以前のエントリでも紹介しましたが、V10 では統計情報を New Relic というSaaSの監視サービスと連携する新機能があります。

実は、New Relic だけでなく、他の監視サービスとも連携できそうだということはオンラインヘルプにも書かれていたのでなんとなく知識としてはありましたが、これまで試したことはありませんでした。

ところで "New Relic" をグーグル先生に聞くと「APM」という単語が頻繁にヒットします。
この APM とは「アプリケーション性能管理」を指す一般的な用語らしいのですが、世の中には APM を謳うサービスが New Relic 以外にも多く存在することを最近知りました。

参考までに、グーグル先生が教えてくれた APM 関連製品/サービスを羅列してみます。
Datadog, Nagios, Stackify, Sensu, Pingdom, LogicMonitor, Splunk, Grafana, Scout, SteelCentral, Applications Manager, AppDynamics, dynaTrace, CA APM, JENNIFER, Hosted Graphite
※これらが Domino と連携できるかどうかは未確認です

この中のいくつかを試してみたくなったのですが、New Relic のようにグラフ化されない統計情報があるのだろうし、その場合にどうすればグラフ化できるのかを調べる手間よりも、自前でグラフ化できるのならそっちの手間のほうが楽しそうだと考えました。


さしずめ「おれおれAPM」です。


まずは、New Relic 等への統計の連携機能が REST API を使って POST していることを確認するため、POST 先として Domino の nsf ファイルを試してみることにしました。

まずは、POST を受けるために HTTP タスクを起動します。

サーバーコンソールから次のコマンドを投入しました。
load http


ドミノディレクトリのサーバー文書で、Domino Access Service (DAS) を有効にします。
また、統計情報を保存する NSF ファイル「statpub.nsf」とビューにおいても DAS を有効にしておきます。

※DASを有効にするための設定については「IBM Domino REST API 利用ガイド」が詳しいです


私の環境では、現在の統計の連携先が New Relic なので、それをやめるために notes.ini から NEWRELIC_LICENSE_KEY= で始まる行を削除しています。

そして Domino の NSF ファイルへ統計情報を POST するよう、notes.ini へ次のように設定しました。
STATPUB_ENABLE=1
STATPUB_URI=http://localhost/statpub.nsf/api/data/documents
STATPUB_DATA_HEAD={"host":"xsp13/v10","stattime":$Timestamp$000,
STATPUB_DATA_TAIL=}
STATPUB_METRIC_FORMAT="metric.$Name$":$Value$
STATPUB_DELTA_METRIC_FORMAT="metric.delta.$Name$":$Value$
STATPUB_HEADERS=Content-Type: application/json$Newline$Accept: application/json$Newline$StatTimeStamp: $Timestamp$Newline$

New Relic 以外へ連携する場合は STATPUB_ で始まるパラメータを必要に応じていくつか指定します。

1行目の STATPUB_ENABLE= は統計の公開を有効にする場合は 1 を指定します。無効は 0 です。

2行目の URI は、REST API を使用して NSF に文書を作成する場合に指定するものと同じです。

3,4行目は、統計情報を JSON 形式とするために最初と最後に{}を付加したり、後から使うであろうサーバー名などを追加しています。stattime にはタイムスタンプとしてUNIXエポックの日時を付加できるのですが、ミリ秒の部分が欠落しており、後述の Chart.js で使う場合に都合が悪いので、3桁のゼロを追加しています。

5,6行目は統計情報のフォーマットを定義します。統計情報にある Update.DefferdList といった名前の前後にダブルコーテーションを加え、名前と値の区切り文字としてコロンを指定しています。なお、6行目の delta で始まる統計情報には、前回の値との差を示す値がセットされるようです。

7行目には POST する際にヘッダとして指定するべき Content-Type といったパラメータなどを定義しています。複数のパラメータを改行で区切るために $Newline$ を挟んでいます。
また、このままでは NSFファイル内に作成される文書の作成者は Anonymous となりますが、もし、作成者を特定のアカウントにしたい場合は「Authorization: Basic <アカウント:パスワード>」を追加すると Basic 認証できます(<>には BASE64でエンコードした文字列を設定します)。


さて、これを設定して数分待っていると statpub.nsf に文書が登録されていました。


こうしてこの連携機能が REST API を使って POST していることが確認できました。


ところで、APM はリアルタイムにグラフ化できることがメリットのひとつだと思うのですが、NSFファイルにあるデータをリアルタイムにグラフ化するには、NSFにデータが作成された瞬間に値をグラフへ反映する仕組みが必要です。また、そもそもグラフをどうやって表現するかということにも関係します。

実は現在参加しているノーツコンソーシアムの「アプリ開発研究会」で、リアルタイムにグラフ化するほうのネタを提供してしまったため、このエントリでは「リアルタイム」をちょっと犠牲にして実現する方法をご紹介します。

POST 先のデータベース「statpub.nsf」に、次のようなビューを追加しています。
1列目)列の値:statpub、最新のデータを最も上に表示するため降順でソートします
2列目)列の値:metric.Update.DeferredList
3列目)列の値:metric.Update2.DeferredList

グラフには2つの統計値を表示したいので、2列目と3列目で値を表示しています。
今回は「Updateタスクのキューに入っている要求の数」を見ることを想定して 「metric.Update.DefferdList」を指定しました。なお、私の環境は2つのUpdateタスクを起動しているので Update2 の統計情報が存在します


さらにページ「index」を追加しています。データベースをWebブラウザで開く際にこのページが開くようデータベースのプロパティを変更しています。

ページには次のコードを記述してあり、このコード全体をパススルーHTMLとしています。
</form>
<canvas id="myChart"></canvas>
<script type="text/javascript">
    var ctx = document.getElementById('myChart').getContext('2d');
    var chart = new Chart(ctx, {
        type: 'line',
        data: {
            datasets: [{
                data: [],
                label: 'Update.DeferredList'
            },{
                data: [],
                label: 'Update2.DeferredList'
            }]
        },
        options: {
            elements: {
                line: {
                    tension: 0
                }
            },
            scales: {
                xAxes: [{
                    type: 'realtime'
                }]
            },
            plugins: {
                streaming: {
                    duration: 600000, //保持する時間幅=画面の横幅(ミリ秒)
                    refresh: 15000, //次にデータを読み込むまでのインターバル(ミリ秒)
                    delay: 0, //最新のデータを表示する間隔(tension 0 の場合、関係なし)
                    frameRate: 30, //数字を大きくするとスクロールがスムーズになる
                    pause: false,

                    onRefresh: function(chart) {
                        var json = '';
                        var xhr = new XMLHttpRequest();
                        xhr.onreadystatechange = function() {
                            if (xhr.readyState === 4) {
                                if (xhr.status === 200) {
                                    json = JSON.parse(xhr.responseText);
                                    chart.data.datasets[0].data.push({
                                        x: json[0]["stattime"],
                                        y: json[0]["metric.Update.DeferredList"]
                                    });
                                    chart.data.datasets[1].data.push({
                                        x: json[0]["stattime"],
                                        y: json[0]["metric.Update2.DeferredList"]
                                    });
                                } else {
                                }
                            }
                        }
                        xhr.open( 'GET', 'http://localhost/statpub.nsf/api/data/collections/name/Update.DeferredList?count=1&systemcolumns=0x80a');
                        xhr.send(null);
                    }
                }
            }
        }
    })
</script>
<form>

また、このページの HTML Head Content には以下のように指定しています。
"<meta charset=\"UTF-8\">
<title>リアルタイム統計情報</title>
<script src=\"https://cdn.jsdelivr.net/npm/moment@2.24.0/min/moment.min.js\"></script>
<script src=\"https://cdn.jsdelivr.net/npm/chart.js@2.8.0\"></script>
<script src=\"https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@1.8.0\"></script>
<style>* { margin: 0px; padding: 0px; }</style>"


このページに書いたコードを簡単に説明します。

統計情報の折れ線グラフを時系列に表示したかったので、今回は Chart.js に chartjs-plugin-streaming プラグインを組み合わせています。グラフは canvas タグの場所に最新の10分間(単位をミリ秒で指定するためコード上は600000)だけ表示する設定です。

ここでは、15秒間隔(単位をミリ秒で指定するためコード上は15000)でリフレッシュしていますが、そのタイミングで XMLHTTPRequest を使ってビューの1行目(最新の統計値)だけを取得します。取得できた JSON データをパースして、日時値と表示したい統計情報の値をグラフに反映します。

グラフを表示するにはブラウザから http://localhost/statpub.nsf へアクセスします。

こうして表示されたグラフがこちらです。※実際はもたもたと右から左へ動きます。


ひとまず「おれおれAPM」ができました。

0 件のコメント:

コメントを投稿