0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【うさうさと学ぶ】Splunk SPL文法 実務で即使えるガイド - コード詳細解説版

0
Posted at

【実務で即使える】Splunk SPL文法完全ガイド - コード詳細解説版

1. 基本構文:indexからのデータ取得

# ===== 基本的なindex検索 =====
index=web_logs              # web_logsというインデックスからデータを取得
sourcetype=access_combined  # アクセスログの形式で絞り込み
| head 100                  # 結果を100件に制限(パイプで処理を連結)

うさうさポイント🐰: |(パイプ)は料理の工程みたいなもの。材料(データ)→切る→煮る→盛り付けの順番!


2. 時間範囲の指定

# ===== 相対時間での検索 =====
index=main                  # mainインデックスを対象
earliest=-24h               # 24時間前から
latest=now                  # 現在時刻まで

# ===== 絶対時間での検索 =====
index=main                                      # mainインデックスを対象
earliest="01/15/2026:00:00:00"                  # 2026年1月15日0時から
latest="01/15/2026:23:59:59"                    # 2026年1月15日23時59分59秒まで

# ===== 時刻の切り捨て(@記号) =====
earliest=-1d@d              # 昨日の0時0分0秒から(@dで日の開始時刻に切り捨て)
latest=@d                   # 今日の0時0分0秒まで(つまり昨日1日分)

earliest=-7d@d              # 7日前の0時0分0秒から
latest=@d                   # 今日の0時0分0秒まで(過去7日間)

earliest=-1h@h              # 1時間前の0分0秒から(@hで時の開始時刻に切り捨て)
latest=now                  # 現在時刻まで

3. フィールド検索とフィルタリング

# ===== 完全一致検索 =====
index=app_logs              # app_logsインデックスから
status=200                  # statusフィールドが200のものだけ

index=app_logs                              # app_logsインデックスから
user="yukiko.ishiguro@example.com"          # userフィールドが完全一致

# ===== 部分一致検索(ワイルドカード) =====
index=app_logs              # app_logsインデックスから
error=*timeout*             # errorフィールドに"timeout"を含む(前後に何でもOK)

index=app_logs              # app_logsインデックスから
url="*/api/*"               # urlフィールドに"/api/"を含む

# ===== AND条件(スペース区切り) =====
index=main                  # mainインデックスから
status=500                  # statusが500で
method=POST                 # かつmethodがPOST

# ===== OR条件(括弧で囲む) =====
index=main                  # mainインデックスから
(status=500 OR status=502 OR status=503)  # statusが500か502か503のいずれか

# ===== NOT条件(除外) =====
index=main                  # mainインデックスから
status=200                  # statusが200で
NOT user=admin              # userがadminでないもの

4. 統計コマンド(Stats Commands)

# ===== 基本的な集計 =====
index=web_logs              # web_logsインデックスから
| stats                     # 統計処理を開始
    count                   # 件数をカウント
    by status               # statusフィールドごとにグループ化

# ===== 複数の統計関数を組み合わせ =====
index=web_logs                              # web_logsインデックスから
| stats                                     # 統計処理を開始
    count as total_requests,                # 件数を total_requests という名前で集計
    avg(response_time) as avg_time,         # response_timeの平均を avg_time という名前で計算
    max(response_time) as max_time,         # response_timeの最大値を max_time として取得
    min(response_time) as min_time,         # response_timeの最小値を min_time として取得
    sum(bytes) as total_bytes               # bytesの合計を total_bytes として計算
    by host                                 # hostごとにグループ化

# ===== 時系列グラフ用の集計 =====
index=web_logs              # web_logsインデックスから
| timechart                 # 時系列チャート用の統計処理
    span=1h                 # 1時間ごとに集計(spanで時間間隔を指定)
    count                   # 件数をカウント
    by status               # statusごとに分類

うさうさポイント🐰: statsは「集計レジ」、timechartは「売上グラフを時間軸で作る機械」だと思ってね!


5. データ変換と加工

# ===== evalでフィールド計算 =====
index=app_logs                              # app_logsインデックスから
| eval                                      # フィールド計算を開始
    response_time_ms=response_time*1000     # response_timeを1000倍してミリ秒に変換
| eval                                      # 続けて別の計算(複数のevalを連結可能)
    status_category=case(                   # case文で条件分岐
        status>=200 AND status<300,         # 200番台なら
        "Success",                          # "Success"を設定
        status>=400 AND status<500,         # 400番台なら
        "Client Error",                     # "Client Error"を設定
        status>=500,                        # 500番台以上なら
        "Server Error",                     # "Server Error"を設定
        1=1,                                # それ以外(常に真)なら
        "Other"                             # "Other"を設定
    )

# ===== rexで正規表現抽出 =====
index=web_logs                              # web_logsインデックスから
| rex                                       # 正規表現抽出を開始
    field=url                               # urlフィールドから抽出
    "\/api\/(?<api_version>v\d+)\/(?<endpoint>\w+)"  
    # /api/v1/users のような形式から
    # (?<api_version>v\d+) → "v1"を api_version フィールドに抽出
    # (?<endpoint>\w+) → "users"を endpoint フィールドに抽出

# ===== whereで条件フィルタ =====
index=app_logs                              # app_logsインデックスから
| stats                                     # まず統計処理
    avg(response_time) as avg_time          # 平均応答時間を計算
    by endpoint                             # エンドポイントごと
| where avg_time > 1.0                      # 平均応答時間が1.0秒を超えるものだけ残す

6. テーブル整形とソート

# ===== 表示フィールドの選択 =====
index=web_logs                              # web_logsインデックスから
| table                                     # テーブル形式で表示
    _time,                                  # タイムスタンプ
    host,                                   # ホスト名
    status,                                 # ステータスコード
    url,                                    # URL
    response_time                           # 応答時間

# ===== ソート(並び替え) =====
index=app_logs                              # app_logsインデックスから
| stats count by user                       # ユーザーごとに件数を集計
| sort -count                               # 件数で降順ソート(-は降順、なしは昇順)
| head 10                                   # 上位10件のみ表示

# ===== フィールド名の変更 =====
index=web_logs                              # web_logsインデックスから
| stats                                     # 統計処理
    count as リクエスト数,                   # count を「リクエスト数」に改名
    avg(response_time) as 平均応答時間       # avg(response_time)を「平均応答時間」に改名

7. 実務パターン集

パターン1: エラー率の監視

index=app_logs                              # app_logsインデックスから
| stats                                     # 統計処理を開始
    count as total,                         # 全件数をtotalとして集計
    count(eval(status>=500)) as errors      # status>=500の件数をerrorsとして集計
                                            # eval()内の条件に一致するものだけカウント
| eval                                      # 計算処理
    error_rate=round(errors/total*100, 2)   # エラー率を計算(百分率、小数点2桁)
                                            # round()で四捨五入

パターン2: トップN抽出

index=web_logs                              # web_logsインデックスから
| stats count by url                        # URLごとにアクセス数を集計
| sort -count                               # 件数で降順ソート(多い順)
| head 20                                   # 上位20件のみ取得
| rename                                    # フィールド名を変更
    url as "アクセスURL",                   # urlを「アクセスURL」に
    count as "アクセス数"                   # countを「アクセス数」に

パターン3: 時間帯別の傾向分析

index=app_logs                              # app_logsインデックスから
| eval                                      # フィールド計算
    hour=strftime(_time, "%H")              # タイムスタンプから時(00-23)を抽出
                                            # strftime()で時刻をフォーマット変換
| stats                                     # 統計処理
    avg(response_time) as avg_response,     # 平均応答時間を計算
    count as requests                       # リクエスト数を集計
    by hour                                 # 時間帯(hour)ごとにグループ化
| sort hour                                 # 時間順にソート(0時から23時まで)

