エンジニアリング

CanvasでServiceNowインシデントのカスタムレポートダッシュボードを作成する

ブログシリーズのパート3へようこそ。今回は、Elastic StackとServiceNowを使ったインシデントマネジメントプロジェクトを構築するシリーズの最終回となります。パート1では、プロジェクトの概要を説明し、インシデントに対する変更を自動でElasticsearchにプッシュバックするようにServiceNowを設定しました。パート2では、アラートと変換、Elasticsearchの一般的な設定を作成してServiceNowとElasticsearchを接続するロジックを実装しました。 

前回までの手順で、機能部分は完成しています。しかしまだ、インシデントマネジメントを実施するための便利な(しかもカッコいい)フロントエンドがありません。そこで今回は、下の画像のようなCanvas workpadを作成します。その目的は、ここまでの成果をすべて活用することと、それをチームのメンバー全員が簡単に理解し、使用できる形式で表現することです。

Canvasで作成したシンプルかつ直感的なServiceNowインシデント追跡ダッシュボード

ダッシュボードに表示する項目は、以下の通りです。

  • 未解決、終了、解決、進行中のチケット
  • インシデントMTTA(平均応答時間)
  • インシデントMTTR(平均復旧時間)
  • 全体MTBF(平均故障間隔)
  • アプリケーションMTBF
  • アプリケーション当たりのインシデント数

それでは早速始めましょう。

Canvas workpadをセットアップする

ここからの手順では、Canvas表現を多用します。これはCanvas workpad上のすべての要素の表象に、Canvasの内部表現が使われるためです。つまりCanvas表現を使うと、機能をCanvasに再現する方法を最も簡単に説明することができます。 

変換がポピュレートするエンティティ中心のインデックスにデータが何もないとき、下に示すエレメントの一部は「Empty datatable」のようなエラーメッセージを返すことに留意してください。

まず準備のために、Canvasを開きます。

  1. Kibanaのツールバーメニューを開きます。
  2. バージョン7.8以降を実行している場合はKibana以下で、それ以前のバージョンの場合は、全アイコンのリストで見つけることができます。
  3. Create Workpad](Workpadを作成)ボタンをクリックします。
  4. workpadが作成されたら、名前を付けます。右側の[Workpad Settings]で設定することができます。筆者は[My Canvas Workpad]から[Incident Tracker]への変更をおすすめします。このメニューは、後述のステップで背景色を設定する際にも使用します。
  5. 所与のコンポーネントについてCanvas表現を編集するには、コンポーネントをクリックしてから、右下の[</> Expression editor](表現エディター)をクリックします。

テーマをセットアップする

Canvas workpadを作成する最初のステップとして、背景の体裁を整えましょう。

  1. 背景色を#232344に設定します。
  2. 長方形のシェイプエレメントを4つ作成し、#444465の色を指定します。
  3. 上部のバーに企業ロゴや企業名、タイトルなどのロゴとテキストを追加します。

進行中のチケットを表示する

次に、進行中のチケットを表示する中央の表を作成します。これには、Elasticsearch SQLとCanvas表現の組み合わせをデータ表エレメントと共に使用します。データ表エレメントを作成するには、エディターに以下のCanvas表現をコピーして、[Run](実行)をクリックします。

filters 
| essql 
 query="SELECT incidentID as Ticket, LAST(state, updatedDate) as State, LAST(assignedTo, updatedDate) as AssignedTo, LAST(description, updatedDate) as Description FROM \"servicenow*\" group by Ticket ORDER BY Ticket ASC" 
| filterrows fn={getCell "State" | any {eq "New"} {eq "On Hold"} {eq "In Progress"}}
| table 
 font={font family="'Open Sans', Helvetica, Arial, sans-serif" size=14 align="left" color="#FFFFFF" weight="normal" underline=false italic=false} paginate=true perPage=10 
| render

この表現は、クエリを実行した後、[State]フィールドが[New]、[On Hold]、または[In Progress]に設定されているものを除くすべての列を除外します。

この時点ではデータが存在しないので、おそらく空白になっています。作成したbusiness ruleをまだ実行していないので、ServiceNowデータがElasticsearchに送られていないためです。必要に応じて、偽のインシデントを作成できます。その場合は様々な段階のチケットを作り、表がリアルに見えるようにします。

MTTA(平均応答時間)を算出する

インシデントのMTTAを表示するには、メトリックエレメントを追加し、以下のCanvas表現を使用します。 

filters 
| essql 
 query="SELECT * FROM (SELECT incidentID, updatedDate, state FROM \"servicenow-incident-updates\") PIVOT (MIN(updatedDate) FOR state IN ('New' as New, 'In Progress' as \"InProgress\"))" 
