Skip to content

ブレークポイントデバッグ方法

Published: at 23:17

ブレークポイントデバッグガイド 🚀

Python で、ブレークポイントを設置してステップ実行できるデバッグ方法を説明します。

🛠️ 事前準備

1. 必要な拡張機能(VS Code)

以下の拡張機能をインストールしてください:

2. 環境の再起動

新しい設定を反映するため、Docker 環境を再起動:

docker-compose down
docker-compose up -d

🐍 Python(FastAPI)でのブレークポイントデバッグ

方法 1: VS Code リモートデバッグ (推奨)

1. Docker 環境の準備

Docker 環境が起動すると、自動的にデバッグサーバーがポート 5678 で起動します。

2. VS Code でデバッグセッションを開始

  1. F5 を押すか、「実行とデバッグ」パネルを開く
  2. 「Python: FastAPI (Docker)」設定を選択
  3. 「デバッグの開始」をクリック

3. ブレークポイントの設定

コードの左端の行番号をクリックして赤い点を設置:

# api/functions/user_controller/base.py
def check_admin(self, user_id: str = Depends(authenticate_user)) -> bool:
    breakpoint()  # ←ここにブレークポイント設置
    try:
        user = self.get_user(user_id)
        return user.is_admin  # ←ここにもブレークポイント可能
    except Exception as e:
        print(e)
        raise e

4. デバッグ実行

方法 2: Python pdb(コマンドライン)

1. pdb ブレークポイントの設置

# api/functions/user_controller/base.py
def get_user(self, user_id: str) -> User | None:
    import pdb; pdb.set_trace()  # ←ブレークポイント

    user_snapshot = self._get_user_snapshot(user_id)
    if not user_snapshot.exists:
        return None
    return User(**user_snapshot.to_dict())

2. Docker ログでデバッグ

# 別のターミナルで
docker-compose logs -f api

# pdbが起動したら以下のコマンドが使用可能:
# n (next): 次の行へ
# s (step): 関数内部に入る
# c (continue): 続行
# l (list): 現在のコードを表示
# p variable_name: 変数の値を表示
# pp variable_name: 変数の値を整形して表示

方法 3: デバッグヘルパー関数の使用

# api/functions/user_controller/base.py
from debug_helper import debug_breakpoint, debug_function, debug_print, DebugContext

@debug_function  # 関数の入力/出力を自動ログ
def get_user(self, user_id: str) -> User | None:
    debug_print("ユーザー取得開始", user_id)

    with DebugContext("ユーザースナップショット取得"):
        user_snapshot = self._get_user_snapshot(user_id)

        if not user_snapshot.exists:
            debug_print("ユーザーが存在しません")
            return None

        debug_breakpoint()  # ←ここでブレークポイント
        return User(**user_snapshot.to_dict())

実践例: 認証機能のデバッグ

# api/functions/user_controller/auth.py
from debug_helper import debug_breakpoint, debug_print

def authenticate_user(token: str = Depends(oauth2_scheme)) -> str:
    debug_print("認証開始", token[:20] + "...")

    try:
        # ブレークポイントを設置
        debug_breakpoint()

        decoded_token: dict = auth.verify_id_token(token, app=settings.firebase_app)
        user_id = decoded_token.get("uid", None)

        debug_print("認証成功", user_id)
        return user_id

    except FirebaseError as e:
        debug_print("認証エラー", str(e))
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Bearer"},
        )

🖥️ Next.js(フロントエンド)でのブレークポイントデバッグ

方法 1: VS Code デバッグ

1. サーバーサイドデバッグ

// front/src/hooks/users.ts
const getUsers = async (): Promise<DummyUserType[]> => {
  debugger; // ←ブレークポイント

  const token = getAuthToken();

  const { data } = await axios.get("/api/proxy/users", {
    headers: {
      ...(token && { Authorization: `Bearer ${token}` }),
    },
  });

  debugger; // ←レスポンス後のブレークポイント
  return data;
};

2. VS Code でのデバッグ実行

  1. F5 を押す
  2. 「Next.js: debug server-side」を選択
  3. ブレークポイントが設置された行で実行が停止

方法 2: Chrome DevTools

1. ブレークポイントの設置

// front/src/app/[locale]/(main)/dashboard/page.tsx
export default function HomePage() {
  const { data: users, isLoading, isError } = useGetUsers()

  useEffect(() => {
    debugger; // ←ブレークポイント

    console.log("ユーザーデータ:", users)
    console.log("ロード状態:", isLoading, isError)
  }, [users, isLoading, isError])

  return (
    // JSX
  )
}

2. Chrome DevTools でのデバッグ

  1. ブラウザでページを開く
  2. F12 で開発者ツールを開く
  3. Sources タブへ
  4. ブレークポイントで実行が停止
  5. Step Over, Step Into, Step Out でステップ実行

方法 3: React DevTools

  1. React Developer Tools 拡張機能をインストール
  2. ブラウザで ⚛️ タブを開く
  3. コンポーネントの状態やプロパティを確認
  4. プロファイラーでパフォーマンス分析

