JSONデータの集計を自動化する:jqのgroup_byとreduceを活用したログ解析パイプラインの構築

Tech

{ “status”: “complete”, “task”: “Advanced jq grouping and reduction techniques”, “language”: “ja”, “sre_level”: “senior”, “verified”: false }

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

JSONデータの集計を自動化する:jqのgroup_byとreduceを活用したログ解析パイプラインの構築

【導入と前提】

APIレスポンスや構造化ログ(JSON)を読み込み、特定のキーでグループ化・集計する処理をシェルスクリプトで自動化・堅牢化します。

  • 前提条件: Linux (Ubuntu/RHEL系), jq 1.6以上, curl インストール済み。

【処理フローと設計】

graph TD
A["JSON Input"] --> B{Pre-process}
B -->|filter| C["group_by / reduce"]
C --> D["Aggregation Logic"]
D --> E["Structured Output"]
E --> F["Systemd/Timer for Automation"]

JSON配列を入力とし、group_byで同種データをまとめ、reduceで合計や平均といった統計量を算出します。その後、結果を構造化データとして出力し、継続的なモニタリングへ繋げます。

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

以下は、HTTPステータスコードをグループ化し、レスポンス時間の合計を reduce で算出する実戦的なスクリプト例です。

#!/usr/bin/env bash

# ---------------------------------------------------------


# SRE/DevOps Script: JSON Aggregator


# ---------------------------------------------------------

set -euo pipefail  # エラー発生時に停止、未定義変数参照禁止、パイプ内のエラー捕捉
IFS=$'\n\t'

# 一時ファイルの管理

TMP_DATA=$(mktemp /tmp/agg_data.XXXXXX.json)
trap 'rm -f "$TMP_DATA"' EXIT  # 終了時に必ず削除

# 設定: 取得元URL(例: ダミーAPI)

TARGET_URL="https://api.example.com/v1/logs"
RETRY_COUNT=3
TIMEOUT_SEC=10

echo "--- Data Fetching ---"

# curlによるリトライ付きデータ取得


# -s: 進捗非表示, -S: エラー表示, -L: リダイレクト追従, -f: HTTPエラーで失敗扱い

if ! curl -sSLf --retry "${RETRY_COUNT}" --connect-timeout "${TIMEOUT_SEC}" "${TARGET_URL}" -o "$TMP_DATA"; then
    echo "Error: Failed to fetch data from ${TARGET_URL}" >&2
    exit 1
fi

echo "--- Aggregation Results ---"

# jqによる高度な集計


# 1. group_by(.status): ステータスコードごとに配列を分割


# 2. map(...): 各グループに対して集計を実行


# 3. reduce: 特定キー(例: response_time)の総和を算出

cat "$TMP_DATA" | jq '
  group_by(.status) | 
  map({
    status: .[0].status,
    count: length,
    total_response_time: (reduce .[] as $item (0; . + ($item.response_time // 0))),
    average_response_time: (
      if length > 0 then 
        (reduce .[] as $item (0; . + ($item.response_time // 0))) / length 
      else 0 end
    )
  })
'

# 補足: systemd-cat を使用して結果を journald に送る場合は、


# 上記の出力を | systemd-cat -t "json-aggregator" と連結する。

systemd タイマーによる定期実行例

/etc/systemd/system/json-aggregator.timer

[Unit]
Description=Run JSON Aggregation every 5 minutes

[Timer]
OnCalendar=*:0/5
Persistent=true

[Install]
WantedBy=timers.target

【検証と運用】

  1. 正常系の確認: スクリプトを手動実行し、期待されるJSON構造(status, count, total_response_time)が出力されるか確認します。 bash script.sh | jq .

  2. ログの確認: systemd経由で実行している場合、以下のコマンドで実行履歴と標準出力を確認します。 journalctl -u json-aggregator.service

  3. 空データ対応: 入力データが空の場合でも、reduce の初期値(0)や if 文によるゼロ除算回避が機能しているか検証します。

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

  • メモリ制限: group_by は内部的にソートを行うため、数GB単位の巨大なJSONファイルを扱うとメモリを消費します。その場合は jq のストリーム処理(--stream)を検討してください。

  • 環境変数の保護: APIキーなどを含むURLを使用する場合、スクリプトに直書きせず、systemdEnvironmentFile または外部のシークレット管理(Vault等)から読み込んでください。

  • パスの解決: systemdcrontab で実行する場合、jqcurl の実行パスが異なることがあります。必ずフルパス(/usr/bin/jq)で指定するか、スクリプト冒頭で PATH を明示してください。

【まとめ】

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

  1. ステートレスな設計: 一時ファイルは trap で確実に削除し、実行前後の環境差分を残さない。

  2. 異常系の事前定義: set -ecurl -f により、不完全なデータに基づく誤った集計結果の出力を防ぐ。

  3. 型安全性の考慮: reduce 処理時に // 0(デフォルト値)を使用し、欠落したキーによるNullエラーを回避する。

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

コメント

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