😊
dbtのログフォーマットをCloud Logging向けに扱いやすくする
tl;dr
以下のような run.sh を用意して、このスクリプトを実行して dbt job を実行すれば、Cloud Logging 上で dbt のログを扱いやすくなります。
run.sh
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
export DBT_LOG_FORMAT=json
# 実行引数を保存
run_args="$*"
# cloudlogging向けに加工
uv run dbt "$@" 2>&1 | while IFS= read -r line; do
echo "$line" | jq -c \
--arg run_args "$run_args" \
'select(type == "object") |
{
severity: (
if .info.level == "error" then "ERROR"
elif .info.level == "warn" then "WARNING"
elif .info.level == "info" then "INFO"
elif .info.level == "debug" then "DEBUG"
else "DEFAULT"
end
),
message: (if .info.name == "Formatting" then "..." else .info.msg end),
timestamp: .info.ts,
invocation_id: .info.invocation_id,
"logging.googleapis.com/labels": ({
run_args: $run_args,
} | with_entries(select(.value != ""))),
raw: .
}' 2>/dev/null || echo "$line"
done
問題意識
dbt は DBT_LOG_FORMAT
環境変数を json
に設定することで、実行ログを JSON で出力できます
が、この JSON の形式は CloudLogging などのログサービスで扱うのに適した構造になっていません
具体的には CloudLogging で特別扱いされるフィールドに適切に値が指定されていないとビューワー上でログメッセージなどが適切に表示されなかったり、ログレベルが指定されなかったりして不便です
ref. Cloud Logging 構造化ログの特別な JSON フィールドまとめ
かといって、デフォルトの出力でもそれはそれで不便、という問題がありました
解決策
dbt の ログ出力は JSON にしつつ、標準出力を jq に食わせて CloudLogging 向けに変換したものを出力するようにしました
工夫ポイント
- jq でのパースに失敗した場合は元の行をそのまま出力し、問題があった場合にもログが確実に出るようにしています
- (最初に貼ったスクリプトでは省いてますが、)label に追加の情報を入れて便利に利用できるようにしています
- dbt job を Google Cloud の Workflows を利用しているので、その workflow_id などを label に入れたりしています
Discussion