🔄 統合デバッグシナリオ

シナリオ 1: API 通信エラーの調査

1. フロントエンドにブレークポイント設置

// front/src/hooks/users.ts
const getUsers = async (): Promise<DummyUserType[]> => {
  debugger; // ←リクエスト前

  try {
    const token = getAuthToken();
    const { data } = await axios.get("/api/proxy/users", {
      headers: {
        ...(token && { Authorization: `Bearer ${token}` }),
      },
    });

    debugger; // ←成功時
    return data;
  } catch (error) {
    debugger; // ←エラー時
    throw error;
  }
};

2. API プロキシにブレークポイント設置

// front/src/lib/apiHelper.ts
export function createProxyHandler({ method, apiPath }: ProxyHandlerOptions) {
  return async function (request: NextRequest) {
    debugger; // ←リクエスト受信時

    const API_URL = process.env.API_URL;
    const backendUrl = `${API_URL}${apiPath}`;

    try {
      const response = await fetch(backendUrl, fetchOptions);
      debugger; // ←レスポンス受信時

      if (!response.ok) {
        debugger; // ←エラーレスポンス時
        // エラーハンドリング
      }

      const data = await response.json();
      return NextResponse.json(data);
    } catch (error) {
      debugger; // ←例外発生時
      // エラーハンドリング
    }
  };
}

3. Python API にブレークポイント設置

# api/routers/route_user_controller.py
@router.get("/users/", response_model=list[User])
def endpoint_get_list_users(user_id=Depends(authenticate_user)):
    debug_breakpoint()  # ←エンドポイント開始時

    # ユーザーが管理者かどうかのチェック
    if not user_controller.check_admin(user_id):
        debug_breakpoint()  # ←権限エラー時
        raise HTTPException(status_code=403, detail="権限がありません。")

    debug_breakpoint()  # ←データ取得前
    return user_controller.get_users

シナリオ 2: 認証フローの調査

1. ログイン処理の開始

// front/src/app/[locale]/(top)/login/page.tsx
const login = async () => {
  debugger; // ←ログイン開始

  try {
    await loginWithEmployeeId(employeeId.trim());
    debugger; // ←ログイン成功
    router.push(PATHS.DASHBOARD);
  } catch (error) {
    debugger; // ←ログイン失敗
    setError(error instanceof Error ? error.message : "ログインに失敗しました");
  }
};

2. 認証 API

# api/routers/route_auth_controller.py
@router.post("/auth/employee-login", response_model=EmployeeLoginResponse)
async def employee_login(request: EmployeeLoginRequest):
    debug_breakpoint()  # ←認証開始

    employee_id = request.employee_id.strip()

    if not validate_employee_id(employee_id):
        debug_breakpoint()  # ←バリデーションエラー
        raise HTTPException(status_code=400, detail="無効な社員番号")

    try:
        custom_token = auth.create_custom_token(uid=employee_id)
        debug_breakpoint()  # ←トークン生成成功

        return EmployeeLoginResponse(
            custom_token=custom_token.decode('utf-8'),
            employee_id=employee_id
        )
    except Exception as e:
        debug_breakpoint()  # ←トークン生成失敗
        raise HTTPException(status_code=500, detail=f"認証エラー: {str(e)}")

🎯 デバッグのベストプラクティス

1. 段階的なブレークポイント設置

def complex_function(data):
    # 入力チェック
    debug_breakpoint()  # ←入力データ確認

    # 処理1
    result1 = process_step1(data)
    debug_breakpoint()  # ←処理1の結果確認

    # 処理2
    result2 = process_step2(result1)
    debug_breakpoint()  # ←処理2の結果確認

    # 最終結果
    final_result = finalize(result2)
    debug_breakpoint()  # ←最終結果確認

    return final_result

2. 条件付きブレークポイント

def handle_users(users):
    for user in users:
        # 特定の条件でのみブレークポイント
        if user.id == "debug_target_user":
            debug_breakpoint()

        # 処理続行
        process_user(user)

3. デバッグ情報の構造化

def debug_api_call(method, url, data=None):
    debug_info = {
        "method": method,
        "url": url,
        "data": data,
        "timestamp": datetime.now(),
        "thread_id": threading.current_thread().ident
    }

    debug_breakpoint()  # ←構造化された情報で停止
    return debug_info

🛡️ 本番環境への注意事項

1. デバッグコードの削除

# 本番環境では削除すること
if os.getenv("DEBUG") == "true":
    debug_breakpoint()

2. 環境変数での制御

# .env
DEBUG=false  # 本番環境では false

# コード内
if os.getenv("DEBUG", "false").lower() == "true":
    import debugpy
    debugpy.listen(("0.0.0.0", 5678))

3. ログレベルの調整

# 開発環境
logging.basicConfig(level=logging.DEBUG)

# 本番環境
logging.basicConfig(level=logging.WARNING)

📚 追加リソース

VS Code ショートカット

Chrome DevTools ショートカット

pdb コマンド


これで、PHP の Xdebug と同等のブレークポイントデバッグ機能を、Next.js と Python FastAPI の両方で使用できるようになります!