🎓 Splunk図形作成コード 一行ずつ完全解説~新人エンジニア向け・全コード徹底解説~
📚 この記事について
前提知識: HTML/CSS/JavaScriptの基礎がわかる程度 目標: Splunkダッシュボードのコードを完全に理解する
🎨 Splunkクラシックダッシュボード 図形作成チートシート
~ステータス連動で色が変わる!四角・丸・棒・三角を自由自在に配置~
📚 この記事で学べること
項目 内容 対象者 Splunk初心者・新人エンジニア 目標 HTML/CSS/SPLで図形を作成し、データに応じて色を変える 所要時間 約30分
🏗️ 全体構成イメージ
┌─────────────────────────────────────────────────────┐
│ Splunk クラシックダッシュボード │
│ ┌─────────────────────────────────────────────┐ │
│ │ HTML Panel(図形を描画するエリア) │ │
│ │ │ │
│ │ ■ 四角 ● 丸 ▬ 棒 ▼ 三角 │ │
│ │ (緑) (黄) (赤) (青) │ │
│ │ │ │
│ │ ← SPLで取得したステータスに応じて色が変化 │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ [データ取得] → [ステータス判定] → [色の反映] │
└─────────────────────────────────────────────────────┘
📂 Part 1: サンプルデータの準備
1-1. テスト用インデックスとデータ作成
まず、動作確認用のサンプルデータを作成します。
| makeresults count=4
| streamstats count as id
| eval device_name = case(
id==1, "サーバーA",
id==2, "サーバーB",
id==3, "ネットワーク機器C",
id==4, "データベースD"
)
| eval status = case(
id==1, "正常",
id==2, "警告",
id==3, "異常",
id==4, "停止"
)
| eval status_code = case(
status=="正常", 0,
status=="警告", 1,
status=="異常", 2,
status=="停止", 3
)
| table device_name, status, status_code
🔍 SPL解説(一行ずつ)
| makeresults count=4
<!-- ▲ 4行の空データを生成する。テスト用データ作成の起点 -->
| streamstats count as id
<!-- ▲ 各行に連番(1,2,3,4)を「id」という名前で付与 -->
| eval device_name = case(
id==1, "サーバーA",
id==2, "サーバーB",
id==3, "ネットワーク機器C",
id==4, "データベースD"
)
<!-- ▲ idの値に応じて「device_name」フィールドに機器名を設定 --> <!-- ▲ case関数: 条件, 値, 条件, 値... の形式で条件分岐 -->
| eval status = case(
status=="正常", 0,
status=="警告", 1,
status=="異常", 2,
status=="停止", 3
)
<!-- ▲ ステータス文字列に対応する数値コードを設定 --> <!-- ▲ 後でJavaScriptで色を判定する際に使用 -->
| table device_name, status, status_code
<!-- ▲ 最終的に表示するフィールドを指定 -->
📊 出力結果イメージ
device_name status status_code サーバーA 正常 0 サーバーB 警告 1 ネットワーク機器C 異常 2 データベースD 停止 3
📂 Part 2: ダッシュボードXML基本構造
2-1. ダッシュボードの骨格
<dashboard>
<!-- ダッシュボードのルート要素 -->
<label>図形サンプルダッシュボード</label>
<!-- ダッシュボード名(画面上部に表示) -->
<row>
<!-- 行(横並びのコンテナ) -->
<panel>
<!-- パネル(各コンテンツを格納する箱) -->
<html>
<!-- HTMLパネル(自由にHTML/CSS/JSを記述可能) -->
</html>
</panel>
</row>
</dashboard>
📂 Part 3: 図形の作成(HTML/CSS)
3-1. 🟦 四角形(Rectangle)
<html>
<style>
/* ===== 四角形のスタイル定義 ===== */
.shape-rectangle {
/* 幅を100ピクセルに設定 */
width: 100px;
/* 高さを60ピクセルに設定 */
height: 60px;
/* 背景色(初期値:グレー) */
background-color: #808080 ;
/* 角を少し丸める(0pxで完全な四角) */
border-radius: 5px;
/* 枠線:1ピクセルの黒い実線 */
border: 1px solid #333 ;
/* テキストを中央揃え */
display: flex;
justify-content: center; /* 横方向中央 */
align-items: center; /* 縦方向中央 */
/* 文字色を白に */
color: white;
/* 文字サイズ */
font-size: 12px;
/* 太字 */
font-weight: bold;
}
</style>
<div class="shape-rectangle">
四角形
</div>
</html>
🔍 CSS解説ポイント
プロパティ 役割 よく使う値 width / height サイズ px, %, em background-color 背景色 カラーコード, 色名 border-radius 角の丸み 0px=角張り, 50%=丸 display: flex 中央揃えの準備 -
3-2. 🔴 丸(Circle)
<html>
<style>
/* ===== 丸のスタイル定義 ===== */
.shape-circle {
/* 幅と高さを同じにする(正方形の土台) */
width: 80px;
height: 80px;
/* 背景色(初期値:グレー) */
background-color: #808080 ;
/* ★重要★ border-radiusを50%にすると丸になる */
border-radius: 50%;
/* 枠線 */
border: 2px solid #333 ;
/* テキスト中央揃え */
display: flex;
justify-content: center;
align-items: center;
/* 文字スタイル */
color: white;
font-size: 12px;
font-weight: bold;
}
</style>
<div class="shape-circle">
丸
</div>
</html>
💡 丸を作るコツ
┌──────────────────────────────────────┐
│ border-radius: 50% → 正円になる │
│ │
│ ★条件:width と height が同じ値 │
│ │
│ width: 80px ─┬─→ ● │
│ height: 80px ─┘ │
└──────────────────────────────────────┘
3-3. ▬ 棒(Bar / Rectangle)
<html>
<style>
/* ===== 棒のスタイル定義 ===== */
.shape-bar {
/* 横長の形状:幅 > 高さ */
width: 150px;
height: 30px;
/* 背景色 */
background-color: #808080 ;
/* 少しだけ角を丸める */
border-radius: 3px;
/* 枠線 */
border: 1px solid #333 ;
/* テキスト中央揃え */
display: flex;
justify-content: center;
align-items: center;
/* 文字スタイル */
color: white;
font-size: 11px;
font-weight: bold;
}
</style>
<div class="shape-bar">
棒(ステータスバー)
</div>
</html>
3-4. 🔻 三角形(Triangle)▽
<html>
<style>
/* ===== 三角形のスタイル定義 ===== */
.shape-triangle {
/* ★重要★ 三角形はサイズを0にしてborderで形を作る */
width: 0;
height: 0;
/* 左右の辺:透明 */
border-left: 40px solid transparent;
border-right: 40px solid transparent;
/* 上辺:色を付ける(下向き三角 ▼) */
border-top: 60px solid #808080 ;
/* 下向き三角の底辺は不要なのでなし */
/* border-bottom: なし */
}
/* ===== 上向き三角形 △ ===== */
.shape-triangle-up {
width: 0;
height: 0;
border-left: 40px solid transparent;
border-right: 40px solid transparent;
/* 下辺に色を付ける(上向き三角 △) */
border-bottom: 60px solid #808080 ;
}
</style>
<!-- 下向き三角 ▼ -->
<div class="shape-triangle"></div>
<!-- 上向き三角 △ -->
<div class="shape-triangle-up"></div>
</html>
💡 三角形の仕組み(図解)
【CSS三角形の原理】
通常のborder: 三角形の作り方:
┌─────────────┐
│ ╲ ╱ │ border-top: 色付き
│ ╲ ╱ │ ▼
│ ╲ ╱ │ ┌─────────┐
│ ╱ ╲ │ │╲ ╱│
│ ╱ ╲ │ │ ╲ ╱ │
│ ╱ ╲ │ │ ▼ │
└─────────────┘ └─────────┘
↑ ↑
transparent transparent
(左辺) (右辺)
📂 Part 4: ステータスに応じた色変更(JavaScript連携)
4-1. 完全版コード(SPL + HTML + CSS + JavaScript)
<dashboard>
<label>ステータス連動図形ダッシュボード</label>
<!-- ===== データ取得用サーチ ===== -->
<search id="status_search">
<query>
| makeresults count=4
| streamstats count as id
| eval device_name = case(
id==1, "サーバーA",
id==2, "サーバーB",
id==3, "ネットワーク機器C",
id==4, "データベースD"
)
| eval status = case(
id==1, "正常",
id==2, "警告",
id==3, "異常",
id==4, "停止"
)
| eval status_code = case(
status=="正常", 0,
status=="警告", 1,
status=="異常", 2,
status=="停止", 3
)
| table device_name, status, status_code
</query>
<earliest>-24h@h</earliest>
<latest>now</latest>
</search>
<row>
<panel>
<title>ステータス連動図形</title>
<html>
<style>
/* ===== コンテナ(図形を並べる箱) ===== */
.shapes-container {
/* 横並びにする */
display: flex;
/* 図形間の余白 */
gap: 20px;
/* 内側の余白 */
padding: 20px;
/* 折り返しを許可 */
flex-wrap: wrap;
}
/* ===== 各図形の共通スタイル ===== */
.shape-item {
/* 縦並びにする(図形 + ラベル) */
display: flex;
flex-direction: column;
/* 中央揃え */
align-items: center;
/* 図形間の余白 */
gap: 8px;
}
/* ===== 四角形 ===== */
.rectangle {
width: 100px;
height: 60px;
background-color: #808080 ;
border-radius: 5px;
border: 2px solid #333 ;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
font-size: 14px;
/* アニメーション(色が滑らかに変化) */
transition: background-color 0.3s ease;
}
/* ===== 丸 ===== */
.circle {
width: 70px;
height: 70px;
background-color: #808080 ;
border-radius: 50%;
border: 2px solid #333 ;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
font-size: 12px;
transition: background-color 0.3s ease;
}
/* ===== 棒 ===== */
.bar {
width: 120px;
height: 25px;
background-color: #808080 ;
border-radius: 3px;
border: 1px solid #333 ;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
font-size: 11px;
transition: background-color 0.3s ease;
}
/* ===== 三角形(下向き)===== */
.triangle {
width: 0;
height: 0;
border-left: 35px solid transparent;
border-right: 35px solid transparent;
border-top: 50px solid #808080 ;
transition: border-top-color 0.3s ease;
}
/* ===== ラベル(機器名) ===== */
.device-label {
font-size: 12px;
color: #333 ;
font-weight: bold;
}
/* ===== ステータスラベル ===== */
.status-label {
font-size: 11px;
color: #666 ;
}
/* ===== 色の定義(ステータス別) ===== */
.status-normal { background-color: #28a745 ; } /* 緑:正常 */
.status-warning { background-color: #ffc107 ; } /* 黄:警告 */
.status-error { background-color: #dc3545 ; } /* 赤:異常 */
.status-stop { background-color: #6c757d ; } /* グレー:停止 */
/* 三角形用(border-topで色を指定) */
.triangle.status-normal { border-top-color: #28a745 ; }
.triangle.status-warning { border-top-color: #ffc107 ; }
.triangle.status-error { border-top-color: #dc3545 ; }
.triangle.status-stop { border-top-color: #6c757d ; }
</style>
<!-- 図形を配置するコンテナ -->
<div class="shapes-container" id="shapesContainer">
<!-- JavaScriptで動的に生成される -->
</div>
<script>
// ===== Splunkのデータを取得してUIに反映 =====
require([
'splunkjs/mvc',
'splunkjs/mvc/searchmanager',
'splunkjs/mvc/simplexml/ready!'
], function(mvc) {
// サーチマネージャーを取得
// "status_search" は <search id="status_search"> と対応
var searchManager = mvc.Components.get("status_search");
// サーチ結果を取得
var results = searchManager.data("results");
// データが変更されたら実行
results.on("data", function() {
// 結果が存在するかチェック
if (results.hasData()) {
// 結果をJSON形式で取得
var rows = results.data().rows;
var fields = results.data().fields;
// コンテナを取得
var container = document.getElementById('shapesContainer');
// コンテナを空にする(再描画のため)
container.innerHTML = '';
// 各行のデータをループ処理
rows.forEach(function(row, index) {
// フィールド名からインデックスを取得
var deviceIndex = fields.indexOf('device_name');
var statusIndex = fields.indexOf('status');
var codeIndex = fields.indexOf('status_code');
// 値を取得
var deviceName = row[deviceIndex];
var status = row[statusIndex];
var statusCode = parseInt(row[codeIndex]);
// ステータスコードに応じたCSSクラスを決定
var statusClass = '';
switch(statusCode) {
case 0: statusClass = 'status-normal'; break; // 正常
case 1: statusClass = 'status-warning'; break; // 警告
case 2: statusClass = 'status-error'; break; // 異常
case 3: statusClass = 'status-stop'; break; // 停止
default: statusClass = '';
}
// 図形の種類を決定(例:インデックスで振り分け)
var shapeTypes = ['rectangle', 'circle', 'bar', 'triangle'];
var shapeType = shapeTypes[index % shapeTypes.length];
// 図形のHTMLを生成
var shapeHtml = '';
if (shapeType === 'rectangle') {
shapeHtml = '<div class="rectangle ' + statusClass + '">' + status + '</div>';
} else if (shapeType === 'circle') {
shapeHtml = '<div class="circle ' + statusClass + '">' + status + '</div>';
} else if (shapeType === 'bar') {
shapeHtml = '<div class="bar ' + statusClass + '">' + status + '</div>';
} else if (shapeType === 'triangle') {
shapeHtml = '<div class="triangle ' + statusClass + '"></div>';
}
// 図形アイテム全体のHTMLを生成
var itemHtml =
'<div class="shape-item">' +
shapeHtml +
'<div class="device-label">' + deviceName + '</div>' +
'<div class="status-label">' + status + '</div>' +
'</div>';
// コンテナに追加
container.innerHTML += itemHtml;
});
}
});
});
</script>
</html>
</panel>
</row>
</dashboard>
📂 Part 5: JavaScript解説(一行ずつ)
5-1. Splunk連携の基本構造
require([
'splunkjs/mvc', // SplunkのMVCフレームワーク
'splunkjs/mvc/searchmanager', // サーチ管理
'splunkjs/mvc/simplexml/ready!' // 準備完了を待つ
], function(mvc) {
// この中にコードを書く
});
🔍 解説
コード 意味 require([...], function) 必要なモジュールを読み込んでから実行 splunkjs/mvc SplunkのUI操作に必要 simplexml/ready! ダッシュボードの準備完了を待つ
5-2. サーチ結果の取得
// サーチマネージャーを取得
var searchManager = mvc.Components.get("status_search");
// └─ "status_search" は XMLの <search id="status_search"> と対応
// サーチ結果を取得
var results = searchManager.data("results");
// └─ "results" は完了した結果を取得
// └─ 他に "preview"(途中結果)もある
5-3. データ変更時の処理
results.on("data", function() {
// データが更新されたら実行される
if (results.hasData()) {
// 結果がある場合のみ処理
var rows = results.data().rows; // 行データ(2次元配列)
var fields = results.data().fields; // フィールド名の配列
// 例: rows = [["サーバーA", "正常", "0"], ["サーバーB", "警告", "1"], ...]
// 例: fields = ["device_name", "status", "status_code"]
}
});
5-4. ステータスに応じた色クラスの決定
// ステータスコードに応じたCSSクラスを決定
var statusClass = '';
switch(statusCode) {
case 0: // status_code が 0 の場合
statusClass = 'status-normal'; // → 緑色(正常)
break;
case 1: // status_code が 1 の場合
statusClass = 'status-warning'; // → 黄色(警告)
break;
case 2: // status_code が 2 の場合
statusClass = 'status-error'; // → 赤色(異常)
break;
case 3: // status_code が 3 の場合
statusClass = 'status-stop'; // → グレー(停止)
break;
default: // それ以外
statusClass = ''; // → デフォルト色
}
📂 Part 6: 図形の自由配置(CSS Grid / Flexbox)
6-1. Flexboxで横並び
.shapes-container {
display: flex; /* 横並びにする */
flex-wrap: wrap; /* 折り返しを許可 */
gap: 20px; /* 図形間の余白 */
justify-content: flex-start; /* 左寄せ */
}
6-2. CSS Gridで自由配置
.shapes-container {
display: grid;
/* 3列のグリッド */
grid-template-columns: repeat(3, 1fr);
/* 行と列の余白 */
gap: 20px;
/* パディング */
padding: 20px;
}
6-3. 絶対位置指定(完全自由配置)
.shapes-container {
position: relative; /* 基準点を設定 */
width: 100%;
height: 400px;
}
.shape-item {
position: absolute; /* 絶対位置指定 */
}
/* 個別の位置指定 */
.shape-item:nth-child(1) { top: 20px; left: 50px; }
.shape-item:nth-child(2) { top: 100px; left: 200px; }
.shape-item:nth-child(3) { top: 50px; left: 350px; }
.shape-item:nth-child(4) { top: 150px; left: 100px; }
📂 Part 7: 実用カラーパレット
7-1. ステータス別推奨カラー
ステータス カラーコード 色名 用途 正常 #28a745 緑 問題なし 警告 #ffc107 黄 注意が必要 異常 #dc3545 赤 即時対応 停止 #6c757d グレー 稼働停止 情報 #17a2b8 水色 参考情報 不明 #343a40 濃灰 状態不明
7-2. CSSクラス定義
/* ===== ステータス別の色定義 ===== */
/* 通常の図形用(background-color) */
.status-normal { background-color: #28a745 !important; }
.status-warning { background-color: #ffc107 !important; color: #333 !important; }
.status-error { background-color: #dc3545 !important; }
.status-stop { background-color: #6c757d !important; }
.status-info { background-color: #17a2b8 !important; }
.status-unknown { background-color: #343a40 !important; }
/* 三角形用(border-top-color) */
.triangle.status-normal { border-top-color: #28a745 !important; }
.triangle.status-warning { border-top-color: #ffc107 !important; }
.triangle.status-error { border-top-color: #dc3545 !important; }
.triangle.status-stop { border-top-color: #6c757d !important; }
.triangle.status-info { border-top-color: #17a2b8 !important; }
.triangle.status-unknown { border-top-color: #343a40 !important; }
📂 Part 8: よくあるエラーと対処法
8-1. 図形が表示されない
原因 対処法 サーチIDの不一致 <search id="xxx"> と mvc.Components.get("xxx") を確認 JavaScriptエラー ブラウザのF12 → Console でエラー確認 CSSが効いていない クラス名のスペルミスを確認
8-2. 色が変わらない
原因 対処法 statusClassが空 console.log(statusCode) でデバッグ CSSの優先度 !important を追加 データ型の違い parseInt() で数値に変換
8-3. デバッグ用コード
// コンソールに出力(F12で確認)
console.log("=== デバッグ情報 ===");
console.log("rows:", rows);
console.log("fields:", fields);
console.log("deviceName:", deviceName);
console.log("status:", status);
console.log("statusCode:", statusCode, typeof statusCode);
console.log("statusClass:", statusClass);
📂 Part 9: 完成版テンプレート(コピペ用)
9-1. 最小構成(すぐ動く版)
<dashboard>
<label>図形ステータスダッシュボード</label>
<search id="mySearch">
<query>
| makeresults count=4
| streamstats count as id
| eval name=case(id==1,"A",id==2,"B",id==3,"C",id==4,"D")
| eval status=case(id==1,"正常",id==2,"警告",id==3,"異常",id==4,"停止")
| eval code=case(status=="正常",0,status=="警告",1,status=="異常",2,status=="停止",3)
| table name, status, code
</query>
</search>
<row>
<panel>
<html>
<style>
.container{display:flex;gap:20px;padding:20px;flex-wrap:wrap;}
.item{display:flex;flex-direction:column;align-items:center;gap:5px;}
.rect{width:80px;height:50px;border-radius:5px;display:flex;justify-content:center;align-items:center;color:#fff;font-weight:bold;}
.circle{width:60px;height:60px;border-radius:50%;display:flex;justify-content:center;align-items:center;color:#fff;font-weight:bold;}
.bar{width:100px;height:20px;border-radius:3px;display:flex;justify-content:center;align-items:center;color:#fff;font-size:11px;}
.tri{width:0;height:0;border-left:30px solid transparent;border-right:30px solid transparent;border-top:45px solid gray;}
.c0{background-color:#28a745;}.c1{background-color:#ffc107;color:#333;}.c2{background-color:#dc3545;}.c3{background-color:#6c757d;}
.tri.c0{border-top-color:#28a745;}.tri.c1{border-top-color:#ffc107;}.tri.c2{border-top-color:#dc3545;}.tri.c3{border-top-color:#6c757d;}
.label{font-size:11px;color:#333;}
</style>
<div class="container" id="box"></div>
<script>
require(['splunkjs/mvc','splunkjs/mvc/simplexml/ready!'],function(mvc){
var sm=mvc.Components.get("mySearch");
sm.data("results").on("data",function(){
if(this.hasData()){
var r=this.data().rows,f=this.data().fields,box=document.getElementById('box');
box.innerHTML='';
var shapes=['rect','circle','bar','tri'];
r.forEach(function(row,i){
var n=row[f.indexOf('name')],s=row[f.indexOf('status')],c=parseInt(row[f.indexOf('code')]);
var cls='c'+c,sh=shapes[i%4];
var html='<div class="item">';
if(sh==='tri'){html+='<div class="tri '+cls+'"></div>';}
else{html+='<div class="'+sh+' '+cls+'">'+s+'</div>';}
html+='<div class="label">'+n+'</div></div>';
box.innerHTML+=html;
});
}
});
});
</script>
</html>
</panel>
</row>
</dashboard>
🎉 まとめ
覚えておくべきポイント
カテゴリ ポイント 四角 border-radius: 5px で少し丸く 丸 border-radius: 50% + 幅=高さ 棒 幅 > 高さ の四角形 三角 border のトリックで作成 色変更 CSSクラスを動的に付与 配置 Flexbox / Grid / 絶対位置
次のステップ
リアルデータに接続: index=your_index でサーチを変更
リアルタイム更新: <refresh> タグを追加
クリックイベント: 図形クリックでドリルダウン
アニメーション: 点滅や拡大縮小を追加
📖 参考リンク
🔷 Part 1: XML構造の解説
1-1. ダッシュボード宣言
<dashboard>
↑ 【1行目】ダッシュボードの開始タグ
- Splunkクラシックダッシュボードの最上位要素
- すべての内容はこのタグの中に書く
- HTMLでいう <html> タグのような役割
<label>ステータス連動図形ダッシュボード</label>
↑ 【2行目】ダッシュボードのタイトル
- 画面上部に表示される名前
- ブラウザのタブにも表示される
- 日本語OK
1-2. サーチ定義(データ取得部分)
<search id="status_search">
↑ 【3行目】サーチブロックの開始
- id="status_search" → このサーチに名前を付ける
- JavaScriptから mvc.Components.get("status_search") で参照できる
- ★重要★ idは一意(ユニーク)でなければならない
<query>
↑ 【4行目】SPLクエリの開始タグ
- この中にSPL(Search Processing Language)を書く
🔷 Part 2: SPLクエリの解説
| makeresults count=4
↑ 【5行目】空のデータを4行生成
┌─ | ──────────────────────────────────────────────────────┐
│ パイプ記号。SPLのコマンドを繋げる │
│ 「前のコマンドの結果を、次のコマンドに渡す」という意味 │
└───────────────────────────────────────────────────────────┘
┌─ makeresults ─────────────────────────────────────────────┐
│ テスト用のダミーデータを生成するコマンド │
│ 実際のインデックスがなくても動作確認できる │
└───────────────────────────────────────────────────────────┘
┌─ count=4 ─────────────────────────────────────────────────┐
│ 生成する行数を指定 │
│ この場合、4行のデータが作られる │
└───────────────────────────────────────────────────────────┘
【この時点のデータ】
┌──────────────────┐
│ _time │
├──────────────────┤
│ 2024-01-01 00:00 │ ← 自動で現在時刻が入る
│ 2024-01-01 00:00 │
│ 2024-01-01 00:00 │
│ 2024-01-01 00:00 │
└──────────────────┘
| streamstats count as id
↑ 【6行目】各行に連番を振る
┌─ streamstats ─────────────────────────────────────────────┐
│ 「流れるように」統計を計算するコマンド │
│ 各行ごとに、その時点までの累計を計算 │
└───────────────────────────────────────────────────────────┘
┌─ count ───────────────────────────────────────────────────┐
│ 行数をカウントする関数 │
│ 1行目→1、2行目→2、3行目→3... と増えていく │
└───────────────────────────────────────────────────────────┘
┌─ as id ───────────────────────────────────────────────────┐
│ カウント結果を「id」という名前のフィールドに保存 │
│ as = 「〜として」という意味 │
└───────────────────────────────────────────────────────────┘
【この時点のデータ】
┌──────────────────┬─────┐
│ _time │ id │
├──────────────────┼─────┤
│ 2024-01-01 00:00 │ 1 │ ← 連番が振られた!
│ 2024-01-01 00:00 │ 2 │
│ 2024-01-01 00:00 │ 3 │
│ 2024-01-01 00:00 │ 4 │
└──────────────────┴─────┘
| eval device_name = case(
id==1, "サーバーA",
id==2, "サーバーB",
id==3, "ネットワーク機器C",
id==4, "データベースD"
)
↑ 【7〜12行目】デバイス名を条件分岐で設定
┌─ eval ────────────────────────────────────────────────────┐
│ 「evaluate(評価する)」の略 │
│ 新しいフィールドを作成したり、値を計算したりする │
│ ★超重要★ Splunkで最もよく使うコマンド │
└───────────────────────────────────────────────────────────┘
┌─ device_name = ───────────────────────────────────────────┐
│ 「device_name」という新しいフィールドを作成 │
│ = の右側の値が代入される │
└───────────────────────────────────────────────────────────┘
┌─ case(条件1, 値1, 条件2, 値2, ...) ───────────────────────┐
│ 条件分岐を行う関数 │
│ 書き方: case(条件, その時の値, 条件, その時の値, ...) │
│ │
│ id==1 → "サーバーA" │
│ id==2 → "サーバーB" │
│ id==3 → "ネットワーク機器C" │
│ id==4 → "データベースD" │
│ │
│ ★注意★ == は「等しい」の比較演算子(=は代入) │
└───────────────────────────────────────────────────────────┘
【この時点のデータ】
┌─────┬─────────────────────┐
│ id │ device_name │
├─────┼─────────────────────┤
│ 1 │ サーバーA │
│ 2 │ サーバーB │
│ 3 │ ネットワーク機器C │
│ 4 │ データベースD │
└─────┴─────────────────────┘
| eval status = case(
id==1, "正常",
id==2, "警告",
id==3, "異常",
id==4, "停止"
)
↑ 【13〜18行目】ステータスを設定
【この時点のデータ】
┌─────┬─────────────────────┬─────────┐
│ id │ device_name │ status │
├─────┼─────────────────────┼─────────┤
│ 1 │ サーバーA │ 正常 │
│ 2 │ サーバーB │ 警告 │
│ 3 │ ネットワーク機器C │ 異常 │
│ 4 │ データベースD │ 停止 │
└─────┴─────────────────────┴─────────┘
| eval status_code = case(
status=="正常", 0,
status=="警告", 1,
status=="異常", 2,
status=="停止", 3
)
↑ 【19〜24行目】ステータスを数値コードに変換
┌─ なぜ数値コードが必要? ──────────────────────────────────┐
│ JavaScriptのswitch文で使いやすくするため │
│ 文字列より数値の方が比較が高速 │
│ 0=正常, 1=警告, 2=異常, 3=停止 という対応表 │
└───────────────────────────────────────────────────────────┘
【この時点のデータ】
┌─────┬─────────────────────┬─────────┬─────────────┐
│ id │ device_name │ status │ status_code │
├─────┼─────────────────────┼─────────┼─────────────┤
│ 1 │ サーバーA │ 正常 │ 0 │
│ 2 │ サーバーB │ 警告 │ 1 │
│ 3 │ ネットワーク機器C │ 異常 │ 2 │
│ 4 │ データベースD │ 停止 │ 3 │
└─────┴─────────────────────┴─────────┴─────────────┘
| table device_name, status, status_code
↑ 【25行目】表示するフィールドを選択
┌─ table ───────────────────────────────────────────────────┐
│ 指定したフィールドだけを表示する │
│ カンマ区切りで複数指定可能 │
│ 指定しないフィールド(id, _timeなど)は除外される │
└───────────────────────────────────────────────────────────┘
【最終出力データ】
┌─────────────────────┬─────────┬─────────────┐
│ device_name │ status │ status_code │
├─────────────────────┼─────────┼─────────────┤
│ サーバーA │ 正常 │ 0 │
│ サーバーB │ 警告 │ 1 │
│ ネットワーク機器C │ 異常 │ 2 │
│ データベースD │ 停止 │ 3 │
└─────────────────────┴─────────┴─────────────┘
</query>
↑ 【26行目】SPLクエリの終了タグ
<earliest>-24h@h</earliest>
↑ 【27行目】検索期間の開始時刻
┌─ -24h ────────────────────────────────────────────────────┐
│ 「24時間前」という意味 │
│ - = マイナス(過去方向) │
│ 24h = 24時間 │
└───────────────────────────────────────────────────────────┘
┌─ @h ──────────────────────────────────────────────────────┐
│ 「時間の境界に丸める」という意味 │
│ 例: 今が14:35なら → 14:00に丸められる │
│ @d なら日の境界(00:00)に丸められる │
└───────────────────────────────────────────────────────────┘
<latest>now</latest>
↑ 【28行目】検索期間の終了時刻
┌─ now ─────────────────────────────────────────────────────┐
│ 「現在時刻」という意味 │
│ つまり「24時間前〜今まで」のデータを検索 │
└───────────────────────────────────────────────────────────┘
</search>
↑ 【29行目】サーチブロックの終了タグ
🔷 Part 3: HTMLパネル構造
<row>
↑ 【30行目】行の開始
┌─────────────────────────────────────────────────────────┐
│ Splunkダッシュボードは「行 → パネル」の構造 │
│ │
│ <row> ← 横方向のコンテナ │
│ <panel>...</panel> ← 1つ目のパネル │
│ <panel>...</panel> ← 2つ目のパネル(横並び) │
│ </row> │
└─────────────────────────────────────────────────────────┘
<panel>
↑ 【31行目】パネルの開始
- パネル = コンテンツを表示する箱
- 1つの<row>に複数の<panel>を入れると横並びになる
<title>ステータス連動図形</title>
↑ 【32行目】パネルのタイトル
- パネル上部に表示される見出し
<html>
↑ 【33行目】HTMLパネルの開始
- この中に自由にHTML/CSS/JavaScriptを書ける
- ★重要★ クラシックダッシュボード最大の自由度ポイント
🔷 Part 4: CSS(スタイル)の解説
<style>
↑ 【34行目】スタイル定義の開始
- CSSを書くためのタグ
- <style>〜</style>の中にCSSルールを記述
4-1. コンテナのスタイル
/* ===== コンテナ(図形を並べる箱) ===== */
.shapes-container {
↑ 【35〜36行目】コンテナクラスの定義開始
┌─ /* ... */ ───────────────────────────────────────────────┐
│ CSSのコメント │
│ コードの説明を書くために使う(実行には影響しない) │
└───────────────────────────────────────────────────────────┘
┌─ .shapes-container ───────────────────────────────────────┐
│ クラスセレクタ │
│ . = クラスを指定する記号 │
│ shapes-container = クラス名 │
│ HTML側で class="shapes-container" と書いた要素に適用 │
└───────────────────────────────────────────────────────────┘
┌─ { ────────────────────────────────────────────────────────┐
│ CSSルールの開始 │
│ この中にプロパティと値を書く │
└───────────────────────────────────────────────────────────┘
/* 横並びにする */
display: flex;
↑ 【37〜38行目】Flexboxを有効化
┌─ display: flex; ──────────────────────────────────────────┐
│ Flexbox(フレックスボックス)レイアウトを有効にする │
│ │
│ 【Flexboxとは?】 │
│ 要素を柔軟に配置できるCSSの仕組み │
│ │
│ display: flex なし: display: flex あり: │
│ ┌─────┐ ┌─────┬─────┬─────┐ │
│ │ A │ │ A │ B │ C │ ← 横並び │
│ ├─────┤ └─────┴─────┴─────┘ │
│ │ B │ ← 縦並び │
│ ├─────┤ │
│ │ C │ │
│ └─────┘ │
└───────────────────────────────────────────────────────────┘
/* 図形間の余白 */
gap: 20px;
↑ 【39〜40行目】要素間の余白
┌─ gap: 20px; ──────────────────────────────────────────────┐
│ Flexbox/Grid内の要素間の余白を設定 │
│ │
│ gap: 20px の効果: │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ A │←20px→│ B │←20px→│ C │ │
│ └─────┘ └─────┘ └─────┘ │
│ │
│ ★便利★ marginより簡単に余白を統一できる │
└───────────────────────────────────────────────────────────┘
/* 内側の余白 */
padding: 20px;
↑ 【41〜42行目】内側の余白
┌─ padding: 20px; ──────────────────────────────────────────┐
│ 要素の内側(枠線と内容の間)の余白 │
│ │
│ ┌─────────────────────────────┐ │
│ │ ← 20px padding → │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ コンテンツ │ │ │
│ │ └─────────────────────┘ │ │
│ │ ↑ 20px padding │ │
│ └─────────────────────────────┘ │
│ │
│ 【margin vs padding】 │
│ margin = 外側の余白(要素同士の間) │
│ padding = 内側の余白(枠線と内容の間) │
└───────────────────────────────────────────────────────────┘
/* 折り返しを許可 */
flex-wrap: wrap;
↑ 【43〜44行目】折り返し設定
┌─ flex-wrap: wrap; ────────────────────────────────────────┐
│ 要素が画面幅を超えたら折り返す │
│ │
│ flex-wrap: nowrap(デフォルト): │
│ ┌────────────────────────────────────────┐ │
│ │ A │ B │ C │ D │ E │ F │→ はみ出る → │ │
│ └────────────────────────────────────────┘ │
│ │
│ flex-wrap: wrap: │
│ ┌────────────────────────┐ │
│ │ A │ B │ C │ D │ │ │
│ │ E │ F │ │ ← 折り返される! │
│ └────────────────────────┘ │
└───────────────────────────────────────────────────────────┘
}
↑ 【45行目】CSSルールの終了
4-2. 各図形アイテムのスタイル
/* ===== 各図形の共通スタイル ===== */
.shape-item {
↑ 【46〜47行目】図形アイテムクラスの定義開始
- 各図形(四角、丸など)を包むラッパー要素のスタイル
/* 縦並びにする(図形 + ラベル) */
display: flex;
flex-direction: column;
↑ 【48〜50行目】縦並びのFlexbox
┌─ flex-direction: column; ─────────────────────────────────┐
│ Flexboxの並び方向を「縦」に変更 │
│ │
│ flex-direction: row(デフォルト): │
│ ┌─────┬─────┬─────┐ │
│ │図形 │ラベル│ステ │ ← 横並び │
│ └─────┴─────┴─────┘ │
│ │
│ flex-direction: column: │
│ ┌───────────┐ │
│ │ 図形 │ │
│ ├───────────┤ │
│ │ ラベル │ ← 縦並び │
│ ├───────────┤ │
│ │ ステータス │ │
│ └───────────┘ │
└───────────────────────────────────────────────────────────┘
/* 中央揃え */
align-items: center;
↑ 【51〜52行目】要素を中央揃え
┌─ align-items: center; ────────────────────────────────────┐
│ Flexboxの交差軸方向(縦並びなら横方向)で中央揃え │
│ │
│ align-items: flex-start: align-items: center: │
│ ┌───────────┐ ┌───────────┐ │
│ │■ │ │ ■ │ │
│ │サーバーA │ │ サーバーA │ │
│ │正常 │ │ 正常 │ │
│ └───────────┘ └───────────┘ │
│ ↑左寄せ ↑中央揃え │
└───────────────────────────────────────────────────────────┘
/* 図形間の余白 */
gap: 8px;
}
↑ 【53〜55行目】図形とラベルの間の余白
- 8px = 適度な間隔(狭すぎず広すぎず)
4-3. 四角形のスタイル
/* ===== 四角形 ===== */
.rectangle {
width: 100px;
height: 60px;
↑ 【56〜59行目】四角形のサイズ
┌─ width: 100px; ───────────────────────────────────────────┐
│ 横幅を100ピクセルに設定 │
│ px = ピクセル(画面上の点の数) │
└───────────────────────────────────────────────────────────┘
┌─ height: 60px; ───────────────────────────────────────────┐
│ 高さを60ピクセルに設定 │
│ 横長の四角形になる(100 > 60) │
└───────────────────────────────────────────────────────────┘
【結果イメージ】
┌────────────────────┐
│ │ ← 100px × 60px
│ │
└────────────────────┘
background-color: #808080 ;
↑ 【60行目】背景色(初期値)
┌─ #808080 ─────────────────────────────────────────────────┐
│ 16進数カラーコード(グレー) │
│ │
│ #RRGGBB の形式: │
│ RR = 赤の強さ (00〜FF) │
│ GG = 緑の強さ (00〜FF) │
│ BB = 青の強さ (00〜FF) │
│ │
│ 例: #808080 = 赤128 + 緑128 + 青128 = グレー │
│ 例: #FF0000 = 赤255 + 緑0 + 青0 = 真っ赤 │
│ 例: #28a745 = 緑色(正常ステータス用) │
└───────────────────────────────────────────────────────────┘
border-radius: 5px;
↑ 【61行目】角の丸み
┌─ border-radius: 5px; ─────────────────────────────────────┐
│ 角を丸くする(値が大きいほど丸くなる) │
│ │
│ 0px: 5px: 20px: 50%: │
│ ┌────┐ ╭────╮ ╭────╮ (●) │
│ │ │ │ │ │ │ 円になる │
│ └────┘ ╰────╯ ╰────╯ │
│ 角張り 少し丸い かなり丸い │
└───────────────────────────────────────────────────────────┘
border: 2px solid #333 ;
↑ 【62行目】枠線
┌─ border: 2px solid #333 ; ─────────────────────────────────┐
│ 枠線を一括指定(太さ、スタイル、色) │
│ │
│ 2px = 枠線の太さ │
│ solid = 実線(他に dashed=破線, dotted=点線) │
│ #333 = 枠線の色(濃いグレー) │
│ │
│ 【枠線スタイルの例】 │
│ solid: ──────── │
│ dashed: - - - - - │
│ dotted: ・・・・・ │
└───────────────────────────────────────────────────────────┘
display: flex;
justify-content: center;
align-items: center;
↑ 【63〜65行目】テキストを中央揃え
┌─ justify-content: center; ────────────────────────────────┐
│ 主軸方向(横並びなら横方向)で中央揃え │
└───────────────────────────────────────────────────────────┘
┌─ align-items: center; ────────────────────────────────────┐
│ 交差軸方向(横並びなら縦方向)で中央揃え │
└───────────────────────────────────────────────────────────┘
【組み合わせ効果】
┌─────────────────────┐
│ │
│ 正常 │ ← 完全に中央に配置
│ │
└─────────────────────┘
color: white;
font-weight: bold;
font-size: 14px;
↑ 【66〜68行目】文字スタイル
┌─ color: white; ───────────────────────────────────────────┐
│ 文字色を白に設定 │
│ 背景色が濃い色なので、白文字で見やすくする │
└───────────────────────────────────────────────────────────┘
┌─ font-weight: bold; ──────────────────────────────────────┐
│ 文字を太字にする │
│ 他の値: normal(普通), lighter(細い), 100〜900 │
└───────────────────────────────────────────────────────────┘
┌─ font-size: 14px; ────────────────────────────────────────┐
│ 文字サイズを14ピクセルに設定 │
│ ブラウザのデフォルトは約16px │
└───────────────────────────────────────────────────────────┘
/* アニメーション(色が滑らかに変化) */
transition: background-color 0.3s ease;
}
↑ 【69〜71行目】アニメーション効果
┌─ transition: background-color 0.3s ease; ─────────────────┐
│ プロパティが変化するときのアニメーションを設定 │
│ │
│ background-color = 変化を監視するプロパティ │
│ 0.3s = 変化にかかる時間(0.3秒) │
│ ease = 変化の速度曲線(最初と最後がゆっくり) │
│ │
│ 【効果】 │
│ JavaScriptで色を変えると、パッと変わらずに │
│ 0.3秒かけて滑らかに変化する! │
│ │
│ グレー ───────→ 緑 │
│ (0.3秒でじんわり変化) │
└───────────────────────────────────────────────────────────┘
4-4. 丸のスタイル
/* ===== 丸 ===== */
.circle {
width: 70px;
height: 70px;
↑ 【72〜75行目】丸のサイズ
┌─ ★重要★ 丸を作るコツ ────────────────────────────────────┐
│ width と height を同じ値にする! │
│ │
│ width: 70px ┬ │
│ height: 70px ┘ → 正方形になる │
│ │
│ この正方形に border-radius: 50% を適用すると │
│ 完全な円になる! │
└───────────────────────────────────────────────────────────┘
background-color: #808080 ;
border-radius: 50%;
↑ 【76〜77行目】丸を作る魔法
┌─ border-radius: 50%; ─────────────────────────────────────┐
│ 角の丸みを50%に設定 │
│ │
│ 【50%の意味】 │
│ 「幅と高さの半分の大きさで角を丸める」 │
│ │
│ 70px × 70px の正方形で 50% = 35px │
│ 4つの角すべてが35pxで丸まる → 完全な円! │
│ │
│ border-radius: 0% border-radius: 50% │
│ ┌────┐ ╭────╮ │
│ │ │ │ │ │
│ │ │ → │ │ → ● │
│ │ │ │ │ │
│ └────┘ ╰────╯ │
└───────────────────────────────────────────────────────────┘
border: 2px solid #333 ;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
font-size: 12px;
transition: background-color 0.3s ease;
}
↑ 【78〜86行目】その他のスタイル
- 四角形とほぼ同じ(文字サイズだけ12pxと少し小さい)
4-5. 棒のスタイル
/* ===== 棒 ===== */
.bar {
width: 120px;
height: 25px;
↑ 【87〜90行目】棒のサイズ
┌─ 横長の形状 ──────────────────────────────────────────────┐
│ width: 120px (横幅) │
│ height: 25px (高さ) │
│ │
│ 横幅 > 高さ → 横長の棒になる │
│ │
│ ┌────────────────────────────────────┐ │
│ │ 棒 │ ← 120px × 25px │
│ └────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────┘
background-color: #808080 ;
border-radius: 3px;
border: 1px solid #333 ;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
font-size: 11px;
transition: background-color 0.3s ease;
}
↑ 【91〜101行目】その他のスタイル
- border-radius: 3px → 角をほんの少しだけ丸める
- font-size: 11px → 棒は細いので文字も小さめ
4-6. 三角形のスタイル
/* ===== 三角形(下向き)===== */
.triangle {
width: 0;
height: 0;
↑ 【102〜105行目】三角形のベース
┌─ ★超重要★ なぜ幅と高さが0? ─────────────────────────────┐
│ CSSの三角形は「枠線(border)のトリック」で作る │
│ │
│ 通常、枠線は四角形の周りに描かれるが、 │
│ 幅と高さを0にすると、枠線だけが残る! │
│ │
│ そして、3辺を透明、1辺に色を付けると │
│ 三角形が現れる! │
└───────────────────────────────────────────────────────────┘
border-left: 35px solid transparent;
border-right: 35px solid transparent;
↑ 【106〜107行目】左右の辺(透明)
┌─ transparent ─────────────────────────────────────────────┐
│ 「透明」という意味 │
│ 色は付くが、見えない状態 │
│ │
│ 左右に35pxずつの透明な枠線 → 三角形の底辺幅が70pxに │
└───────────────────────────────────────────────────────────┘
border-top: 50px solid #808080 ;
↑ 【108行目】上辺(色を付ける)
┌─ border-top: 50px solid #808080 ; ─────────────────────────┐
│ 上の枠線に色を付ける → 下向き三角形 ▼ が完成! │
│ │
│ 【三角形の仕組み図解】 │
│ │
│ 幅0、高さ0の点を中心に、枠線が放射状に描かれる │
│ │
│ border-top(色付き) │
│ ▼ │
│ ╱ ╲ │
│ ╱ ● ╲ ← 幅0、高さ0の中心点 │
│ ╱ ╲ │
│ 透明 透明 │
│ (border-left) (border-right) │
│ │
│ 結果: 色付きの部分だけが見える → ▼ │
└───────────────────────────────────────────────────────────┘
transition: border-top-color 0.3s ease;
}
↑ 【109〜110行目】三角形のアニメーション
┌─ border-top-color ────────────────────────────────────────┐
│ 三角形は background-color ではなく │
│ border-top-color で色を変える! │
│ │
│ ★注意★ 四角や丸とは違うプロパティ名 │
└───────────────────────────────────────────────────────────┘
4-7. ラベルのスタイル
/* ===== ラベル(機器名) ===== */
.device-label {
font-size: 12px;
color: #333 ;
font-weight: bold;
}
↑ 【111〜116行目】機器名ラベル
- font-size: 12px → 小さめの文字
- color: #333 → 濃いグレー(黒に近い)
- font-weight: bold → 太字で目立たせる
/* ===== ステータスラベル ===== */
.status-label {
font-size: 11px;
color: #666 ;
}
↑ 【117〜121行目】ステータスラベル
- font-size: 11px → さらに小さい
- color: #666 → 中間グレー(サブ情報なので控えめに)
4-8. ステータス別の色クラス
/* ===== 色の定義(ステータス別) ===== */
.status-normal { background-color: #28a745 ; }
.status-warning { background-color: #ffc107 ; }
.status-error { background-color: #dc3545 ; }
.status-stop { background-color: #6c757d ; }
↑ 【122〜126行目】ステータス別の背景色
┌─ 色クラスの対応表 ────────────────────────────────────────┐
│ │
│ クラス名 │ カラーコード │ 色 │ 用途 │
│ ─────────────────┼──────────────┼──────┼────────────────│
│ .status-normal │ #28a745 │ 緑 │ 正常 │
│ .status-warning │ #ffc107 │ 黄 │ 警告 │
│ .status-error │ #dc3545 │ 赤 │ 異常 │
│ .status-stop │ #6c757d │ 灰 │ 停止 │
│ │
│ これらの色はBootstrapの標準色と同じ │
│ (多くの人が見慣れている色) │
└───────────────────────────────────────────────────────────┘
/* 三角形用(border-topで色を指定) */
.triangle.status-normal { border-top-color: #28a745 ; }
.triangle.status-warning { border-top-color: #ffc107 ; }
.triangle.status-error { border-top-color: #dc3545 ; }
.triangle.status-stop { border-top-color: #6c757d ; }
↑ 【127〜131行目】三角形専用の色クラス
┌─ .triangle.status-normal ─────────────────────────────────┐
│ 複合セレクタ(両方のクラスを持つ要素に適用) │
│ │
│ class="triangle status-normal" を持つ要素に適用 │
│ │
│ ★なぜ別に定義?★ │
│ 三角形は background-color ではなく │
│ border-top-color で色を変える必要があるため │
└───────────────────────────────────────────────────────────┘
</style>
↑ 【132行目】スタイル定義の終了
🔷 Part 5: HTML本体の解説
<!-- 図形を配置するコンテナ -->
<div class="shapes-container" id="shapesContainer">
<!-- JavaScriptで動的に生成される -->
</div>
↑ 【133〜136行目】図形を入れる箱
┌─ <div> ───────────────────────────────────────────────────┐
│ 汎用のコンテナ要素 │
│ 中にコンテンツを入れるための箱 │
└───────────────────────────────────────────────────────────┘
┌─ class="shapes-container" ────────────────────────────────┐
│ CSSのスタイルを適用するためのクラス名 │
│ 上で定義した .shapes-container のスタイルが適用される │
└───────────────────────────────────────────────────────────┘
┌─ id="shapesContainer" ────────────────────────────────────┐
│ JavaScriptから getElementById() で取得するためのID │
│ ★重要★ idは1ページに1つだけ(一意でなければならない) │
└───────────────────────────────────────────────────────────┘
【最初は空っぽ → JavaScriptで図形が追加される】
初期状態: JavaScript実行後:
┌─────────────────────┐ ┌─────────────────────────────┐
│ │ │ ■ ● ▬ ▼ │
│ (空っぽ) │ → │ A B C D │
│ │ │ 正常 警告 異常 停止 │
└─────────────────────┘ └─────────────────────────────┘
🔷 Part 6: JavaScript(Splunk連携)の解説
<script>
↑ 【137行目】JavaScriptコードの開始
6-1. モジュール読み込み
// ===== Splunkのデータを取得してUIに反映 =====
require([
'splunkjs/mvc',
'splunkjs/mvc/searchmanager',
'splunkjs/mvc/simplexml/ready!'
], function(mvc) {
↑ 【138〜143行目】Splunk用モジュールの読み込み
┌─ require([...], function) ────────────────────────────────┐
│ AMD(Asynchronous Module Definition)形式のモジュール読込│
│ 必要なライブラリが読み込まれてから、function内を実行 │
│ │
│ 【なぜrequireを使う?】 │
│ Splunkの機能は別ファイルに分かれている │
│ 必要な部分だけを読み込むことで、効率的に動作 │
└───────────────────────────────────────────────────────────┘
┌─ 'splunkjs/mvc' ──────────────────────────────────────────┐
│ SplunkのMVC(Model-View-Controller)フレームワーク │
│ ダッシュボードのコンポーネントを操作するために必要 │
│ 例: サーチ結果の取得、パネルの操作など │
└───────────────────────────────────────────────────────────┘
┌─ 'splunkjs/mvc/searchmanager' ────────────────────────────┐
│ サーチを管理するモジュール │
│ SPLクエリの実行や結果取得に使う │
│ (実際には今回は直接使わないが、依存関係として必要) │
└───────────────────────────────────────────────────────────┘
┌─ 'splunkjs/mvc/simplexml/ready!' ─────────────────────────┐
│ ダッシュボードの準備完了を待つ特別なモジュール │
│ 末尾の「!」は「待ってから実行」という意味 │
│ │
│ 【なぜ必要?】 │
│ ダッシュボードの読み込みが完了する前に │
│ JavaScriptが動くと、エラーになる可能性がある │
└───────────────────────────────────────────────────────────┘
┌─ function(mvc) ───────────────────────────────────────────┐
│ 読み込んだモジュールを「mvc」という名前で受け取る │
│ この関数の中でSplunkの機能を使える │
└───────────────────────────────────────────────────────────┘
6-2. サーチマネージャーの取得
// サーチマネージャーを取得
// "status_search" は <search id="status_search"> と対応
var searchManager = mvc.Components.get("status_search");
↑ 【144〜146行目】サーチへの参照を取得
┌─ var ─────────────────────────────────────────────────────┐
│ 変数を宣言するキーワード │
│ searchManager という名前の変数を作成 │
└───────────────────────────────────────────────────────────┘
┌─ mvc.Components.get("status_search") ─────────────────────┐
│ ダッシュボード上のコンポーネントを名前で取得 │
│ │
│ mvc.Components = Splunkのコンポーネント管理オブジェクト │
│ .get("status_search") = "status_search"という名前のもの │
│ │
│ 【対応関係】 │
│ XML側: <search id="status_search"> │
│ JS側: mvc.Components.get("status_search") │
│ ↑ 同じ名前! │
│ │
│ ★注意★ idが一致しないとエラーになる │
└───────────────────────────────────────────────────────────┘
6-3. 結果データの取得
// サーチ結果を取得
var results = searchManager.data("results");
↑ 【147〜148行目】結果データへの参照を取得
┌─ searchManager.data("results") ───────────────────────────┐
│ サーチの結果データを取得 │
│ │
│ "results" = 完了した最終結果 │
│ "preview" = 途中経過の結果(リアルタイム用) │
│ │
│ 【resultsオブジェクトの機能】 │
│ .hasData() → データがあるかチェック │
│ .data() → 実際のデータを取得 │
│ .on("data") → データ更新時のイベント登録 │
└───────────────────────────────────────────────────────────┘
6-4. イベントリスナーの設定
// データが変更されたら実行
results.on("data", function() {
↑ 【149〜150行目】データ更新時の処理を登録
┌─ .on("data", function() {...}) ───────────────────────────┐
│ イベントリスナーの登録 │
│ │
│ "data" = 「データが更新された」というイベント名 │
│ function() = そのイベントが発生したら実行する関数 │
│ │
│ 【いつ発火する?】 │
│ ・ページ読み込み時(最初のサーチ完了時) │
│ ・自動更新時(<refresh>タグがある場合) │
│ ・手動でサーチを再実行した時 │
│ │
│ 【イベント駆動の流れ】 │
│ SPLサーチ実行 → 結果取得 → "data"イベント発火 │
│ → function()が実行される │
└───────────────────────────────────────────────────────────┘
6-5. データ存在チェック
// 結果が存在するかチェック
if (results.hasData()) {
↑ 【151〜152行目】データがあるか確認
┌─ if (results.hasData()) ──────────────────────────────────┐
│ 条件分岐: データがある場合のみ処理を実行 │
│ │
│ hasData() = true/false を返すメソッド │
│ ・サーチ結果があれば true │
│ ・結果が空、またはエラーなら false │
│ │
│ 【なぜチェックが必要?】 │
│ データがない状態で処理すると、エラーになる │
│ 例: 空のデータに対して .forEach() を実行 → エラー │
└───────────────────────────────────────────────────────────┘
6-6. 結果データの取り出し
// 結果をJSON形式で取得
var rows = results.data().rows;
var fields = results.data().fields;
↑ 【153〜155行目】行データとフィールド名を取得
┌─ results.data() ──────────────────────────────────────────┐
│ サーチ結果のデータオブジェクトを取得 │
│ │
│ 返り値の構造: │
│ { │
│ rows: [...], // 行データの2次元配列 │
│ fields: [...] // フィールド名の配列 │
│ } │
└───────────────────────────────────────────────────────────┘
┌─ .rows ───────────────────────────────────────────────────┐
│ 行データの2次元配列 │
│ │
│ 例: │
│ [ │
│ ["サーバーA", "正常", "0"], // 1行目 │
│ ["サーバーB", "警告", "1"], // 2行目 │
│ ["ネットワーク機器C", "異常", "2"], │
│ ["データベースD", "停止", "3"] │
│ ] │
└───────────────────────────────────────────────────────────┘
┌─ .fields ─────────────────────────────────────────────────┐
│ フィールド名(カラム名)の配列 │
│ │
│ 例: │
│ ["device_name", "status", "status_code"] │
│ │
│ インデックス: 0 1 2 │
│ ↑ ↑ ↑ │
│ 後で使う: fields.indexOf("status") → 1 │
└───────────────────────────────────────────────────────────┘
6-7. コンテナの取得と初期化
// コンテナを取得
var container = document.getElementById('shapesContainer');
// コンテナを空にする(再描画のため)
container.innerHTML = '';
↑ 【156〜160行目】描画先の準備
┌─ document.getElementById('shapesContainer') ──────────────┐
│ HTML要素をIDで取得 │
│ │
│ document = ウェブページ全体を表すオブジェクト │
│ getElementById() = 指定IDの要素を探して返す │
│ 'shapesContainer' = 探すID名 │
│ │
│ 【対応関係】 │
│ HTML側: <div id="shapesContainer"> │
│ JS側: document.getElementById('shapesContainer') │
└───────────────────────────────────────────────────────────┘
┌─ container.innerHTML = '' ────────────────────────────────┐
│ コンテナの中身を空にする │
│ │
│ innerHTML = 要素の中のHTMLを取得/設定するプロパティ │
│ '' = 空文字列(何もない状態) │
│ │
│ 【なぜ空にする?】 │
│ データ更新のたびに図形を追加すると、 │
│ 前の図形が残ったまま新しい図形が追加されてしまう │
│ │
│ 空にしない場合: │
│ 1回目: ■ ● ▬ ▼ │
│ 2回目: ■ ● ▬ ▼ ■ ● ▬ ▼ ← 倍に増える! │
│ │
│ 空にする場合: │
│ 1回目: ■ ● ▬ ▼ │
│ 2回目: ■ ● ▬ ▼ ← 正しく更新 │
└───────────────────────────────────────────────────────────┘
6-8. データのループ処理
// 各行のデータをループ処理
rows.forEach(function(row, index) {
↑ 【161〜162行目】全行を1つずつ処理
┌─ .forEach(function(row, index) {...}) ────────────────────┐
│ 配列の各要素に対して関数を実行 │
│ │
│ rows.forEach() = rowsの各行に対してループ │
│ │
│ function(row, index) の引数: │
│ ・row = 現在処理中の行(配列) │
│ ・index = 現在のインデックス(0, 1, 2, 3...) │
│ │
│ 【処理の流れ】 │
│ 1回目: row=["サーバーA","正常","0"], index=0 │
│ 2回目: row=["サーバーB","警告","1"], index=1 │
│ 3回目: row=["ネットワーク機器C","異常","2"], index=2 │
│ 4回目: row=["データベースD","停止","3"], index=3 │
└───────────────────────────────────────────────────────────┘
6-9. フィールドのインデックス取得
// フィールド名からインデックスを取得
var deviceIndex = fields.indexOf('device_name');
var statusIndex = fields.indexOf('status');
var codeIndex = fields.indexOf('status_code');
↑ 【163〜166行目】各フィールドの位置を特定
┌─ fields.indexOf('device_name') ───────────────────────────┐
│ 配列の中から指定した値の位置(インデックス)を探す │
│ │
│ fields = ["device_name", "status", "status_code"] │
│ ↑0番目 ↑1番目 ↑2番目 │
│ │
│ fields.indexOf('device_name') → 0 │
│ fields.indexOf('status') → 1 │
│ fields.indexOf('status_code') → 2 │
│ │
│ 【なぜこの処理が必要?】 │
│ フィールドの順番は保証されていない │
│ SPLの書き方によって順番が変わる可能性がある │
│ インデックスで直接アクセスすると危険 │
│ │
│ 危険な書き方: │
│ var deviceName = row[0]; // 0番目がdevice_nameとは限らない│
│ │
│ 安全な書き方: │
│ var deviceIndex = fields.indexOf('device_name'); │
│ var deviceName = row[deviceIndex]; // 確実に正しい値 │
└───────────────────────────────────────────────────────────┘
6-10. 値の取得
// 値を取得
var deviceName = row[deviceIndex];
var status = row[statusIndex];
var statusCode = parseInt(row[codeIndex]);
↑ 【167〜170行目】各フィールドの値を取り出す
┌─ row[deviceIndex] ────────────────────────────────────────┐
│ 配列から指定位置の値を取得 │
│ │
│ 例: row = ["サーバーA", "正常", "0"] │
│ deviceIndex = 0 │
│ row[deviceIndex] = row[0] = "サーバーA" │
└───────────────────────────────────────────────────────────┘
┌─ parseInt(row[codeIndex]) ────────────────────────────────┐
│ 文字列を整数に変換 │
│ │
│ row[codeIndex] = "0" ← 文字列(String型) │
│ parseInt("0") = 0 ← 数値(Number型) │
│ │
│ 【なぜ変換が必要?】 │
│ Splunkのサーチ結果は全て文字列として返される │
│ switch文で数値と比較するために変換が必要 │
│ │
│ 文字列のまま比較すると: │
│ "0" === 0 → false ← 型が違うので一致しない! │
│ │
│ 数値に変換すると: │
│ 0 === 0 → true ← 正しく比較できる │
└───────────────────────────────────────────────────────────┘
6-11. ステータスに応じたクラス決定
// ステータスコードに応じたCSSクラスを決定
var statusClass = '';
switch(statusCode) {
case 0: statusClass = 'status-normal'; break;
case 1: statusClass = 'status-warning'; break;
case 2: statusClass = 'status-error'; break;
case 3: statusClass = 'status-stop'; break;
default: statusClass = '';
}
↑ 【171〜179行目】ステータスコードからCSSクラスを決定
┌─ var statusClass = '' ────────────────────────────────────┐
│ 変数の初期化(空文字で初期化) │
│ 後でswitch文で値を代入する │
└───────────────────────────────────────────────────────────┘
┌─ switch(statusCode) {...} ────────────────────────────────┐
│ 値に応じた分岐処理 │
│ │
│ statusCode │ 実行される処理 │
│ ───────────┼──────────────────────────────────────────── │
│ 0 │ statusClass = 'status-normal' (緑) │
│ 1 │ statusClass = 'status-warning' (黄) │
│ 2 │ statusClass = 'status-error' (赤) │
│ 3 │ statusClass = 'status-stop' (灰) │
│ その他 │ statusClass = '' (初期色) │
└───────────────────────────────────────────────────────────┘
┌─ break; ──────────────────────────────────────────────────┐
│ switch文を抜ける命令 │
│ │
│ ★重要★ breakを書き忘れると、次のcaseも実行される │
│ (フォールスルーという) │
│ │
│ breakなし: │
│ case 0: → case 1: → case 2: → ... 全部実行されてしまう │
│ │
│ breakあり: │
│ case 0: → break → 終了 (正しい動作) │
└───────────────────────────────────────────────────────────┘
┌─ default: ────────────────────────────────────────────────┐
│ どのcaseにも当てはまらない場合の処理 │
│ │
│ 例: statusCode が 5 の場合 → default が実行される │
│ セーフティネットとして必ず書いておくと良い │
└───────────────────────────────────────────────────────────┘
6-12. 図形の種類を決定
// 図形の種類を決定(例:インデックスで振り分け)
var shapeTypes = ['rectangle', 'circle', 'bar', 'triangle'];
var shapeType = shapeTypes[index % shapeTypes.length];
↑ 【180〜182行目】インデックスに応じた図形タイプの決定
┌─ var shapeTypes = ['rectangle', 'circle', 'bar', 'triangle'] ┐
│ 図形タイプの配列 │
│ │
│ インデックス: 0 1 2 3 │
│ rectangle circle bar triangle │
│ (四角) (丸) (棒) (三角) │
└──────────────────────────────────────────────────────────────┘
┌─ index % shapeTypes.length ───────────────────────────────┐
│ 剰余演算子(%)を使ったループ技法 │
│ │
│ shapeTypes.length = 4(配列の要素数) │
│ │
│ index │ index % 4 │ 結果 │
│ ──────┼───────────┼──────────────────────────────────── │
│ 0 │ 0 % 4 │ 0 → shapeTypes[0] = 'rectangle' │
│ 1 │ 1 % 4 │ 1 → shapeTypes[1] = 'circle' │
│ 2 │ 2 % 4 │ 2 → shapeTypes[2] = 'bar' │
│ 3 │ 3 % 4 │ 3 → shapeTypes[3] = 'triangle' │
│ 4 │ 4 % 4 │ 0 → shapeTypes[0] = 'rectangle' │
│ 5 │ 5 % 4 │ 1 → shapeTypes[1] = 'circle' │
│ ... │ ... │ ... (繰り返し) │
│ │
│ 【この技法のメリット】 │
│ データが何行あっても、4種類の図形を順番に割り当てられる │
└───────────────────────────────────────────────────────────┘
6-13. 図形HTMLの生成
// 図形のHTMLを生成
var shapeHtml = '';
if (shapeType === 'rectangle') {
shapeHtml = '<div class="rectangle ' + statusClass + '">' + status + '</div>';
} else if (shapeType === 'circle') {
shapeHtml = '<div class="circle ' + statusClass + '">' + status + '</div>';
} else if (shapeType === 'bar') {
shapeHtml = '<div class="bar ' + statusClass + '">' + status + '</div>';
} else if (shapeType === 'triangle') {
shapeHtml = '<div class="triangle ' + statusClass + '"></div>';
}
↑ 【183〜194行目】図形タイプに応じたHTML生成
┌─ '<div class="rectangle ' + statusClass + '">' ───────────┐
│ 文字列の連結 │
│ │
│ 例: statusClass = 'status-normal' の場合 │
│ │
│ '<div class="rectangle ' + 'status-normal' + '">' │
│ = '<div class="rectangle status-normal">' │
│ │
│ 【生成されるHTML】 │
│ <div class="rectangle status-normal">正常</div> │
│ │
│ このdivには2つのクラスが適用される: │
│ ・rectangle → 四角形のスタイル │
│ ・status-normal → 緑色の背景 │
└───────────────────────────────────────────────────────────┘
┌─ + status + ──────────────────────────────────────────────┐
│ 図形の中に表示するテキスト │
│ │
│ status = "正常" の場合 │
│ → <div class="rectangle status-normal">正常</div> │
│ │
│ ★三角形の場合は中身なし★ │
│ 三角形はCSSのborderで形を作るため、 │
│ 中にテキストを入れられない │
│ → <div class="triangle status-normal"></div> │
└───────────────────────────────────────────────────────────┘
6-14. 完成したアイテムのHTML生成
// 図形アイテム全体のHTMLを生成
var itemHtml =
'<div class="shape-item">' +
shapeHtml +
'<div class="device-label">' + deviceName + '</div>' +
'<div class="status-label">' + status + '</div>' +
'</div>';
↑ 【195〜201行目】図形 + ラベルを組み合わせたHTML生成
┌─ 生成されるHTMLの構造 ────────────────────────────────────┐
│ │
│ <div class="shape-item"> ← 外側の包み │
│ <div class="rectangle status-normal">正常</div> │
│ ↑ 図形 │
│ <div class="device-label">サーバーA</div> │
│ ↑ 機器名ラベル │
│ <div class="status-label">正常</div> │
│ ↑ ステータスラベル │
│ </div> │
│ │
│ 【表示イメージ】 │
│ ┌───────────────┐ │
│ │ 正常 │ ← 四角形(緑色) │
│ └───────────────┘ │
│ サーバーA ← 機器名 │
│ 正常 ← ステータス │
└───────────────────────────────────────────────────────────┘
6-15. コンテナへの追加
// コンテナに追加
container.innerHTML += itemHtml;
↑ 【202〜203行目】生成したHTMLをコンテナに追加
┌─ container.innerHTML += itemHtml ─────────────────────────┐
│ コンテナの中身にHTMLを追加 │
│ │
│ += は「既存の内容に追加」という意味 │
│ = だと「置き換え」になる │
│ │
│ 【処理の流れ】 │
│ 1回目のループ後: │
│ container.innerHTML = "<div>...サーバーA...</div>" │
│ │
│ 2回目のループ後: │
│ container.innerHTML = "<div>...サーバーA...</div> │
│ <div>...サーバーB...</div>" │
│ │
│ ... (繰り返し) │
│ │
│ 最終結果: │
│ container.innerHTML = "<div>A</div><div>B</div>..." │
│ 4つの図形がすべて追加される │
└───────────────────────────────────────────────────────────┘
6-16. 閉じ括弧
});
}
});
});
</script>
↑ 【204〜208行目】各ブロックの終了
┌─ 括弧の対応 ──────────────────────────────────────────────┐
│ │
│ }); ← rows.forEach(function(row, index) { の終了 │
│ │
│ } ← if (results.hasData()) { の終了 │
│ │
│ }); ← results.on("data", function() { の終了 │
│ │
│ }); ← require([...], function(mvc) { の終了 │
│ │
│ </script> ← JavaScriptコードの終了 │
│ │
│ 【インデントで構造を把握】 │
│ require([ │ │
│ results.on("data", function() { │ │
│ if (results.hasData()) { │ ← 対応する括弧 │
│ rows.forEach(function() { │ │
│ }); │ │
│ } │ │
│ }); │ │
│ }); │ │
└───────────────────────────────────────────────────────────┘
🔷 Part 7: XML終了部分
</html>
</panel>
</row>
</dashboard>
↑ 【209〜212行目】各ブロックの終了タグ
</html> ← HTMLパネルの終了
</panel> ← パネルの終了
</row> ← 行の終了
</dashboard> ← ダッシュボードの終了
🎯 まとめ: 処理の全体フロー
【1. 読み込み時】
ダッシュボード読み込み
↓
XMLパース(<search>、<html>などを解析)
↓
SPLサーチ実行: makeresults → eval → table
↓
【2. JavaScript処理】
require() でモジュール読み込み
↓
mvc.Components.get() でサーチ参照取得
↓
results.on("data") でイベント登録
↓
【3. データ取得時】
サーチ完了 → "data"イベント発火
↓
hasData() でデータ確認
↓
rows, fields 取得
↓
【4. 描画処理】
container.innerHTML = '' で初期化
↓
forEach でループ
├─ フィールドインデックス取得
├─ 値取得(deviceName, status, statusCode)
├─ statusClass 決定(switch文)
├─ shapeType 決定(index % 4)
├─ HTML文字列生成
└─ container に追加
↓
【5. 完成!】
┌─────────────────────────────────┐
│ ■緑 ●黄 ▬赤 ▼灰 │
│ サーバーA サーバーB 機器C データベースD │
│ 正常 警告 異常 停止 │
└─────────────────────────────────┘
📚 用語集
用語 意味 SPL Search Processing Language(Splunkのクエリ言語) eval 値を計算・設定するSPLコマンド case() 条件分岐を行うSPL関数 MVC Model-View-Controller(設計パターン) DOM Document Object Model(HTML要素の操作) Flexbox CSSのレイアウト手法 addEventListener イベント処理の登録 parseInt 文字列→整数の変換 innerHTML 要素の中身のHTML
お疲れ様でした!🎊
これで全コードの一行一行の意味が理解できたはずです!