jqを駆使したJSONログの高度な集計:group_byとreduceによる分析自動化

Tech

{ “category”: “SRE_DEVOPS_TIPS”, “topic”: “JQ_ADVANCED_AGGREGATION”, “tools”: [“jq”, “bash”, “curl”], “version”: “1.0.0” }

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

jqを駆使したJSONログの高度な集計:group_byとreduceによる分析自動化

【導入と前提】

APIレスポンスやログのJSON配列を特定キーでグループ化・統計処理し、システム状態の可視化を自動化・堅牢化します。

  • OS: 汎用Linux (Ubuntu/RHEL等)

  • ツール: jq 1.6以上, curl 7.0以上

  • 前提: 構造化されたJSON配列データ(例:クラウドのメトリクスやCIビルド履歴)の存在。

【処理フローと設計】

graph TD
A["JSON Input"] --> B["Map/Filter: 前処理"]
B --> C{"Aggregation Logic"}
C --> D["group_by: キーによる群構造化"]
C --> E["reduce: 累積・ハッシュ変換"]
D --> F["Summary Output"]
E --> F
  • 前処理: 不要なフィールドを除去し、メモリ消費を抑えます。

  • group_by: 配列を特定のキーでソート・分割し、階層構造を作ります。

  • reduce: 配列を走査しながらオブジェクト(連想配列)を構築し、計算量を最適化します。

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

#!/usr/bin/env bash

# --- 実行時エラー制御 ---

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

# 一時ファイル管理

TMP_DATA=$(mktemp /tmp/api_response.XXXXXX.json)
trap 'rm -f "$TMP_DATA"' EXIT # スクリプト終了時に必ず削除

# --- 設定・ターゲット ---


# 例: GitHub APIから特定リポジトリのイベントを取得(ダミー)

API_URL="https://api.github.com/repos/stedolan/jq/events"

echo "INFO: データの取得中..."

# curlの堅牢な実行


# -s: 進捗非表示, -S: エラー表示, -L: リダイレクト追従, --retry: 失敗時再試行

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

echo "INFO: 集計の実行 (group_by & reduce)..."

# --- 高度なjq処理 ---


# 1. group_by を使ったイベントタイプ別カウント


# 2. reduce を使ったメモリ効率の良い集計

cat "$TMP_DATA" | jq -r '

  # 処理1: イベントタイプでグループ化してカウント

  group_by(.type) | map({
    type: .[0].type,
    count: length
  }) | 

  # 処理2: reduce を使い、特定ユーザーのアクション数をハッシュ化

  (reduce .[] as $item ({}; .[$item.type] = $item.count)) as $summary |

  # 最終的な構造化出力

  {
    generated_at: (now | strflocaltime("%Y-%m-%d %H:%M:%S")),
    event_summary: $summary,
    top_event: (group_by(.type) | sort_by(length) | last | .[0].type)
  }
'

【検証と運用】

正常系の確認

スクリプトを実行し、標準出力に構造化されたJSONが返ってくることを確認します。

bash aggregate_logs.sh

ログ確認と監視

cronやsystemd timerで運用する場合、標準エラー出力を logger または journalctl に飛ばします。

# systemd ユニットでの確認例

journalctl -u my-jq-aggregator.service --since "1 hour ago"

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

  1. メモリ制限とgroup_by:

    • group_by は内部でデータをソートするため、巨大なJSONファイル(数GB)ではメモリを大量に消費します。その場合は、jq -c で一行ずつ reduce を使ってストリーム処理することを検討してください。
  2. 型変換エラー:

    • JSON内の数値が文字列として渡される場合、tonumber を忘れると集計(add 等)で実行時エラーが発生します。
  3. 機密情報:

    • curl でトークンを渡す際は、set -x(デバッグモード)を無効化するか、環境変数を直接出力しないように注意してください。

【まとめ】

運用の冪等性を維持するための3つのポイント:

  1. 入力データの不変性: 元データを加工せず、パイプラインの最終段で整形する。

  2. アトミックな書き出し: 集計結果をファイルに保存する場合、一時ファイルに書き出してから mv することで中途半端な状態を防ぐ。

  3. スキーマ検証: jq 内で select(has("target_key")) を使い、予期せぬ構造のデータが混入しても処理を継続または安全にスキップさせる。

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

コメント

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