パターン4: 異常検知(閾値超え)

index=system_logs                           # system_logsインデックスから
| stats                                     # 統計処理
    avg(cpu_usage) as avg_cpu               # CPU使用率の平均を計算
    by host                                 # ホストごと
| where avg_cpu > 80                        # 平均CPU使用率が80%を超えるものだけ
| eval                                      # アラートレベルを計算
    alert_level=case(                       # 条件分岐で判定
        avg_cpu>90,                         # 90%超なら
        "Critical",                         # 「Critical - 即対応」
        avg_cpu>80,                         # 80%超なら(既に90%超は除外済み)
        "Warning"                           # 「Warning - 要注意」
    )

パターン5: セキュリティイベントの検知

index=security_logs                         # security_logsインデックスから
earliest=-5m                                # 直近5分間のデータ
| search                                    # 追加の検索条件
    (action=login AND result=failed)        # ログイン失敗、または
    OR                                      # あるいは
    (action=unauthorized_access)            # 不正アクセス
| stats                                     # 統計処理
    count as event_count,                   # イベント数を集計
    values(user) as users,                  # 関与したユーザーのリスト(重複なし)
    values(src_ip) as source_ips            # 送信元IPのリスト(重複なし)
    by action                               # アクションタイプごと
| where event_count > 5                     # 5回以上発生したもののみ

8. パフォーマンス最適化

# ===== Good Practice(推奨) =====
index=main                                  # インデックスを明示
sourcetype=access                           # ソースタイプも指定
earliest=-1h                                # 時間範囲を限定(1時間)
| search status=500                         # 早い段階でフィルタリング
| stats count by host                       # 必要な統計のみ

# ===== フィールドを明示的に選択 =====
index=main                                  # インデックスを指定
| fields                                    # フィールドを選択
    _time,                                  # タイムスタンプ
    host,                                   # ホスト
    status,                                 # ステータス
    response_time                           # 応答時間(これら4つのみ処理対象)
| stats                                     # 統計処理
    avg(response_time)                      # 平均応答時間を計算
    by host                                 # ホストごと

# ===== Bad Practice(非推奨) =====
index=main                                  # 全データ取得(時間範囲なし→遅い)
| stats                                     # すべてのフィールドで統計
    count                                   # 集計してから
    by sourcetype, status, host             # 複数軸でグループ化(重い)
| search status=500                         # 最後にフィルタ(遅い!早めにやるべき)

最適化の鉄則🐰:

  1. 🥕 材料(データ)は最初に選ぶ(index, 時間範囲)
  2. 🥕 不要な野菜(フィールド)は早めに捨てる
  3. 🥕 大きな鍋(統計処理)の前に下ごしらえ(フィルタ)

【Splunk】ダッシュボード構築の実践的テクニック

1. 基本的なダッシュボードXML

<dashboard>
  <!-- ダッシュボード全体の設定 -->
  <label>リアルタイム監視ダッシュボード</label>
  <!-- ダッシュボードのタイトル -->
  
  <description>システム全体のステータスを監視</description>
  <!-- ダッシュボードの説明文 -->
  
  <!-- 行(横方向のレイアウト) -->
  <row>
    <!-- パネル1: エラー数の推移 -->
    <panel>
      <title>エラー数推移(1時間)</title>
      <!-- パネルのタイトル -->
      
      <chart>
        <!-- グラフタイプのビジュアライゼーション -->
        <search>
          <!-- 検索クエリ -->
          <query>
            <!-- SPL検索文 -->
