JSONログの高度な集計自動化:jqを用いたグルーピングと統計レポートの生成

Tech

{ “category”: “DevOps/SRE”, “topic”: “Advanced JSON Processing with jq”, “tools”: [“jq”, “bash”, “curl”], “complexity”: “Intermediate/Advanced”, “keywords”: [“group_by”, “reduce”, “aggregation”, “log-analysis”] } 本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

JSONログの高度な集計自動化:jqを用いたグルーピングと統計レポートの生成

【導入と前提】 APIレスポンスや構造化ログから特定のキーを抽出し、出現頻度や合計値を高速に集計するSRE向けログ解析パイプラインの構築。

  • 実行環境:GNU/Linux (Ubuntu/RHEL)

  • 必須ツール:jq 1.6以上, curl

【処理フローと設計】

graph TD
A["JSON Data Source"] -->|curl/cat| B["jq: Pre-filter"]
B -->|group_by| C["jq: Grouping"]
C -->|map/length| D["Summary Report"]
B -->|reduce| E["Custom Aggregation"]
D --> F["Final Output/Alert"]
E --> F

group_by は指定したキーで配列を多次元配列に分割し、map と組み合わせることでカウントや平均値を算出します。一方、reduce はメモリ効率が良く、単一のパスで複雑なハッシュ集計(合計値計算など)を行う際に適しています。

【実装:堅牢な自動化スクリプト】

#!/usr/bin/env bash

# --- 安全のための設定 ---

set -euo pipefail
IFS=$'\n\t'

# --- 終了時のクリーンアップ ---

trap 'rm -f /tmp/raw_data.json' EXIT

# --- 設定:サンプルAPIエンドポイント ---

LOG_URL="https://api.example.com/v1/status/logs"
RAW_FILE="/tmp/raw_data.json"

echo "Step 1: ログデータの取得"

# curlオプション: -s (静音), -L (リダイレクト追従), --retry (一時エラー時の再試行)

if ! curl -sL --retry 3 "$LOG_URL" -o "$RAW_FILE"; then
    echo "Error: データの取得に失敗しました。" >&2
    exit 1
fi

echo "Step 2: group_by によるHTTPステータスコード別集計"

# group_by(.status): 指定キーでグループ化


# map({status: .[0].status, count: length}): 各グループの要素数をカウント

jq -r '
  group_by(.status) 
  | map({
      status: .[0].status, 
      count: length
    }) 
  | .[] 
  | "Status: \(.status) \t Count: \(.count)"
' "$RAW_FILE"

echo "Step 3: reduce による特定ユーザーのペイロード合計計算"

# reduce: 配列を一つずつ処理して accumulator (acc) に格納


# .[]: 入力配列を展開


# acc[.user] += .bytes: ユーザーごとのバイト数を累積

jq -r '
  reduce .[] as $item ({}; .[$item.user] += $item.bytes)
  | to_entries 
  | .[] 
  | "User: \(.key) \t Total Bytes: \(.value)"
' "$RAW_FILE"

# --- systemd-timer用の終了処理 ---

echo "処理が正常に完了しました。"

【検証と運用】

  1. 正常系の確認 スクリプトを実行し、標準出力にステータスコードとユーザーごとの集計が表示されることを確認します。

    ./analyze_logs.sh
    
  2. ログの確認(cron/systemd経由の場合) systemdユニットとして登録している場合は、以下のコマンドで実行履歴を確認します。

    journalctl -u json-aggregator.service --since "1 hour ago"
    

【トラブルシューティングと落とし穴】

  • 巨大なJSONファイルの扱い: jq は入力ファイルを一度メモリに読み込みます。数GB単位のログを処理する場合は、jq --stream オプションの使用を検討してください。

  • データ型の不一致: reduce 内での加算処理(+=)は、初期値が null だとエラーになる場合があります。($item.bytes // 0) のようにデフォルト値を設定すると安全です。

  • 環境変数の管理: APIキーなどの機密情報を含む場合は、スクリプト内にハードコードせず export API_KEY=$(vault read ...) 等のセキュアな方法で注入してください。

  • 一時ファイルの競合: /tmp への書き出しは、同時実行される可能性がある場合 mktemp を使用してファイル名の衝突を避けてください。

【まとめ】 運用の冪等性と堅牢性を維持するための3つのポイント:

  1. パイプラインの保護: set -o pipefail を使用し、jq 内のエラーでスクリプトが停止するように設計する。

  2. 型安全性の確保: jq 内でデータが存在しない可能性を考慮し、デフォルト値演算子(//)を適切に活用する。

  3. リソース管理: trap による確実な一時ファイル削除と、リトライ処理を含む curl の利用を徹底する。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました