Liferay DXP 7.0は、検索関連の機能としてElasticsearchと密接に連携しています。 たまたまですが、ElasticsearchはELKスタックの一部分です。 ですから、"ELKスタック全体を使うと何ができるのか?"という疑問を持つのは当然です。
答えは、「チャンスはたくさんある」です。 ここで紹介するオプションの一つは、DXP 7.0の「ダッシュボード」の構築です。様々なチャートやグラフを使って、複雑な情報をグラフィカルに表示します。 これらは、情報を素早く消費可能な形式にまとめることができるため、人気があります。
この記事では、ELKスタックを使ってダッシュボードのグラフを作成します(ELKスタックがインストールされていることが前提です)。
ここで紹介する内容は、開発とテストを行ったものです。
- Liferay DXP 7.0 FP22
- Elasticsearch 2.3.3
- Kibana 4.5.1
- Logstash 2.3.2
- Apache HTTPd 2.4
Liferay DXP
ダッシュボードの構築には、Liferay DXPに組み込まれたLiferay Auditの機能を活用する予定です。 そのため、Liferay Portal 7.0 CEでは機能が不足しているため、これらは動作しません。 Liferay Portal 7.0 CEの監査レイヤーを構築することは可能ですが、これは本文書の範囲外です。
Elasticsearch
前述の通り、DXP 7.0では検索関連の機能にElasticsearchを採用しています。 本番環境では、ESはアプリケーションコンテナの外に別途インストールされ、おそらく一般には公開されないバックエンドシステムにインストールされるでしょう。
Kibana
Kibanaは、Elasticsearchをベースにした視覚化ツールです。 Kibanaでは、ESに対して検索クエリを使用し、その結果に基づいてチャートやグラフなどの視覚化を行うことができます。 このドキュメントでは、いくつかの簡単なビジュアライゼーションを紹介しますが、Kibanaは複雑なクエリを使用して魅力的なビジュアライゼーションを構築することをサポートします。 しかし、複雑なクエリやビジュアライゼーションは、このドキュメントの範囲外です。
また、Kibanaはバックエンドにもインストールされている必要があり、ESサーバーまたは専用サーバーにインストールされている必要があります。 クライアントブラウザはKibanaサーバにリソースを要求する必要がありますが、これはプロキシを介して行うべきです。 このドキュメントでは、KibanaサーバーへのリクエストをプロキシするためにApache httpdを使用します。
ログスタッシュ
logstashという名前は、ログファイルのためのツールという印象を与え、誤解を招く恐れがあります。 実はlogstashは、非構造化データソースからデータを抽出して別の場所に送るのに適したETL(Extract, Transform, Load)ツールなのです。 ログファイルから情報を抽出してドキュメントとしてElasticsearchに読み込むためのツールとしてスタートしましたが、データベースやファイル、twitterのフィードなどからlogstashを動作させるために、さまざまなプラグインが開発されています。 フィルターと変換のメカニズムは、抽出されたデータをElasticSearchドキュメントとしてロードするのに適したドキュメントに変換するのに役立ちます。
ビート
logstashの関連ツールとして、beatsフレームワークがあります。 Logstashは、リソースを大量に消費するツールであり、すべての本番システムにインストールするには重すぎる可能性があります。 ファイルビーツツールをはじめとするbeatsフレームワークがその解決策となります。 beatsフレームワークは、データをネットワーク経由で中央のlogstashインスタンスに送信する前に、ローカルで読み取りとフィルタリングを行う軽量のエージェントを提供します。これにより、データが存在するシステムにbeatsエージェントをインストールしても、logstashの処理の大部分を別の(専用の)サーバーにオフロードすることができます。
このドキュメントではbeatsツールを使用していませんが、本番環境では、バックエンドにlogstashをインストールし(ESサーバーか、おそらく専用サーバー)、他のシステムでfilebeatsエージェントを使用してlogstashへのデータ送信を処理することが望ましいでしょう。
Apache HTTPd
このドキュメントでは、LiferayのTomcatインスタンスとバックエンドのKibanaサーバーへのリクエストをプロキシするためにApache HTTPdを使用しています。
解像度
ここで紹介する実装は、以下の要件を満たすように設計されています。
- ELKスタックを使用して、ログインアクティビティを表示するダッシュボードを作成します。
- 現在の1週間の1日あたりのログイン数。
- 現在の日の1時間あたりのログイン数。
- ELKスタックを使用して、1日あたりのフォーム送信数を表示するダッシュボードを作成します。
- ELKスタックを使用して、ページの人気度を表示するダッシュボードを作成します。
これらのダッシュボードの構築に必要なデータはアクティビティベースであるため、監査フレームワークを活用してデータ収集を処理します。 アーキテクチャ図は次のようになります。
監査フレームワークを使用すると、イベントの生成に使用されるロジックは、監査ファイルを維持するコードから分離されます。 また、監査フレームワークを活用することにより、監査メッセージを生成するためのすぐに使用できる例をDXPソースで直接利用できます。
実装の詳細
要件を満たすダッシュボードを構築するには、以下を生成する必要があります。
- ダッシュボードに必要なデータを提供するための適切な監査メッセージを生成するカスタム監査コード。 ログインダッシュボードは、OOTBユーザーモデルリスナー監査イベントジェネレーターを使用して満たすことができます。
- 監査メッセージを受信して監査ファイルに書き込むためのAuditMessageProcessor。
- 監査ファイルを処理し、ドキュメントをESにロードするためのlogstash構成ファイル。
- 各ダッシュボードのKibanaビジュアライゼーション。
- メッセージをLiferay / TomcatおよびKibanaサーバーにプロキシするためのApacheセットアップ。
監査コード
ダッシュボードの場合、次のアクションに対して監査情報をトリガーする必要があります。
- ユーザーログイン-幸い、これはcom.liferay.portal.security.audit.event.generators.events.LoginPostActionのOOTB監査イベント生成コードによってすでに処理されています。 ログインが発生すると、このログイン後ハンドラーが監査メッセージを生成し、これらの監査メッセージをダッシュボードグラフに使用できます。
- フォームの送信-フォームがLR7で送信されると、フォームフィールドがシリアル化され、DDMContentレコードとして保存されます。 したがって、フォームがいつ保存、更新、または削除されるかを識別するために、DDMContentModelListenerが必要になります。 テスト中に、フォームデータの逆シリアル化に必要な対応するDDMStorageLink要素の前にDDMContentsが保存されていることが判明したため、最初のフォーム送信を監査するためにDDMStorageLinksのModelListenerが追加されました。
- ページビューはさまざまな方法で監査できますが、この実装では、ServicePreActionを使用して、レンダリングされるページを識別します。 LayoutActionクラスから適合されたコードを使用して、レンダリングされるページが識別および監査されます。
添付のプロジェクトでは、関連するクラスは次のとおりです。
- com.liferay.portal.security.audit.event.generators.DDMContentModelListener
- com.liferay.portal.security.audit.event.generators.DDMStorageLinkModelListener
- com.liferay.portal.security.audit.event.generators.AuditServicePreAction
中にいくつかのユーティリティクラスもあります com.liferay.portal.security.audit.generators.util
AuditMessageインスタンスを作成するために使用されるパッケージは。
AuditMessageProcessor
DXP監査処理メカニズムでは、AuditMessageインスタンスはLiferayMessageBusに配置されます。 デフォルトのメッセージ・バス・リスナー、 com.liferay.portal.security.audit.router.internal.DefaultAuditRouter
、各監査メッセージを受信し、各登録AuditMessageProcessorインスタンスにそれを転送します。
ELKスタックのlogstashコンポーネントを活用するために、ここで紹介する実装では、監査メッセージをJSONファイルに書き込みます。 各監査メッセージはJSONにシリアル化され、ローテーションファイルに書き込まれます。
このための実装クラスは、 com.liferay.portal.security.audit.json.log.JsonLoggingAuditMessageProcessor
とそれの対応するクラスであるcom.liferay.portal.security.audit.json.log.JsonLoggingAuditMessageProcessorConfiguration
。
イベントのデプロイと生成
ビジュアライゼーションを構築するには、ESインデックスで利用可能ないくつかのドキュメントが必要です。 バンドルをビルドしてDXP環境にデプロイしてから、イベントの生成を開始します。 数回ログインおよびログアウトし、ポータル内を移動して、フォームを定義し、値の送信を開始します。
次のステップに進むときは、環境に戻って新しいイベントを生成し続けます。これにより、すべてのイベントを報告できる期間が与えられます。
Logstash構成ファイル
logstash構成ファイルは、特定のプロセスの入力、フィルター、および出力を定義します。
入力構成
この実装の場合、入力は監査jsonファイルです。
input { file { # For the demo just using a fixed path to file. path => "/Users/dnebinger/liferay/clients/liferay/elk/bundles/logs/json/audit.json" # Since the file may roll over, we should start at the beginning start_position => beginning # Don't ignore older records ignore_older => 0 # our file is a json file so use it for the codec. codec => "json" } }
フィルタ構成
フィルタは、読み込まれたレコードに対していくつかの変換を実行します。
filter { # Apply some changes to the incoming records mutate { add_field => { # Copy the eventType field to the action field. "action" => "%{eventType}" } # Strip out the values that we don't care to include in the index. remove_field => [ "sessionID","path","host" ] } # If path is provided, clone to the not analyzed and not indexed fields. if "" in [additionalInfo][path] { mutate { add_field => { "[additionalInfo][pathUrl]" => "%{[additionalInfo][path]}" } add_field => { "[additionalInfo][pathString]" => "%{[additionalInfo][path]}" } } } # The audit timestamp is mashed together, we need to extract it out. # Date follows the following format: 20160608135725305 date { match => [ "timestamp", "yyyyMMddHHmmssSSS" ] } }
出力構成
出力のために、レコードはElasticsearchにアップロードされます:
output { # Target elasticsearch elasticsearch { # Point at the backend server. If a cluster we'd use multiple hosts. hosts => ["192.168.1.2"] # Specify the index where our records should go index => "audit-%{+YYYY.MM.dd}" } # For debugging purposes, also write the records to the console. stdout { codec => rubydebug } }
Logstashの実行
インデックスの準備
インデックスをロードする前に、一部のフィールドを手動で定義して、分析とインデックス作成を無効にします。 これらの種類の変更は、すべてのデータのインデックスを再作成する必要がないように、インデックスを最初にロードする前に行う必要があります。
コマンドラインで次のコマンドを発行して、フィールドを事前定義します。
curl -XPUT 192.168.1.2:9200/audit/logs/_mapping -d ' { "logs": { "properties": { "additionalInfo": { "properties": { "pathUrl": { "type":"string", "index":"not_analyzed" }, "pathString": { "type":"string", "index":"no" } } } } } } '
監査ログがlogstashによって処理されると、残りの列はデフォルト設定で追加されます。
Logstashを実行します
構成ファイルの準備ができたら、logstashを開始できます。 logstashディレクトリから、次のコマンドを実行します。
bin/logstash agent -f audit.conf
一部の監査イベントはすでに作成されているため、logstashが開始すると、ファイルの処理が開始され、次のようなメッセージがコンソールに表示されます。
{ "companyId" => "20116", "classPK" => "20164", "clientHost" => "::1", "clientIP" => "::1", "serverName" => "localhost", "className" => "com.liferay.portal.kernel.model.User", "eventType" => "LOGIN", "serverPort" => 80, "userName" => "Test Test", "userId" => "20164", "timestamp" => "20160610231917907", "@version" => "1", "@timestamp" => "2016-06-11T03:19:17.907Z", "action" => "LOGIN" }
これらのメッセージが流れると、レコードはファイルから消費され、変換され、ドキュメントとしてElasticsearchにロードされます。
Kibanaの視覚化
Kibanaの視覚化は、実際にはKibanaUI内で作成されます。 最初のステップは、インデックスパターンを定義することです。 インデックスパターンは、視覚化を構築するための基盤です。
インデックスパターンの作成
次の図に従ってインデックスパターンを作成します。
検索クエリを定義する
次のステップは、検索クエリを作成することです。 1つ目は、当日の時間単位のログインです。 クリックして 発見 開始するには、タブ。
右上隅の時間枠を変更することから始めます。 リンクをクリックして、時間枠を今日に変更します。これは、表示するレコードを制限する時間枠を定義します。
次に、Kibanaバナーの下にあるドロップダウンのインデックスを、新しく定義された監査インデックスパターンに変更します。 ページは次のようになります。
使用可能なフィールド セクションから、action、userName、およびuserIdフィールドを追加します。 これにより、レコードのタイムスタンプ、アクション(NAVIGATEやLOGINなど)、およびイベントのユーザー詳細が表示されます。 1時間あたりのログイン数のクエリを作成しているので、検索バーを変更して次のようにします。
action:LOGIN
Enterキーを押します。
クリックして セーブ としてクエリを保存するには、ボタンを ログイン。 これと同じ検索が、後で表示される「時間ごとのログイン」および「日ごとのログイン」の視覚化に使用されます。
次は、ページヒット検索です。 New Search リンクをクリックして、新しい検索を開始します。 クエリを次のように設定します。
action:NAVIGATION
選択したフィールドにアクション、userName、additionalInfo.pageUrlを追加します。 ページヒットとして保存します。
フォーム送信検索の場合は、[ 新しい検索 リンクをクリックして新しい検索を開始します。 クエリを次のように設定します。
action:ADD AND className:com.liferay.dynamic.data.mapping.model.DDMContent
選択したフィールドにアクションとclassNameを追加し、この検索を フォーム送信として保存します。
視覚化を作成する
Visualize リンクをクリックして、ビューを切り替えます。
縦棒グラフ をクリックして、時間ごとのログインの視覚化を作成します。 保存された検索から オプションを選択し、 ログイン 検索を選択します。
右上には、確認してください 今日 選択されたオプションです。 Y軸 セクションで、カスタムラベルを ログインます。
バケット セクションで、 X軸 オプションを選択します。 日付ヒストグラム を選択し、間隔を 時間ごとにに設定し、カスタムラベルを 時間ます。
緑のクリック > 可視化を更新するには、ボタンを。 うまくいけば、次のようなものが表示されます。
この可視化を保存 ログインで1時間。
For the next visualization, click the New Visualization button, From a saved search and the Logins search. For the X-Axis label, use Day. In the upper right corner, change to the This Week option. Save this visualization as Logins By Day.
For the next visualization, repeat the above steps but use the Forms Submitted search. For the Y-Axis, use Forms and for the X-Axis label use Day. Save this visualization as Forms Submitted By Day.
For the last visualization, click the New Visualization button but use the Pie Chart. Use the Page Hits for the search. Under the Bucket type, select Split Slices and use the Terms for the aggregation. Use the additionalInfo.pathUrl for the field, 10 for the size and Page for the custom label.
The pie chart should look something like:
Choice - Visualization or Dashboard
There are now four different visualizations that can be used individually within Liferay. Another choice is to create a Kibana Dashboard.
Kibana Dashboards are defined on the Kibana side and act as a freeform Liferay page. On a dashboard, visualizations can be added, sized and moved around.
Either can be embedded on a Liferay page although the dashboard option wants to take up a large area of a page. For that reason, individual visualizations may work better.
Placing Visualizations on Liferay
Since the Kibana server is on a back-end server, it will not normally be addressable in the browser, but Kibana needs to expose some resources (js and css) to the browser for the visualizations to work.
The IFrame portlet will be used in Liferay to place the visualization on a page, but Liferay will not proxy the resources.
To expose the Kibana server to the browser, a fronting web server will be used to route most requests to Liferay and some requests to the Kibana server.
In the setup used here, Apache HTTPd was used to send requests to Liferay/Tomcat via AJP and route /kibana/ and /bundles/ requests to the Kibana server. Kibana needed to be configured with a server.basePath setting and the proxy statements defined for httpd. These files are available in the project as src/main/resources/kibana/kibana.yml and src/main/resources/apache/mod_jk.conf.
Getting the Visualization URL
To configure the IFrame portlet, a URL is necessary. These URLs come from Kibana (after the server.basePath has been set and Kibana restarted).
Whether using a visualization or a dashboard, the process is the same. Open the visualization or dashboard that is going to be placed in Liferay and click the Share ... button. Two lines are available, the top is the Embed (IFrame) link and the second is the Shared link. Both links are the same but the Share link does not have the surrounding IFrame tag.
On the right side of each of these links are two buttons. The first is the Generate Short URL button which returns a code string for a complete visualization, the second is the Copy to Clipboard link. Using the short URL is nicer to manage, but the long form has some value too. Pick the form you want to use and copy the value. On the Liferay side, place an IFrame portlet on the page and configure to use the URL as the source URL. If everything is working correctly, the visualization should be on the page:
So the long form of the URL has value too. The URL actually has all of the details used to render the visualization and dashboard. Given some time and some understanding, it is possible to build out or modify Kibana visualizations without going to Kibana to do the work. It's certainly easier to leverage the Kibana UI to define the visualizations, but it is not required.
Additional Information
Creating dashboards will be really easy to do using the ELK stack and leveraging some Liferay functionality. The flexibility of all of the tools in the stack really open the doors to all kinds of possibilities that were not so available before.
Take a spin over on google and do a search for Kibana Dashboard Examples and there are some really cool ones out there. And now they are embeddable within a Liferay page and can be populated by Liferay data too.
This document, these examples and this sample code only scratch the surface of the possibilities, but these are real-world examples.
One project currently underway has requirements for showing dashboards for the numbers of different types of forms submitted over a time period. Using the code from this example, all form submissions result in audit records so all form data is in Elasticsearch in a consumable format. Visualizations based on the forms and the different data types result in the individual dashboard charts the requirements mandate. Client gets all of these snazzy responsive charts and graphs, but the implementation team has to do little more than add audit event generators and define visualizations based upon Elasticsearch searches.