index=app_logs                      <!-- app_logsから -->
level=ERROR                         <!-- エラーレベルのみ -->
earliest=-1h                        <!-- 1時間前から -->
| timechart                         <!-- 時系列グラフ用集計 -->
    span=5m                         <!-- 5分間隔 -->
    count                           <!-- 件数をカウント -->
    by host                         <!-- ホストごとに分類 -->
          </query>
          <earliest>-1h</earliest>
          <!-- 検索の開始時刻(1時間前) -->
          <latest>now</latest>
          <!-- 検索の終了時刻(現在) -->
        </search>
        
        <!-- グラフの表示オプション -->
        <option name="charting.chart">line</option>
        <!-- グラフタイプ: 折れ線グラフ -->
        
        <option name="charting.axisY.minimumNumber">0</option>
        <!-- Y軸の最小値を0に設定 -->
        
        <option name="charting.legend.placement">bottom</option>
        <!-- 凡例を下部に配置 -->
      </chart>
    </panel>
  </row>
</dashboard>

2. KPIダッシュボード

<row>
  <!-- シングルバリュー(単一値)表示 -->
  <panel>
    <title>総リクエスト数</title>
    <single>
      <!-- シングルバリュータイプ -->
      <search>
        <query>
index=web_logs                      <!-- web_logsから -->
earliest=-24h                       <!-- 24時間分 -->
| stats count                       <!-- 件数を集計 -->
| eval count=tostring(count, "commas")  
<!-- 数値をカンマ区切りの文字列に変換(例: 1234567 → 1,234,567) -->
        </query>
      </search>
      
      <option name="numberPrecision">0</option>
      <!-- 小数点以下の桁数: 0桁(整数表示) -->
      
      <option name="underLabel">過去24時間</option>
      <!-- 数値の下に表示するラベル -->
      
      <option name="rangeColors">["0x65A637","0x6DB7C6","0xF7BC38","0xF58F39","0xD93F3C"]</option>
      <!-- レンジごとの色設定(緑→青→黄→橙→赤) -->
    </single>
  </panel>
  
  <!-- エラー率のKPI -->
  <panel>
    <title>エラー率</title>
    <single>
      <search>
        <query>
index=app_logs                      <!-- app_logsから -->
earliest=-1h                        <!-- 1時間分 -->
| stats                             <!-- 統計処理 -->
    count as total,                 <!-- 総数 -->
    count(eval(status>=500)) as errors  
    <!-- status>=500の件数(サーバーエラー) -->
| eval error_rate=round((errors/total)*100, 2)  
<!-- エラー率を計算: (エラー数/総数)×100、小数点2桁 -->
| fields error_rate               <!-- error_rateフィールドのみ表示 -->
        </query>
      </search>
      
      <option name="unit">%</option>
      <!-- 単位を%で表示 -->
      
      <option name="rangeValues">[0,1,5]</option>
      <!-- 閾値: 0-1%(緑)、1-5%(黄)、5%以上(赤) -->
      
      <option name="rangeColors">["0x65A637","0xF7BC38","0xD93F3C"]</option>
      <!-- 緑、黄、赤の色設定 -->
    </single>
  </panel>
</row>

3. インタラクティブ機能(ドリルダウン)

<panel>
  <title>ホスト別エラー数(クリックで詳細表示)</title>
  <table>
    <search>
      <query>
index=app_logs                      <!-- app_logsから -->
level=ERROR                         <!-- エラーのみ -->
earliest=-1h                        <!-- 1時間分 -->
| stats count by host               <!-- ホストごとに集計 -->
| sort -count                       <!-- 降順ソート -->
      </query>
    </search>
    
    <!-- ドリルダウン設定 -->
    <drilldown>
      <!-- 行クリック時の動作 -->
      <link target="_blank">
        <!-- 新しいタブで開く -->
        /app/search/search?q=
        search index=app_logs level=ERROR host=$click.value$
        <!-- クリックした行のhost値を $click.value$ で取得 -->
        &amp;earliest=-1h
        <!-- &はXMLなので &amp; とエスケープ -->
      </link>
    </drilldown>
  </table>
</panel>

4. 動的フィルター(インプット)

