Application Insights と PowerBI を使って Java の Web アプリの PageView を監視する
半年ほど前に 割と普通なブログ > Application Insight を Java アプリケーションから利用する で紹介させて頂いた Java の Application Insights の利用方法だが、以下のように BLOB ストレージに永続ログとしてデータを出力できることをご存じだろうか。
連続エクスポートは Application Insights の標準以上の有料プランで利用する必要があるが、以下の様に "30日間のプレミアム試用版"という期間限定でお試しで無料で利用できるプランがある。
今回はこちらを利用して Application Insights のログを Power BI の可視化までを無料で行ってみる。
連続エクスポートの設定
管理ポータルから Application Insights の設定タブより、宛先のストレージサービスを選択してログの出力先を指定する。
この際、以下の様にエクスポートするデータの種類を選択できる。
Java アプリケーションの作成
JSP ファイルが 3 個、Servlet が一つのシンプルな構成とする。特に解説はしないが、画面とサーブレットの関係が inde.jsp <- HomeServlet.jsp -> second.jsp かつ、third.jsp が独立している構成なことが理解いただけると思う。また、Application Insights へログ出力が必要な instrumentationKey 値は管理ポータルから取得すること。
- pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mydomain</groupId> <artifactId>AppInsightWebApp</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>AppInsightWebApp Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.microsoft.azure</groupId> <artifactId>applicationinsights-web</artifactId> <version>1.0.1</version> </dependency> <dependency> <groupId>com.microsoft.azure</groupId> <artifactId>applicationinsights-core</artifactId> <version>1.0.1</version> </dependency> <dependency> <groupId>com.microsoft.azure</groupId> <artifactId>applicationinsights-logging-log4j2</artifactId> <version>1.0.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.3</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.3</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>AppInsightWebApp</finalName> </build> </project>
- HomeServlet.java
package com.mydomain; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/home") public class HomeServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String nextPage = request.getParameter("next"); if (nextPage == null) { nextPage = "index.jsp"; } RequestDispatcher dispatch = request.getRequestDispatcher("/" + nextPage); dispatch.forward(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub } }
- index.jsp
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <script type="text/javascript"> var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i=arguments;t.queue.push(function(){t[config].apply(t,i)})}}var t={config:config},u=document,e=window,o="script",s=u.createElement(o),i,f;for(s.src=config.url||"//az416426.vo.msecnd.net/scripts/a/ai.0.js",u.getElementsByTagName(o)[0].parentNode.appendChild(s),t.cookie=u.cookie,t.queue=[],i=["Event","Exception","Metric","PageView","Trace"];i.length;)r("track"+i.pop());return r("setAuthenticatedUserContext"),r("clearAuthenticatedUserContext"),config.disableExceptionTracking||(i="onerror",r("_"+i),f=e[i],e[i]=function(config,r,u,e,o){var s=f&&f(config,r,u,e,o);return s!==!0&&t["_"+i](config,r,u,e,o),s}),t }({ instrumentationKey:"<my instrumentationKey>" }); window.appInsights=appInsights; appInsights.trackPageView(); </script> <title>AppInsights-site index</title> </head> <body> <h2>Hello World! - index page</h2> <a href="<%=request.getContextPath()%>/home?next=second.jsp">next page</a> </body> </html>
- second.jsp
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <script type="text/javascript"> var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i=arguments;t.queue.push(function(){t[config].apply(t,i)})}}var t={config:config},u=document,e=window,o="script",s=u.createElement(o),i,f;for(s.src=config.url||"//az416426.vo.msecnd.net/scripts/a/ai.0.js",u.getElementsByTagName(o)[0].parentNode.appendChild(s),t.cookie=u.cookie,t.queue=[],i=["Event","Exception","Metric","PageView","Trace"];i.length;)r("track"+i.pop());return r("setAuthenticatedUserContext"),r("clearAuthenticatedUserContext"),config.disableExceptionTracking||(i="onerror",r("_"+i),f=e[i],e[i]=function(config,r,u,e,o){var s=f&&f(config,r,u,e,o);return s!==!0&&t["_"+i](config,r,u,e,o),s}),t }({ instrumentationKey:"<my instrumentationKey>" }); window.appInsights=appInsights; appInsights.trackPageView(); </script> <title>AppInsights-site second</title> </head> <body> <h2>Hello World!- second page</h2> <a href="<%=request.getContextPath()%>/home?next=index.jsp">next page</a> </body> </html>
- third.jsp
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <script type="text/javascript"> var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i=arguments;t.queue.push(function(){t[config].apply(t,i)})}}var t={config:config},u=document,e=window,o="script",s=u.createElement(o),i,f;for(s.src=config.url||"//az416426.vo.msecnd.net/scripts/a/ai.0.js",u.getElementsByTagName(o)[0].parentNode.appendChild(s),t.cookie=u.cookie,t.queue=[],i=["Event","Exception","Metric","PageView","Trace"];i.length;)r("track"+i.pop());return r("setAuthenticatedUserContext"),r("clearAuthenticatedUserContext"),config.disableExceptionTracking||(i="onerror",r("_"+i),f=e[i],e[i]=function(config,r,u,e,o){var s=f&&f(config,r,u,e,o);return s!==!0&&t["_"+i](config,r,u,e,o),s}),t }({ instrumentationKey:"<my instrumentationKey>" }); window.appInsights=appInsights; appInsights.trackPageView(); </script> <title>AppInsights-site third@@@@@@</title> </head> <body> <h2>Hello World!- third page</h2> </body> </html>
次に、上記のアプリケーションを作成後、Tomcat 等で Web アプリケーションを起動する。
ログ出力の確認
起動した Web アプリケーションにブラウザ経由でアクセスすると、Application Insights へのログ出力が成功していれば以下のように管理ポータルからログが閲覧可能だ。
更に、連続エクスポートが正常に行われている場合、blob container に以下の様にファイルが出力されているはずだ。今回は このうちの PageViews をターゲットとする。
Stream Analytics でログを整形し、Power BI に出力する
Application Insights データの Power BI ビュー を参照いただければ問題ないと思うが、Stream Analytics の新規インスタンスを作成して以下の設定を行う。
- 入力として BLOB ストレージを選択
- 出力先として Power BI を選択
- Stream Analytics のクエリを作成
上記で Stream Analytics の入出力設定は特に問題ないと思うが、Stream Analytics のクエリがドキュメントではうまく動かなかった( A.[view] 部分が間違っていた程度だが )ので以下を参考にしてほしい。
SELECT flat.ArrayValue.name, count(*) INTO [pbi-output] FROM [export-input] A OUTER APPLY GetElements(A.[view]) as flat GROUP BY TumblingWindow(minute, 1), flat.ArrayValue.name
上記のクエリは以下の様な形式で BLOB に格納されているデータは以下のような URL でファイルを作成されログ出力される。
- https://<アカウント名>.blob.core.windows.net/appinsightslog/forpowerbiappinsights_581bb4f68f56476c9c3ce13eca62c0f4/PageViews/2015-09-29/10/c565d13c-b5f9-42f4-b9eb-a82e05fa6695_20150929_100813.blob
ファイルの中身は以下となるが、上記のクエリは「"name": "AppInsights-site index"」における値を抜き出すクエリになっている。詳細は参考のリンク先における Stream Analytics のクエリを参考にしてほしい。
{ "view": [ { "urlData": { "port": 8080, "host": "localhost", "protocol": "http", "base": "/AppInsightWebApp/", "queryParameters": [ ], "hashTag": "" }, "name": "AppInsights-site index", "count": 1, "durationMetric": { "value": 5980000.0, "count": 1.0, "sampledValue": 5980000.0 }, "url": "http://localhost:8080/AppInsightWebApp/" } ], "internal": { "data": { "id": "<my id>", "documentVersion": "1.6" } }, "context": { "device": { <中略>
Power BI で閲覧
次に powerbi.microsoft.com へアクセスし、Stream Analytics の出力で設定した宛先を確認する。正常に Stream Analytics が動作していれば、以下の画面の様に「Stream Analytics の出力で設定した宛先」の箇所が追加されているので、こちらを操作して任意のグラフを作成できる。
上記のように、Application Insights と Power BI を利用することで、容易に画面毎のアクセス数が確認できるビューを作成できることが分かった。もちろん Stream Analytics のクエリを変更することで任意の情報を Power BI 側に表示することが可能になる。