| mapColumn "New" fn={getCell "New" | formatdate "X" | math "value"} 
| mapColumn "InProgress" fn={getCell "InProgress" | formatdate "X" | math "value"} 
| filterrows fn={getCell "InProgress" | gt 0} 
| mapColumn "Duration" expression={math expression="InProgress - New"} 
| math "mean(Duration)" 
| metric "Mean Time To Acknowledge" 
 metricFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=48 align="center" color="#FFFFFF" weight="normal" underline=false italic=false} 
 labelFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=14 align="center" color="#FFFFFF" weight="normal" underline=false italic=false} metricFormat="00:00:00" 
| render

この表現はPIVOTを含む応用的なElasticsearch SQL関数を使用します。MTTAを算出するには、まず作成から応答までの合計時間を計算し、次にそれをインシデント数で割ります。ここでPIVOTを使用する目的は、ユーザーがServiceNowのチケットに対して行ったアップデートの格納です。つまり、誰かがステータスやworknote、assigneeをアップデートするたびに変更がElasticsearchにプッシュされるようにしたい、ということです。そうすれば、結果の分析に大変便利です。そこでデータをpivotし、インシデント1件につき1つの列を取得します。インシデントのステータスは最初に“New”、次に“In Progress”になります。 

次に、インシデントが作成された時刻からインシデントが認識された時刻までの経過時間を引き算で求め、応答時間を算出します。MTTAは、この持続時間フィールド関数の平均値から算出します。

MTTR(平均復旧時間)を算出する

インシデントのMTTRを表示するには、メトリックエレメントを追加し、以下のCanvas表現を使用します。

filters 
| essql 
 query="SELECT * FROM (SELECT incidentID, updatedDate, state FROM \"servicenow-incident-updates\") PIVOT (MIN(updatedDate) FOR state IN ('New' as New, 'Resolved' as \"Resolved\"))" 
| mapColumn "New" fn={getCell "New" | formatdate "X" | math "value"} 
| mapColumn "Resolved" fn={getCell "Resolved" | formatdate "X" | math "value"} 
| filterrows fn={getCell "Resolved" | gt 0} 
| mapColumn "Duration" expression={math expression="Resolved - New"} 
| math "mean(Duration)" 
| metric "Mean Time To Resolve" 
 metricFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=48 align="center" color="#FFFFFF" weight="normal" underline=false italic=false} 
 labelFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=14 align="center" color="#FFFFFF" weight="normal" underline=false italic=false} metricFormat="00:00:00" 
| render

各インシデントのサマリービューを確認する必要があることから、MTTAと同様にPIVOT関数を使用します。MTTAと異なるのは、ステータスが最初に“new”になった時間と、“resolved”になった時間を取得することです。これはMTTRが、チケット解決までの平均時間だからです。MTTAとほぼ同一なので、重複を避けるために詳細は割愛します。

全体のMTBF(平均故障間隔)を算出する

MTTAとMTTRを求めることができました。次は各アプリケーションのMTBFです。これには、2つの変換を使用します。1つはapp_incident_summary_transform、もう1つがcalculate_uptime_hours_online_transfoです。この2つの変換を用いて、全体のMTBFを非常に簡単に算出できます。MTBFは1時間単位ですが、使用する変換は秒単位で計算しています。したがって、全アプリの平均を算出した結果に3600を掛けて(乗算により)秒単位に変換します。

以下のCanvas表現を使用して、もう1つのメトリックエレメントを作成しましょう。

filters 
| essql query="SELECT AVG(mtbf) * 3600 as MTBF FROM app_incident_summary" 
| math "MTBF" 
| metric "Overall Mean Time between Failure" 
 metricFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=48 align="center" color="#FFFFFF" weight="normal" underline=false italic=false} 
 labelFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=14 align="center" color="#FFFFFF" weight="normal" underline=false italic=false} metricFormat="00:00:00" 
| render

アプリケーションのMTBF(平均故障間隔)を算出する

全体のMTBFは算出済みなので、各アプリケーションのMTBFも簡単に表示できます。必要な作業は、新しいデータ表エレメントを作成し、以下のCanvas表現を使用してデータを表示することです。見やすさを考慮し、各アプリケーションのMTBFは小数点以下2桁にしてあります。

filters 
| essql 
 query="SELECT app_name as AppName, ROUND(mtbf,2) as \"MTBF hr\" FROM app_incident_summary" 
| table paginate=false 
 font={font family="'Open Sans', Helvetica, Arial, sans-serif" size=14 align="left" color="#FFFFFF" weight="normal" underline=false italic=false} 
| render

解決済みチケットを算出する

成果も確認できるよう、workpadには“終了”の件数も忘れずに表示しましょう。シンプルなメトリックエレメントでステータスが“Resolved”となったすべてのインシデントを取得し、さらに数学関数でインシデントIDのユニーク数を求めます。