<fieldset submitButton="true">
  <!-- 検索ボタン付きのフィールドセット -->
  
  <!-- 時間範囲ピッカー -->
  <input type="time" token="time_range">
    <!-- トークン名: time_range(他のパネルで使用可能) -->
    <label>時間範囲</label>
    <default>
      <earliest>-24h</earliest>
      <!-- デフォルト: 24時間前から -->
      <latest>now</latest>
      <!-- デフォルト: 現在まで -->
    </default>
  </input>
  
  <!-- ドロップダウン選択 -->
  <input type="dropdown" token="selected_host">
    <!-- トークン名: selected_host -->
    <label>ホスト選択</label>
    <choice value="*">すべて</choice>
    <!-- *はワイルドカード(全て選択) -->
    <choice value="web01">web01</choice>
    <choice value="web02">web02</choice>
    <choice value="db01">db01</choice>
    <default>*</default>
    <!-- デフォルト値: すべて -->
  </input>
  
  <!-- テキスト入力 -->
  <input type="text" token="search_keyword">
    <label>検索キーワード</label>
    <default>*</default>
    <!-- デフォルト: ワイルドカード(全て) -->
  </input>
</fieldset>

<!-- トークンを使用したパネル -->
<row>
  <panel>
    <title>フィルタ結果</title>
    <table>
      <search>
        <query>
index=app_logs                      <!-- app_logsから -->
host=$selected_host$                <!-- トークンを$で囲んで使用 -->
$search_keyword$                    <!-- キーワードで絞り込み -->
| stats count by level              <!-- レベルごとに集計 -->
        </query>
        <earliest>$time_range.earliest$</earliest>
        <!-- 時間範囲トークンの開始時刻 -->
        <latest>$time_range.latest$</latest>
        <!-- 時間範囲トークンの終了時刻 -->
      </search>
    </table>
  </panel>
</row>

5. リアルタイムダッシュボード

<panel>
  <title>リアルタイムエラー監視</title>
  <chart>
    <search>
      <query>
index=app_logs                      <!-- app_logsから -->
level=ERROR                         <!-- エラーのみ -->
| timechart                         <!-- 時系列グラフ -->
    span=10s                        <!-- 10秒間隔(リアルタイム用) -->
    count                           <!-- 件数をカウント -->
      </query>
      
      <earliest>rt-5m</earliest>
      <!-- リアルタイム検索: 5分前から(rtはreal-time) -->
      
      <latest>rt</latest>
      <!-- リアルタイム検索: 現在まで -->
      
      <refresh>10s</refresh>
      <!-- 10秒ごとに自動更新 -->
    </search>
    
    <option name="charting.chart">area</option>
    <!-- エリアチャート(面グラフ) -->
    
    <option name="refresh.display">progressbar</option>
    <!-- 更新時にプログレスバーを表示 -->
  </chart>
</panel>

6. カスタムCSS(見た目のカスタマイズ)

<dashboard stylesheet="custom_dashboard.css">
  <!-- カスタムCSSファイルを読み込み -->
  
  <label>カスタムデザインダッシュボード</label>
  
  <row>
    <panel id="critical_panel">
      <!-- IDを付けてCSS適用可能にする -->
      <title>Critical Alerts</title>
      <single>
        <search>
          <query>
index=app_logs                      <!-- app_logsから -->
level=CRITICAL                      <!-- クリティカルレベル -->
earliest=-5m                        <!-- 5分以内 -->
| stats count                       <!-- 件数を集計 -->
          </query>
        </search>
      </single>
    </panel>
  </row>
</dashboard>

custom_dashboard.css:

/* Critical パネルの背景色を赤に */
#critical_panel {
    background-color: #ffebee;  /* 薄い赤 */
    border-left: 5px solid #d32f2f;  /* 左に赤いボーダー */
}

/* パネルタイトルのスタイル */
.dashboard-panel > .dashboard-element > .panel-head {
    background-color: #1976d2;  /* 青色の背景 */
    color: white;  /* 白文字 */
    font-weight: bold;  /* 太字 */
    padding: 10px;  /* 内側の余白 */
}

