{ “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系),
jq1.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
【検証と運用】
正常系の確認: スクリプトを手動実行し、期待されるJSON構造(
status,count,total_response_time)が出力されるか確認します。bash script.sh | jq .ログの確認: systemd経由で実行している場合、以下のコマンドで実行履歴と標準出力を確認します。
journalctl -u json-aggregator.service空データ対応: 入力データが空の場合でも、
reduceの初期値(0)やif文によるゼロ除算回避が機能しているか検証します。
【トラブルシューティングと落とし穴】
メモリ制限:
group_byは内部的にソートを行うため、数GB単位の巨大なJSONファイルを扱うとメモリを消費します。その場合はjqのストリーム処理(--stream)を検討してください。環境変数の保護: APIキーなどを含むURLを使用する場合、スクリプトに直書きせず、
systemdのEnvironmentFileまたは外部のシークレット管理(Vault等)から読み込んでください。パスの解決:
systemdやcrontabで実行する場合、jqやcurlの実行パスが異なることがあります。必ずフルパス(/usr/bin/jq)で指定するか、スクリプト冒頭でPATHを明示してください。
【まとめ】
運用の冪等性を維持するためのポイント:
ステートレスな設計: 一時ファイルは
trapで確実に削除し、実行前後の環境差分を残さない。異常系の事前定義:
set -eとcurl -fにより、不完全なデータに基づく誤った集計結果の出力を防ぐ。型安全性の考慮:
reduce処理時に// 0(デフォルト値)を使用し、欠落したキーによるNullエラーを回避する。