filters 
| essql query="SELECT state,incidentID FROM \"servicenow*\" where state = 'Resolved'" 
| math "unique(incidentID)" 
| metric "Resolved Tickets" 
 metricFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=48 align="center" color="#FFFFFF" weight="normal" underline=false italic=false} 
 labelFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=14 align="center" color="#FFFFFF" weight="normal" underline=false italic=false} metricFormat="0,0.[000]" 
| render

アプリケーション当たりのインシデント数を算出する

次に、アプリケーション当たりのユニークインシデント数をドーナツチャートに表示します。“アプリケーション当たりのインシデント数”というテキストの上にマークダウンエレメントを追加して、何についてのドーナツチャートかというコンテクストを含めると良いでしょう。

filters 
| essql 
 query="SELECT incidentID as IncidentCount, app_name as AppName FROM \"servicenow*\"" 
| pointseries color="AppName" size="unique(IncidentCount)" 
| pie hole=41 labels=false legend="se" radius=0.72 
 palette={palette "#01A4A4" "#CC6666" "#D0D102" "#616161" "#00A1CB" "#32742C" "#F18D05" "#113F8C" "#61AE24" "#D70060" gradient=false} tilt=1 
 font={font family="'Open Sans', Helvetica, Arial, sans-serif" size=14 align="left" color="#FFFFFF" weight="normal" underline=false italic=false} 
| render

最新のチケットステータスを算出する

このセクションは、4つのメトリックエレメントで構成されます。4つのCanvas表現はよく似ていて、わずかな違いしかありません。簡単に説明すると、まずすべてのインシデントの最新のアップデートを取得します。次にCanvas表現のfilterrows関数を使い、求めるインシデントをステータス別に保持します。これで、ユニークインシデント数を数えることができます。

以下の表現を使用して、ステータスを[New]から適切な内容にアップデートします。また、[New Tickets]のメトリックのテキストも忘れずにアップデートしてください。

filters 
| essql 
 query="SELECT incidentID, LAST(state, updatedDate) as State FROM \"servicenow*\" group by incidentID" count=1000 
| filterrows fn={getCell "State" | eq 'New'} 
| math "unique(incidentID)" 
| metric "New Tickets" 
 metricFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=48 align="center" color="#FFFFFF" weight="normal" underline=false italic=false} 
 labelFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=14 align="center" color="#FFFFFF" weight="normal" underline=false italic=false} metricFormat="0,0.[000]" 
| render

完成品

これでCanvas workpadの異なるピースをすべて構築しました。非常に便利なインシデントマネジメントダッシュボードの完成です。

どんなインシデントも逃しません

手法をさまざまに応用する

おつかれさまでした!今回は、Elastic Stackの多数のコンポーネントを使ってServiceNowのインシデントからMTTA、MTTR、MTBFを計算し、さらにその情報をわかりやすく美しいダッシュボードに表示する手順をご説明しました。ここから導かれる重要な結論の1つは、情報とは何かのツールから来るものではなく、実データ内に存在しているということです。今回取り上げたメトリックはナレッジのすぐれた基礎であり、現場担当者はアプリケーションのヘルスを検知したインシデントと関連付けて把握する目的でこのナレッジを活用できます。たとえばMTBFの値が小さい場合、アプリケーションに高い頻度で障害が発生していることを意味します。MTTAの値が大きい場合、障害発生から調査開始までの時間が長いことを意味します。 

「ここまで目を通したけれど、まだ実践していない」という方は、ぜひご自身で手順を試してみてください。Elastic Cloudの無料トライアルを立ち上げて、ServiceNowの既存のインスタンスをお使いいただくか、または個人開発者向けインスタンスをご利用ください。

さらに、GitHubやGoogle Driveなどの外部ソースに加えてServiceNowデータを検索するには、Elastic Workplace Search事前構築済みServiceNowコネクターをご活用ください。Workplace Searchを使うと一元的な業務用検索エクスペリエンスを構築でき、あらゆるコンテンツソースにわたって関連性に優れた検索結果を手にすることができます。Elastic Cloudのトライアルでも、Workplace Searchをお試しいただくことができます。

今回の記事では、お手元のデータを使って様々なメトリックを追跡する基礎的な手法を解説しました。この手法を応用して、たとえばログや、インフラストラクチャーのメトリックAPMトレース機械学習が検知した異常に基づくインシデントを作成するといったことも可能です。またCanvasダッシュボードを利用する関係者にさらなるバリューを提供するには、Kibanaのアプリ(Logs、APMなど)や、個々の問題の根本原因調査に有用な情報を提供する組織独自のダッシュボードへのリンクもぜひ追加してみてください。 

このブログシリーズをお楽しみいただいた方には、こちらのリソースもおすすめです。

ぜひご活用ください。