😊

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 に入れたりしています
GitHubで編集を提案

Discussion