debug-local について
Lightdash開発者向けのローカルデバッグガイドです。修正前にログ、トレース、再現による根拠で原因を確認し、PM2、Maple、ブラウザツール、データベースを使った調査手順をまとめています。
主な機能
- 01証拠を集めて根本原因を確認
- 02Mapleでトレースとエラーを検索
- 03既知のパターンに沿って調査
- 04仮説を検証して回帰テストを作成
- 05修正を確認してデバッグ報告を作成
活用シーン
- 01APIエラーや応答遅延を調査
- 02権限、キャッシュ、移行の問題を診断
- 03フロントエンドやスケジューラーの障害を調査
- 04修正を検証し根拠を記録
MCP 対応
ブラウザー自動化にはChrome DevTools MCPツールを使用します。ページ移動、スナップショット、操作、スクリーンショット、ネットワーク調査に対応します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lightdash/ lightdash --skill debug-localインストール後、Claude Code で/debug-localを入力して読み込まれたか確認します。
詳細
Lightdash のデバッグ
鉄則
根本原因を調査する前に、修正してはいけません。
証拠(ログ、トレース、再現)に裏付けられた根本原因の仮説を確認するまで、アプリケーションコードを編集しないでください。症状だけを修正すると、いたちごっこのようなデバッグになります。
フェーズ 1:証拠を集める
仮説を立てる前に、事実を集めてください。
1. 症状を収集する
エラーメッセージ、スタックトレース、再現手順を確認してください。ユーザーから十分なコンテキストが提供されていない場合は、確認の質問を 1 つだけしてください。
2. 最近の変更を確認する
git log --oneline -20 -- <affected-files>
以前は動作していましたか?リグレッションであれば、根本原因は差分にあります。
3. ログとトレースを確認する
pnpm exec pm2 logs lightdash-api --lines 50 --nostream
次に Maple を照会します(ローカルモードでは、API とスケジューラーからの OTLP トレースを取り込みます)。
maple services --format table # per-service throughput and error rate
maple errors --since 5m # errors grouped by fingerprint
maple traces --since 5m --errors # recent traces containing errors
maple trace <trace-id> # full span tree + correlated logs
maple slow-traces --since 15m # slowest traces
CLI のデフォルトポートは 4318 なので、まずこのインスタンスを指定します。
export MAPLE_LOCAL_URL="http://127.0.0.1:${MAPLE_PORT:-4320}"。すべてのフィルターについては
トレース検索を参照してください。
4. 再現する
バグを確実に再現できますか?ブラウザー自動化または curl を使って再現してください。再現できない場合は、先に進む前に証拠をさらに集めてください。
5. コードを読む
症状から潜在的な原因まで、コードの実行経路をたどってください。Grep で関連箇所をすべて検索し、Read でロジックを理解してください。
出力: 根本原因の仮説を述べてください。何が、なぜ問題なのかを具体的かつ検証可能な主張として示します。
フェーズ 2:パターン照合
バグが Lightdash の既知のパターンに当てはまるか確認してください。
| パターン | 兆候 | 調査箇所 |
|---|---|---|
| 権限エラー | 403 Forbidden | projectMemberAbility.ts、organizationMemberAbility.ts の CASL アビリティ |
| クエリの遅延/N+1 | 応答が 1 秒超、DB スパンが多数 | maple trace <id> のスパンツリー — db.* スパンを数え、ループを確認 |
| 古い Explore キャッシュ | 古い列/メトリクスが表示される | cached_explores テーブル、CompileService |
| マイグレーションの問題 | 列が見つからない、スキーマが一致しない | packages/backend/src/database/migrations/、ロールバックを確認 |
| スケジューラージョブの失敗 | ジョブが実行されない、停止している | PM2 スケジューラーログ、graphile_worker.jobs テーブル |
| フロントエンドの古いデータ | ミューテーション後も UI に古いデータが表示される | TanStack Query のキャッシュ無効化、queryClient.invalidateQueries を確認 |
| 競合状態 | 発生が断続的、タイミングに依存する | 共有状態への同時アクセス、await の不足 |
| サービス間のファイルの問題 | ワーカー/ヘッドレスでファイルが見つからない | ローカルファイルシステムではなく、FileStorageClient を介して S3 を使用する必要がある |
| 設定の不整合 | ローカルでは動作するが、CI/ステージングでは失敗する | 環境変数、.env.development.local とコンテナー環境変数の違い |
| null の伝播 | TypeError、プロパティを読み取れない | オプション値に対するガードの不足、Knex の .first() が undefined を返す |
以下も確認してください:
- 同じ領域で過去に修正があったか
git logで確認します。同じファイルでバグが繰り返し発生するのは、アーキテクチャ上の問題の兆候です。 - 問題が common、backend、frontend のどの層にあるかを確認します。層を誤って特定すると時間を浪費します。
フェーズ 3:仮説を検証する
修正を 1 つでも書く前に、仮説を検証してください。
-
確認: 一時的なログやアサーションを追加するか、Maple/PM2 を使って疑わしい根本原因を確認します。再現させ、証拠が一致するか確認してください。
-
誤りの場合: フェーズ 1 に戻ってください。証拠をさらに集めます。推測してはいけません。
-
3 回までのルール: 3 つの仮説が失敗したら、停止してください。ユーザーに次の選択肢を尋ねます:
- 新しい仮説で続ける(内容を説明する)
- 人によるレビューにエスカレーションする
- インストルメンテーションを追加し、次回発生時に捕捉できるよう待つ
フェーズ 4:修正する
根本原因を確認したら、次の手順に進みます。
-
症状ではなく、根本原因を修正します。 実際の問題を解消する、最小限の変更にしてください。
-
差分を最小限にします。 変更するファイル数と行数を最小限にしてください。隣接するコードをリファクタリングしてはいけません。
-
修正がなければ失敗し、修正があれば成功するリグレッションテストを作成してください。
-
関連するテストスイートを実行してください。出力を貼り付けます。
-
影響範囲を確認: 修正が 5 ファイルを超えて変更する場合は、一時停止し、続行する前にユーザーに確認してください。
フェーズ 5:検証と報告
元のバグのシナリオを再現し、修正されたことを確認してください。 これは必須です。
構造化されたデバッグレポートを出力してください。
DEBUG REPORT
════════════════════════════════════════
Symptom: [what the user observed]
Root cause: [what was actually wrong]
Fix: [what was changed, with file:line references]
Evidence: [test output, trace showing fix works]
Regression test: [file:line of the new test]
Status: DONE | DONE_WITH_CONCERNS | BLOCKED
════════════════════════════════════════
ステータスの定義:
- DONE — 根本原因を特定し、修正を適用し、回帰テストを作成して、テストに合格した
- DONE_WITH_CONCERNS — 修正済みですが、完全には検証できない(例:断続的に発生するバグ、ステージング環境での確認が必要)
- BLOCKED — 調査後も根本原因が不明で、ユーザーにエスカレーションした
前提条件
開発環境が実行中であることを確認してください。
/docker-dev # Start Docker services (postgres, minio, etc.)
pnpm pm2:start # Start all PM2 processes including Maple
pnpm pm2:status # Verify all processes are online
サービス:
- フロントエンド:http://localhost:3000
- API:http://localhost:8080
- Maple トレース UI:http://localhost:4320
ツールのリファレンス
サーバーログ(PM2)
pnpm pm2:logs # Stream all logs (Ctrl+C to exit)
pnpm pm2:logs:api # API server logs only
pnpm pm2:logs:scheduler # Background job scheduler logs
pnpm pm2:logs:frontend # Vite dev server logs
pnpm pm2:logs:maple # Maple tracing server logs
ブロッキングなしでログを表示する場合(最後の N 行):
pnpm exec pm2 logs lightdash-api --lines 20 --nostream
ログ形式
Lightdash のログには、関連付け用の 32 文字のトレース ID が含まれています。
[700aa55e784a437aa97de9b8c5c3ed3a] GET /api/v1/health 200 - 37 ms
[4d40816e5a7d433e88f99008de5f4be5] GET /api/v1/user/login-options 200 - 2 ms
maple trace に 32 文字の ID 全体を渡すと、リクエストを表示できます。
トレースの検索(Maple CLI)
Maple のローカルモードでは、埋め込み ClickHouse にトレース、ログ、メトリクスが保存され、maple CLI を通じて公開されます。各コマンドでは、対象期間として --since <30m|1h|24h|7d> を指定します。出力は JSON 形式です。対象を絞るには jq をパイプでつなぎます。
--format table は、フラットな行セット(services、query)にのみ適用されます。他のコマンドではその旨が示され、JSON にフォールバックします。
シェルごとに対象を一度設定してください。CLI のデフォルトはポート 4318 で、各ワークツリーはそれぞれのスロットポートで独自のサーバーを実行します。
export MAPLE_LOCAL_URL="http://127.0.0.1:${MAPLE_PORT:-4320}"
サービス一覧の表示
maple services --format table
サービスごとのスループット、エラー率、P95 レイテンシ。API は $LD_INSTANCE_ID(デフォルトは lightdash)として、ワーカーは $LD_INSTANCE_ID-scheduler として報告されます。
最近のトレース一覧の表示
maple traces --since 5m | jq '.traces[] | {traceId, spanName, durationMs}'
maple traces --since 1h --errors --min-duration-ms 500
maple slow-traces --since 15m
フィルター:--span-name <substr>、--http-method、--errors、--min-duration-ms、--max-duration-ms、--service、--limit。
トレースの詳細を取得
maple trace 700aa55e784a437aa97de9b8c5c3ed3a
トレースに関連付けられたログと、完全なスパンツリーを返します。
エラーを検索
maple errors --since 30m # grouped by fingerprint
maple error <fingerprint-hash> # sample traces + timeseries
ログを検索
maple logs --since 5m --severity ERROR
maple logs --trace-id 700aa55e784a437aa97de9b8c5c3ed3a
maple logs -q "compile" --since 1h
生 SQL による確認
maple query "SELECT ServiceName, count() FROM traces GROUP BY ServiceName"
ブラウザーのデバッグ(Chrome DevTools MCP)
ブラウザーの自動化には、Chrome DevTools MCP ツールを使用します。
ページを開く
mcp__chrome-devtools__new_page with url: "http://localhost:3000/login"
mcp__chrome-devtools__navigate_page with url: "http://localhost:3000", type: "url"
スナップショットを取得
mcp__chrome-devtools__take_snapshot
各要素に一意の uid 識別子が付いた、アクセシビリティツリーに基づくページのテキストスナップショットを返します。
要素を操作
mcp__chrome-devtools__click with uid: "1_5"
mcp__chrome-devtools__fill with uid: "1_4", value: "[email protected]"
mcp__chrome-devtools__hover with uid: "1_3"
スクリーンショット
mcp__chrome-devtools__take_screenshot
mcp__chrome-devtools__take_screenshot with fullPage: true
mcp__chrome-devtools__take_screenshot with filePath: "/tmp/debug.png"
コンソールとネットワーク
mcp__chrome-devtools__list_console_messages
mcp__chrome-devtools__list_network_requests
mcp__chrome-devtools__get_network_request with reqid: 123
ページ管理
mcp__chrome-devtools__list_pages
mcp__chrome-devtools__select_page with pageId: 1
mcp__chrome-devtools__close_page with pageId: 2
データベースの調査
# Check table schema
psql -c "\d <table_name>"
# Query data directly
psql -c "SELECT * FROM <table> WHERE <condition> LIMIT 5;"
# Check scheduler jobs
psql -c "SELECT id, task_identifier, attempts, last_error FROM graphile_worker.jobs WHERE last_error IS NOT NULL LIMIT 10;"
トレース属性(ワイドイベント)
トレースには、タイミング以外のコンテキスト属性も含まれます。
| 属性 | 例 | 説明 |
|---|---|---|
http.route | /api/v1/projects/:projectUuid | ルートパターン |
http.status_code | 200 | レスポンスステータス |
http.method | GET | HTTP メソッド |
sentry.op | db、http.server | 操作の種類 |
db.system | postgresql | データベースの種類 |
よくあるデバッグシナリオ
| 症状 | 確認事項 |
|---|---|
| 401 Unauthorized | トレースの認証ミドルウェアを確認し、セッション/JWT のスパンを確認します |
| 403 Forbidden | トレース属性でユーザーの権限を確認し、CASL の権限を確認します |
| 404 Not Found | ルートが存在することを確認し、リソース検索のスパンを確認します |
| 400 Bad Request | 検証エラーがないか、トレース/エラーログを確認します |
| 応答が遅い | 遅い db.* や外部呼び出しがないかスパンの内訳を確認し、N+1 がないか db スパンの数を確認します |
| 結果が空 | クエリパラメーターを確認し、db クエリのスパンを確認します |
| 500 Server Error | search_errors を使用してスタックトレースとコンテキストを確認します |
| UI が更新されない | TanStack Query の開発ツールを確認し、ミューテーション後にキャッシュが無効化されていることを確認します |
| スケジューラーが実行されていない | pnpm pm2:logs:scheduler を確認し、graphile_worker.jobs テーブルをクエリします |
クイックコマンドリファレンス
| 操作 | コマンド |
|---|---|
| すべてのログを表示 | pnpm pm2:logs |
| API ログを表示(ブロックなし) | pnpm exec pm2 logs lightdash-api --lines 20 --nostream |
| プロセスの状態を確認 | pnpm pm2:status |
| API を再起動 | pnpm pm2:restart:api |
| 最近のトレース | maple traces --since 5m |
| トレースの詳細 | maple trace <full-trace-id> |
| 最近のエラー | maple errors --since 5m |
| ブラウザーのスナップショット | mcp__chrome-devtools__take_snapshot |
| Maple トレース UI を開く | http://localhost:4320 |
エージェント間の検証
別の AI エージェントを使って調査結果を検証し、結論に異議を唱え、独立した証拠を得てください。これは行き詰まったときだけに行うものではありません。分析が確かなものになるよう、デバッグの過程で積極的に検証を求めてください。
環境を検出する
which claude 2>/dev/null && echo "HAS_CLAUDE=true" || echo "HAS_CLAUDE=false"
which codex 2>/dev/null && echo "HAS_CODEX=true" || echo "HAS_CODEX=false"
Claude の場合 → Codex に尋ねる
codex exec "Given this context from a Lightdash debugging session:
<context>
[paste relevant logs, traces, error messages, or code snippets]
</context>
<question>
[your specific question — e.g., 'Does this trace confirm that the query cache is being bypassed?' or 'Given this stack trace, is my conclusion that the middleware short-circuits before auth correct?']
</question>"
Codex の場合 → Claude に尋ねる
claude -p "Given this context from a Lightdash debugging session:
<context>
[paste relevant logs, traces, error messages, or code snippets]
</context>
<question>
[your specific question]
</question>"
相談するタイミング
- 仮説を検証する:根本原因を結論づける前に、証拠が自分の説を裏付けているか、別の説明がないかを他方のエージェントに尋ねます
- データの解釈を確認する:トレース、ログ、クエリの出力を読む際に、正しく読み取れているかを確認します
- 修正案に異議を唱えてもらう:コード変更を提案する前に、その修正が根本原因に対処しているのか、それとも症状を隠しているだけなのかを尋ねます
- 複雑なロジックを相互確認する:問題が複数のシステム(フロントエンド + API + データベース + 権限)に関わる場合は、連携について独立した見解を得ます
- 結論を裏付ける:ユーザーに「X が原因です」と伝える前に、別の視点からも同意が得られるか確認します。同意が得られない場合は、その相違を明らかにします
ガイドライン
- タイムアウトを 5 分に設定する:Codex の応答には時間がかかることがあります。Bash ツール経由で
codex execを実行する場合は、早期終了を避けるため、Bash のタイムアウトを 300000ms(5 分)に設定してください。codex exec自体に--timeoutを渡してはいけません。このフラグには対応していません。 - 具体的に伝える:曖昧な説明だけでなく、実際のエラー、トレース出力、コードスニペットを含めます
- 単に回答を求めるのではなく、検証を依頼する:「この証拠は、X という結論を裏付けていますか?」のほうが、「何が問題ですか?」より適切です
- 現在の仮説を伝える:最初から調査をやり直すのではなく、他方のエージェントが仮説を確認したり、異議を唱えたりできるようにします
- すでに否定した可能性も伝える:調査の重複を避け、相談に集中できるようにします
- 必ずユーザーに報告する:別のエージェントに相談した場合は、そのことをユーザーに伝えます。何を尋ね、相手が何を見つけ、自分がその評価に同意するかを要約します。意見が異なる場合は、それぞれの見解と根拠となる証拠を示します。別のエージェントに相談したことをユーザーが知らないままにしてはいけません。
テストユーザーの認証情報
認証が必要なフローをテストする場合:
- メールアドレス:[email protected]
- パスワード:demo_password!
API アクセス(パーソナルアクセストークン)
API 呼び出しでは、Chrome DevTools MCP 経由で fetch() を使うより、この方法を優先してください。 PAT を使った curl はより高速で信頼性が高く、ブラウザーセッションやページコンテキストも必要ありません。ブラウザー MCP ツールは、UI 操作と視覚的なデバッグにのみ使用してください。
シードデータによって開発用 PAT が自動的に用意されます。ブラウザーログインなしで直接 API を呼び出す場合に使用してください。
# Source the env file to get LDPAT and LIGHTDASH_API_URL
source .env.development.local
# Example: list projects
curl -s -H "Authorization: ApiKey $LDPAT" "$LIGHTDASH_API_URL/api/v1/org/projects" | jq
# Example: get user info
curl -s -H "Authorization: ApiKey $LDPAT" "$LIGHTDASH_API_URL/api/v1/user" | jq
トークン(ldpat_deadbeefdeadbeefdeadbeefdeadbeef)は @lightdash/common の SEED_PAT で定義され、データベースのシード時に挿入されます。これは管理者ユーザー([email protected])に属し、有効期限はありません。