JSONログ集計の自動化:jqのgroup_byとreduceによる高度な統計レポート生成

Tech

{ “role”: “Experienced SRE / DevOps Engineer”, “tone”: “Professional, Technical, Implementation-focused”, “format”: “Markdown”, “key_elements”: [“set -euo pipefail”, “trap”, “Mermaid”, “jq”, “idempotency”], “language”: “Japanese” }

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

JSONログ集計の自動化:jqのgroup_byとreduceによる高度な統計レポート生成

【導入と前提】

大量のJSON構造を持つシステムログやAPIレスポンスを、特定のキーでグループ化・集計し、統計レポートを生成する運用を自動化します。

  • OS: GNU/Linux (Ubuntu 22.04 LTS / RHEL 9 等)

  • ツール: jq (v1.6以上推奨), bash (4.x以上)

  • 権限: 一般ユーザー権限(ログ保存先への書き込み権限が必要)

【処理フローと設計】

graph TD
A["JSON Data Source"] -->|curl / cat| B("Pre-process: Filter")
B -->|jq: group_by| C("Categorize by Key")
C -->|jq: reduce / map| D("Aggregate metrics")
D -->|Format| E["Structured Report/Alert"]
  1. Input: 複数のJSONオブジェクトが含まれるストリームまたは配列。

  2. Process: group_by で特定フィールド(例:ステータスコード)ごとにソート・分離。

  3. Aggregate: reduce または map を用いて、グループ内の数値合計や平均、発生頻度を算出。

  4. Output: 後続の監視ツールやダッシュボードに渡し易い、整理されたJSON形式で出力。

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

#!/usr/bin/env bash

# --- 安全のためのシェルオプション設定 ---

set -euo pipefail

# -e: エラー発生時に即座に終了


# -u: 未定義変数の参照時にエラー


# -o pipefail: パイプラインの途中のエラーを拾う

# --- 一時ファイルの管理 ---

TMP_FILE=$(mktemp)
readonly TMP_FILE
trap 'rm -f "$TMP_FILE"' EXIT # スクリプト終了時に必ず削除

# --- 設定値 ---

readonly RAW_LOG_URL="https://api.example.com/v1/metrics" # 例としてのエンドポイント
readonly REPORT_PATH="./daily_report.json"

main() {
    echo "Starting JSON log aggregation..."

    # 1. データの取得(リトライ付き)


    # --retry: 通信失敗時の再試行


    # -L: リダイレクトを追跡


    # -s: 進捗を表示しない(silent)

    if ! curl -sL --retry 3 "${RAW_LOG_URL}" -o "$TMP_FILE"; then
        echo "Error: Failed to fetch log data." >&2
        exit 1
    fi

    # 2. jqによる高度な集計


    # ロジック:


    # .data 配列を取得 -> status でグループ化 


    # -> 各グループに対し {status, count, avg_latency} を算出


    # -> reduceを使って最終的なサマリJSONを構築

    jq '
        .data | 
        group_by(.status) | 
        map({
            status: .[0].status | tostring,
            count: length,
            avg_latency: (map(.latency) | add / length)
        }) | 
        reduce .[] as $item ({}; . + {($item.status): {count: $item.count, latency: $item.avg_latency}})
    ' "$TMP_FILE" > "$REPORT_PATH"

    echo "Report generated at: ${REPORT_PATH}"
}

main "$@"

【検証と運用】

正常系の確認

生成されたレポートの内容を確認します。

# 生成されたJSONを整形表示

cat daily_report.json | jq .

# 期待される出力例


# {


#   "200": { "count": 150, "latency": 45.2 },


#   "500": { "count": 2, "latency": 1200.5 }


# }

エラー確認

スクリプトが失敗した場合や、systemd等で実行している場合は journalctl を確認します。

# systemdタイマー等で実行している場合

journalctl -u log-aggregation.service -e

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

  1. メモリ消費: group_by は内部で全データのソートを行うため、数GB単位の超巨大JSONを処理する場合、メモリ不足になる可能性があります。その場合は jq--stream オプションを検討するか、前段で split して処理してください。

  2. キーの不在: 集計対象のキー(例:.latency)が存在しないオブジェクトが混じると add でエラーになります。(.latency // 0) のようにデフォルト値を設定する防衛的記述が有効です。

  3. 環境変数の管理: APIキー等が必要な場合、スクリプト内にハードコードせず export API_KEY=... または .env ファイルから読み込むように設計してください。

【まとめ】

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

  • データのクリーンアップ: trap を使用して、失敗時も含め一時ファイルを確実に削除する。

  • 構造の検証: jq 処理の前に、入力データが期待するスキーマを持っているかチェックする。

  • パイプラインの保護: set -o pipefail を指定し、jq 内でのエラーを見逃さないようにする。

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

コメント

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