/* シングルバリューの数値サイズ */
.single-value {
    font-size: 48px !important;  /* 数値を大きく */
    font-weight: bold;  /* 太字 */
}

【運用自動化】Splunkで実現する24時間監視体制

1. 基本的なアラート検索

# ===== エラー急増検知アラート =====
index=app_logs                      # app_logsインデックスから
level=ERROR                         # エラーレベルのみ
earliest=-5m                        # 直近5分間のデータ
| stats                             # 統計処理開始
    count as error_count            # エラー数をerror_countとして集計
    by host                         # ホストごとにグループ化
| where error_count > 50            # 50件を超えるものだけ抽出
| eval                              # 重要度判定を計算
    severity=case(                  # case文で条件分岐
        error_count>100,            # 100件超なら
        "Critical",                 # "Critical"(緊急)
        error_count>50,             # 50件超なら
        "Warning"                   # "Warning"(警告)
    )

アラート設定(UI上):

  • Schedule: Every 5 minutes(5分ごと実行)
  • Time Range: -5m(直近5分)
  • Trigger when: Number of Results > 0(結果が1件以上あれば発火)

2. 複雑な条件のアラート

# ===== 応答時間劣化検知 =====
index=web_logs                      # web_logsインデックスから
earliest=-10m                       # 直近10分間
| stats                             # 統計処理
    avg(response_time) as avg_time, # 平均応答時間を計算
    max(response_time) as max_time, # 最大応答時間を取得
    count                           # リクエスト数も取得
    by host                         # ホストごと
| where                             # 条件フィルタ
    avg_time > 2.0                  # 平均が2秒超、または
    OR max_time > 5.0               # 最大が5秒超
| eval                              # アラート内容を生成
    alert_message="Host: " . host . 
    ", Avg: " . round(avg_time, 2) . "s" . 
    ", Max: " . round(max_time, 2) . "s"
    # 文字列を . で連結してメッセージ作成
    # round()で小数点2桁に丸める

3. ログ出力停止検知

# ===== ログ出力停止の検知(ハートビート監視) =====
index=app_logs                      # app_logsインデックスから
earliest=-15m                       # 直近15分間
| stats count by host               # ホストごとのログ件数を集計
| append                            # 結果に追加データを結合
    [| inputlookup expected_hosts.csv]  
    # expected_hosts.csvから期待されるホストリストを読み込み
    # サブサーチ([]で囲まれた部分)の結果を追加
| stats                             # 再度統計処理
    sum(count) as log_count         # ログ件数の合計
    by host                         # ホストごと
| where                             # 条件チェック
    log_count=0                     # ログが0件、または
    OR isnull(log_count)            # ログ件数がnull(データなし)
| eval                              # アラートメッセージ作成
    alert_type="No logs detected",  # アラートタイプ
    severity="High"                 # 重要度は高

expected_hosts.csv の中身:

host
web01
web02
db01
app01

4. セキュリティアラート

# ===== ログイン失敗の異常検知 =====
index=security_logs                 # security_logsから
earliest=-5m                        # 直近5分間
| search                            # 追加検索条件
    (action=login AND result=failed)    # ログイン失敗、または
    OR                              # あるいは
    (action=unauthorized_access)    # 不正アクセス試行
| stats                             # 統計処理
    count as event_count,           # イベント数を集計
    values(user) as users,          # 関与したユーザー名(重複排除)
                                    # values()はユニークな値のリストを返す
    values(src_ip) as source_ips    # 送信元IPアドレス(重複排除)
    by action                       # アクションタイプごと
| where event_count > 5             # 5回以上発生したもののみ
| eval                              # 詳細メッセージ作成
    alert_details="Action: " . action . 
    ", Count: " . event_count . 
    ", Users: " . users . 
    ", IPs: " . source_ips

5. Webhook連携(Slack通知)

