fluentd+elasticsearch+kibanaの構成でログ解析をすることが流行っているらしい!
ということで、今回はSFDCの画面からアクセスログを取ってelasticsearch+kibanaで
ビジュアライゼーション&解析するっていうことをやってみました。
(個人的に一般ユーザのアクセスログだけじゃなく、管理する側のアクセスログとか取って解析して
何か面白いもの見れないかなーなんて思ってます。)
流れとしては
SFDCからelasticsearchにデータを登録する
→elasticsearchのデータをkibanaで見る
って感じ。
elasticsearchとkibanaのインストール・セットアップ方法に関しては以下を参照ください!
fluentd + Elasticsearch + Kibanaで始めるログ解析 (セットアップ編)
0. SFDCからデータ登録をする際の方針
SFDCのお知らせ等のサイドバーコンポーネントにデータ登録用のスクリプトか何かを埋め込むという方式で行いますが、方法としては
a. お知らせにJavaScriptを埋め込んでajaxでelasticsearchにデータを飛ばす
b. お知らせに埋め込んだJavaScriptでVFを呼び出すscriptタグあるいはiframeタグを動的に生成して、
そのVFページ(Apex)からelasticsearchに対してコールアウトする。
の2パターンがありそうですが、aはCORSの対応が必要が面倒そう(っていうかハマった…orz)なので
今回はbのApexからコールアウトする方式で!
1. Visualforceページ + Apexクラスの作成
こんな感じで#LoggerES.cls
public with sharing class LoggerES {
public LoggerES() {
Map<String, String> params = ApexPages.currentPage().getParameters();
String jsonBody = JSON.serialize(new Map<String, String>{
'user' => UserInfo.getUserId(),
'url' => params.get('url'),
'ref' => params.get('ref')
});
HttpRequest req = new HttpRequest();
req.setHeader('Content-Type', 'application/json; charset=UTF-8');
req.setHeader('Content-Length', String.valueOf(jsonBody.length()));
req.setEndpoint('http://{domain}:9200/sfdc/access_log');
req.setMethod('POST');
req.setBody(jsonBody);
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
}
}
#LoggerScript.page
<apex:page showHeader="false" contentType="text/javascript" controller="LoggerES">
</apex:page>
リモートサイトの設定で対象ドメイン、ポートに対するコールアウトを許可するのも忘れずに。
あと、今回は非SSLのhttpで認証なしにやってますが、実環境でやる場合はhttps+basic認証とかで
セキュアにelasticsearchにアクセスできる仕組みを作ってやってください。
サーバサイドのポート9200に対するIPフィルタリングも有効だと思います。
CSRFは特に対策しなくも良いかと思います(ログ作られるだけだし)
2. お知らせにスクリプト埋め込み
以下のようなスクリプトを埋め込む。これによって動的にLoggerScriptページをパラメータ付きで呼び出して、elasticsearchにデータ登録を行う。
<script type="text/javascript">
(function(){
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = '/apex/LoggerScript?url=' + location.href + '&ref=' + document.referrer;
if( head != null){
head.appendChild(script);
}
})();
</script>
注意点としてはお知らせのスクリプト内に空行を入れると
タグが自動的に付与されるっぽいので
空行は作らない方が良いです。
あと、カスタムコンポーネントのhtmlエリアでも同様のことはできるけど
プレビュー機能でscriptが動いて編集がし辛かったりするので
標準画面にJS埋め込みとかやりたい場合はお知らせがオススメ。
あとは、このお知らせコンポーネントをホームページのページレイアウトに追加するだけ!
ユーザインターフェースで”すべてのページにカスタムサイドバーコンポーネントを表示”にチェックをつけるのもお忘れなく。
で、適当にSFDCの標準画面を彷徨って、ログの収集結果をkibanaで見るとこんな感じにグラフ化される。
入力データはこんな感じ。
んー、ドメインをデータとして入れちゃうと上位に入っちゃうから 、パスだけにした方が良いかも。
仕組み上レポート、ダッシュボードみたいにサイドバーが出てこない系コンテンツは
ログが取れないのは難点っすね…。意味のあるデータを集めたい場合はもうちょい工夫が必要そう。
アクセスログレベルの解析だったらGA使えって話だしw
※aパターンで実装した場合
ちなみに、aパターンで書くとVFページだけで書けちゃいます。(お知らせscriptだけでもイケそうですが、ユーザコンテキストとかをAPIコール無しに取得するにはVFが必要)
<apex:page showHeader="false" contentType="text/javascript">
(function($) {
var url = "https://{domain}:9200/sfdc/access_log"
$.ajax({
url : url,
data : JSON.stringify({
"user" : "{!$User.FirstName} {!$User.LastName}",
"path" : location.href,
"org" : "{!$Organization.Id}"
}),
type : "POST",
contentType : "application/json"
}).done(function(){
}).fail(function(){
});
})(jQuery);
</apex:page>
ただし、CORS対応しないと動かないです。