2014-05-08

elasticsearch+kibanaでSFDCのアクセスログ取ってみる。

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で見るとこんな感じにグラフ化される。

kibana-sf

 

入力データはこんな感じ。

kibana-sfrec

 

んー、ドメインをデータとして入れちゃうと上位に入っちゃうから 、パスだけにした方が良いかも。

仕組み上レポート、ダッシュボードみたいにサイドバーが出てこない系コンテンツは

ログが取れないのは難点っすね…。意味のあるデータを集めたい場合はもうちょい工夫が必要そう。

アクセスログレベルの解析だったら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対応しないと動かないです。

このエントリーをはてなブックマークに追加