{
  "text": "🚨 High Error Rate Alert",
  
  "attachments": [
    {
      "color": "danger",
      
      "fields": [
        {
          "title": "Host",
          "value": "$result.host$",
          "short": true
        },
        {
          "title": "Error Count",
          "value": "$result.error_count$",
          "short": true
        },
        {
          "title": "Severity",
          "value": "$result.severity$",
          "short": true
        },
        {
          "title": "Detection Time",
          "value": "$trigger_time$",
          "short": true
        },
        {
          "title": "Search Link",
          "value": "<$results_link$|View Details>",
          "short": false
        }
      ],
      
      "footer": "Splunk Alert System",
      
      "ts": "$trigger_time_epoch$"
    }
  ]
}

トークンの説明:

  • $result.host$ → 検索結果のhostフィールド値
  • $result.error_count$ → 検索結果のerror_countフィールド値
  • $trigger_time$ → アラート発火時刻
  • $results_link$ → Splunk検索結果へのリンク
  • $trigger_time_epoch$ → Unix エポック時間

6. 自動復旧スクリプト

#!/bin/bash
# ===== auto_restart.sh =====
# Splunkアラートから呼び出される自動復旧スクリプト

# コマンドライン引数を変数に格納
HOST=$1          # 第1引数: ホスト名
SERVICE=$2       # 第2引数: サービス名

# ログファイルのパス
LOG_FILE="/var/log/splunk_auto_recovery.log"

# 現在時刻を取得
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

# ログに記録
echo "[$TIMESTAMP] Starting auto recovery for $SERVICE on $HOST" >> $LOG_FILE

# SSH経由でサービス再起動を実行
# -o StrictHostKeyChecking=no: ホストキーチェックをスキップ(自動化用)
ssh -o StrictHostKeyChecking=no $HOST "sudo systemctl restart $SERVICE"

# 再起動コマンドの終了ステータスをチェック
if [ $? -eq 0 ]; then
    # 成功時(終了コード0)
    echo "[$TIMESTAMP] Successfully restarted $SERVICE on $HOST" >> $LOG_FILE
    
    # 成功通知メールを送信
    echo "Service $SERVICE has been automatically restarted on $HOST at $TIMESTAMP" | \
        mail -s "Auto Recovery Success: $SERVICE on $HOST" ops@example.com
else
    # 失敗時(終了コード0以外)
    echo "[$TIMESTAMP] Failed to restart $SERVICE on $HOST" >> $LOG_FILE
    
    # 失敗通知メールを送信
    echo "Failed to restart $SERVICE on $HOST at $TIMESTAMP. Manual intervention required." | \
        mail -s "Auto Recovery FAILED: $SERVICE on $HOST" ops@example.com
fi

# 再起動後のステータス確認(5秒待機)
sleep 5

# サービスの状態を確認
STATUS=$(ssh $HOST "systemctl is-active $SERVICE")
echo "[$TIMESTAMP] Service status: $STATUS" >> $LOG_FILE

Splunkアラートアクション設定:

Script filename: auto_restart.sh
Script arguments: "$result.host$" "$result.service$"

7. メール通知テンプレート

Subject: [Splunk Alert] $name$ - $result.severity$

本文:
================================================================
Splunk自動監視システムからのアラート通知
================================================================

【アラート名】
$name$

【重要度】
$result.severity$

【検出時刻】
$trigger_time$

【検出内容】
ホスト: $result.host$
エラー数: $result.error_count$
エラーメッセージ: $result.error_message$

【詳細情報】
直近5分間で異常なエラー増加を検知しました。
通常時の平均: 10件/5分
現在の検出数: $result.error_count$件/5分

【対応手順】
1. 以下のリンクから詳細ログを確認
   $results_link$

2. エラーの原因を特定

3. 必要に応じてサービス再起動
   ssh $result.host$ "sudo systemctl restart app-service"

4. 復旧後、Slackの #ops-alerts チャンネルで報告

【エスカレーション】
30分以内に復旧しない場合:
- オンコールエンジニアに連絡: +81-90-XXXX-XXXX
- マネージャーに報告: manager@example.com

================================================================
Splunk Alert System - Powered by DX Team
================================================================

8. アラート抑制(Throttle)設定

# ===== 基本検索(アラート抑制前) =====
index=app_logs                      # app_logsから
level=ERROR                         # エラーのみ
earliest=-5m                        # 直近5分
| stats                             # 統計処理
    count by host, error_type       # ホストとエラータイプごと
| where count > 10                  # 10件超のみ

Throttle設定(UI上):

Suppress triggering for: 1 hour
# 同じ条件で1時間以内に再発火しない

Suppress results containing field: host
# hostフィールドが同じ結果は抑制
# つまり、同じホストからのアラートは1時間に1回のみ

効果:

09:00 - web01でアラート発火 → 通知送信 ✅
09:15 - web01でアラート発火 → 抑制(通知なし) 🔇
09:30 - web01でアラート発火 → 抑制(通知なし) 🔇
09:45 - web02でアラート発火 → 通知送信 ✅(別ホストなのでOK)
10:01 - web01でアラート発火 → 通知送信 ✅(1時間経過したのでOK)

9. 複数条件の組み合わせアラート

# ===== 複合条件での異常検知 =====
index=app_logs                      # app_logsから
earliest=-5m                        # 直近5分
| stats                             # 統計処理
    avg(response_time) as avg_time, # 平均応答時間
    count(eval(status=500)) as error_count,  
    # status=500の件数(サーバーエラー)
    count as total                  # 総リクエスト数
    by host                         # ホストごと
| eval                              # アラート条件の評価
    alert=case(                     # case文で複数条件判定
        avg_time>2.0 AND error_count>10,     
        # 応答時間が遅い かつ エラーが多い
        "Critical",                 # → Critical(最重要)
        
        avg_time>1.5 OR error_count>5,       
        # 応答時間がやや遅い または エラーがやや多い
        "Warning",                  # → Warning(警告)
        
        1=1,                        # それ以外(常に真)
        "Normal"                    # → Normal(正常)
    )
| where                             # フィルタリング
    alert IN ("Critical", "Warning")  
    # CriticalまたはWarningのみ抽出(Normalは除外)
| eval                              # 詳細メッセージ作成
    details="Host: " . host . 
    " | Avg Time: " . round(avg_time, 2) . "s" . 
    " | Errors: " . error_count . "/" . total

10. 機械学習による異常検知

# ===== 過去の傾向から異常を検知 =====
index=app_logs                      # app_logsから
earliest=-7d                        # 過去7日分のデータ
| timechart                         # 時系列データ作成
    span=1h                         # 1時間ごと
    count                           # リクエスト数を集計
| predict                           # 予測アルゴリズム適用
    count                           # countフィールドを予測
    as predicted_count              # 予測値をpredicted_countとして保存
    algorithm=LLP                   # LLP(Local Linear Prediction)アルゴリズム使用
    future_timespan=0               # 未来予測はしない(現在の異常検知のみ)
| eval                              # 偏差を計算
    deviation=abs(count-predicted_count)  
    # 実測値と予測値の差の絶対値
| where                             # 異常判定
    deviation > predicted_count*0.3   
    # 予測値の30%以上乖離していたら異常
| eval                              # アラートレベル判定
    alert_level=case(
        deviation > predicted_count*0.5,   
        # 50%以上の乖離
        "Critical - 即対応",
        
        deviation > predicted_count*0.3,   
        # 30-50%の乖離
        "Warning - 要監視",
        
        1=1, "Info"                 # それ以外
    )

うさうさポイント🐰:
機械学習は「いつものパターン」を学習して、「いつもと違う」を見つける賢い子!

  • 📊 過去7日間のデータで「普通の状態」を学習
  • 🔍 今のデータが「普通」から30%以上離れてたらアラート
  • 🎯 曜日や時間帯の変動も考慮してくれる

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?