このページでは、uwsgi から実行される Django のアプリを VSCode からデバッグ(ステップ実行)するための方法について解説していきます。
解説は「Django の開発用ウェブサーバーから実行されるアプリのデバッグ環境」が既に VSCode に構築されていることを前提として進めさせていただきますので、この環境が構築されていない場合は事前に下記ページをご参照いただければと思います。
「Django の開発用ウェブサーバーから実行されるアプリのデバッグ環境」とは、要は Python のデバッガーから manage.py を実行してデバッグを開始する環境です。
上記ページで紹介するデバッグ環境が整っていれば、VSCode の設定に限れば、後は launch.json の変更を行うだけで uwsgi から実行される Django のアプリもデバッグできるようになります。
ただ、実際に環境を整えてデバッグを試してみた感触としては、正直ちょっと動作が不安定かなぁという印象です…。
また、デバッグできることが確認できたのは Mac のみです(Windows では試していない)。なので、Mac 上でのデバッグを行うことを想定した解説になっています。
少なくとも Raspberry Pi OS の場合は上手く動作させられませんでした…。もし上手く動作させることができれば記事を更新して追記したいと思います。
上手く動作しない OS や不安定な面はあるものの、Mac で動作確認できたということは方向性は合ってると思うんですよね…。なので、他の OS を利用されている方であっても、uwsgi から実行される Django のウェブアプリのデバッグ環境を構築したいという方には少なくとも参考にはなると思います。
Contents
このページで構築していくデバッグ環境
まず、先ほども紹介した下記ページのデバッグ環境と、今回このページで構築していく環境との違いを説明しておきます。
前述でも少し触れましたが、上記ページで紹介しているデバッグ環境と今回構築していくデバッグ環境との違いは、VSCode の設定に関して言えば launch.json のみとなります。
以前に紹介したデバッグ環境
まず、上記ページで解説しているのは、「Django の開発用ウェブサーバー」からアプリを実行することを前提としたデバッグ環境の構築方法になります。
python manage.py runserver を実行すると、Django の開発用ウェブサーバーが起動し、その開発用ウェブサーバーからアプリ(views.py の関数など)が実行されることでアプリが動作することになります。

上記ページで紹介しているデバッグ環境は、この「Django の開発用ウェブサーバーから実行される Django のウェブアプリ」のみをデバッグするためのものになります。
ただ、開発段階では python manage.py runserver を実行して Django の開発用ウェブサーバーを起動し、このウェブサーバーからアプリを実行することが多いので、上記ページで紹介しているデバッグ環境さえ構築できれば十分なことが多いと思います。
スポンサーリンク
このページで構築するデバッグ環境
その一方で、開発段階ではなく本番環境に移行する際には、Django の開発用ウェブサーバーからアプリを動作させるのではなく uwsgi などのアプリケーションサーバーからアプリが実行されることになります。
要は Django の開発用ウェブサーバーを利用せずに、本番用のウェブサーバー(Apache や Nginx など)を利用し、さらにウェブサーバーからアプリケーションサーバー(uwsgi など)を経由してアプリが実行されることになります。

前述の通り、最初に紹介したページで紹介しているのは Django の開発用ウェブサーバーからアプリを動作させることを前提としたデバッグ環境の構築方法ですので、上の図のような uwsgi からアプリが実行される場合には適用できません。
で、このページでは、上の図のような「uwsgi からアプリが実行される構成でも VSCode からアプリのデバッグが可能な環境」を構築するための手順を解説していきます。

このデバッグ環境が構築できれば、より本番環境に近い環境でのアプリのデバッグ(ステップ実行など)が VSCode から行えるようになるというメリットがあります。
前準備:uwsgi からアプリを実行する
念のため、uwsgi から Django で開発したアプリを実行させるための手順についても解説しておきます。
既に uwsgi から Django で開発したアプリを実行させる環境を構築済みの方は、次の uwsgi から実行されるアプリをデバッグする手順 までスキップしていただければと思います。
今回は、先ほど紹介したような本番環境を本格的に整えるのではなく、Apache や Nginx は用意せずに uwsgi のみを用意するようにしていきたいと思います。これでもウェブアプリを動作させることが可能です。

また、実際には試していないですが、Apache や Nginx から uwsgi を実行する環境に移行した際にも、今回紹介する手順と同様の手順でウェブアプリをデバッグすることが可能なはずです(いずれにしてもアプリは uwsgi と同じプロセス上で動作するため)。
ここからは、実際に手順を進めながら uwsgi からウェブアプリを動作させていきますので、事前に動作可能なウェブアプリを用意しておいてください(views.py の関数やメソッドが実行されるアプリであればどんなものでも良いです)。
uwsgi のインストール
まずは uwsgi のインストールを行いましょう!
uwsgi は pip からインストールすることが可能です。
ということで、下記コマンドをターミナルから実行して uwsgi をインストールしてください(必要に応じて python の部分は、いつも Python スクリプトを実行する際に使用しているコマンドに置き換えて実行してください)。
% python -m pip uninstall uwsgi
インストールが完了したら下記コマンドを実行してみてください。
% uwsgi --version 2.0.20
上記のようにバージョンが表示されれば uwsgi のインストール完了です!
コマンドを実行してもバージョンが表示されない場合、uwsgi への PATH が通っていない可能性が高いです。
uwsgi は python の実行ファイルと同じフォルダに存在するはずですので、そのフォルダに PATH を通しておく or 今後の uwsgi コマンドを絶対パスで指定して実行するようにしてください。
また、PATH の通し方は下記ページで解説していますので、こちらが参考になると思います。
スポンサーリンク
uwsgi の起動
続いて uwsgi を起動し、uwsgi からウェブアプリが実行されるようにしていきます。
これを実現するためには、下記の形式のコマンドを実行する必要があります。
% uwsgi --http :ポート番号 --module プロジェクト名.wsgi --chdir プロジェクトのフォルダパス
ポート番号
まず ポート番号 には、uwsgi がウェブブラウザからの接続を待ち受けるポート番号を指定します。
これには python manage.py runserver 実行時に指定しているポート番号と同じ番号を指定すれば良いです。もし実行時にポート番号を指定していない場合、デフォルト設定の 8000 がポート番号として指定されているはずですので、上記の ポート番号 にも 8000 を指定すれば良いです。
プロジェクト名 と プロジェクトのフォルダパス
プロジェクト名 と プロジェクトのフォルダパス については、デバッグしたい Django のアプリのプロジェクトに合わせて設定してください。
例えば下の図のように /Users/daeu/Documents/python というフォルダの中で startproject を実行して debug_test プロジェクトを作成している場合、プロジェクト名 には debug_test、プロジェクトのフォルダのパス には /Users/daeu/Documents/python/debug_test を指定することになります。

プロジェクトのフォルダパス に関しては、「manage.py が存在するフォルダのパス」と言った方が分かりやすいかもしれないです。絶対パス指定でも相対パス指定でも良いです。
要は、プロジェクト名 と プロジェクトのフォルダパス は startproject 実行時に作成される wsgi.py を指定するためのオプションとなります。
上記の例のようにオプションを設定する場合、uwsgi 実行時のコマンドは次のようになります。
% uwsgi --http :8000 --module debug_test.wsgi --chdir /Users/daeu/Docments/python/debug_test
エラーが出ていないか確認
コマンドを実行した際には、様々なメッセージが表示されると思います。
このメッセージの中でまず確認すべきことは、下記のようなメッセージが “表示されていない” ことです。これが表示されている場合は プロジェクト名 と プロジェクトのフォルダパス の設定がおかしい可能性が高いため、コマンドの引数を再度見直してみてください。
ModuleNotFoundError: No module named 'debug_app.wsgi'
アプリの動作確認
次はアプリの動作確認を行なっていきます。
もし既に python manage.py runserver 等で Django の開発用ウェブサーバーを立ち上げている場合は、事前にコマンドを終了させておいてください。
さて、先ほど実行したコマンドで uwsgi を起動すれば、uwsgi がウェブサーバーの役割を果たし、ウェブブラウザ等からリクエストがあった際に uwsgi からウェブアプリが実行されてウェブアプリが動作するようになります。
ということで、ウェブブラウザからリクエストを送信してみましょう!

いつもウェブアプリの動作確認を行なっている時と同様に、ウェブブラウザのアドレスバーに下記のような URL を指定してエンターキーを押せば良いです。
http://localhost:8000/app/
uwsgi を実行する際に ポート番号 に 8000 以外を指定した場合は、その指定した番号に合わせて上記 URL の 8000 部分を変更してください。
また、app の部分は urls.py の設定によって異なるため、ご自身の urls.py の設定に応じて変更してください。
ウェブブラウザにいつも通りのアプリの画面が表示されれば、uwsgi からのアプリの実行に成功したことになります。これで事前準備は完了です!
ただ、ここまでの手順はあくまでもデバッグ環境構築の用の簡易版のものになるので注意してください。前述の通り、本来であれば Apache や Nginx がウェブサーバーとして動作するはずですし、静的ファイルやアップロードファイルの扱いの設定等もスキップさせていただいています。
uwsgi の終了
動作確認ができれば一旦 uwsgi を終了させておきましょう!
uwsgi は、uwsgi を実行中のターミナルで control + c を同時押しすることで終了することができます。
スポンサーリンク
uwsgi から実行されるアプリをデバッグする手順
ここから本題の uwsgi から実行されるアプリをデバッグするための環境を構築していきます。
VSCode で操作を行なっていくため、VSCode を起動し、デバッグを行いたいアプリが存在するプロジェクトを開いておいてください。
launch.json に Attach 用のデバッグ構成を追加する
結論としては、下記の太字で示す Python: Attach using Process Id の構成を launch.json に追加するだけで、uwsgi から実行されるアプリのデバッグが可能になります。
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Attach using Process Id",
"type": "python",
"request": "attach",
"processId": "${command:pickProcess}",
"justMyCode": true
},
{
"name": "Python: Django",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/manage.py",
"args": [
"runserver"
],
"django": true,
"justMyCode": true
}
]
}
直接 launch.json に上記の太字部分をコピペして追加しても良いですし、VSCode を操作して自動的に追加することもできます。
自動的に追加する手順について解説しておくと(既に launch.json が存在することを前提とした解説になります)、まず VSCode のウィンドウ左側の 実行とデバッグ ボタンをクリックし、さらに上側のプルダウンメニューをクリックします。

すると、下の図のようにメニューが表示されるので、ここで 構成の追加... を選択します。

すると、下の図のような選択肢が表示されるはずなので、ここで Python を選択します(この選択肢の表示はスキップされる場合があるかも)。

さらに、コマンドパレットにデバッグ構成の選択肢が表示されますので、ここで Attach using Process ID を選択します。

以上の操作を行えば、前述で紹介した launch.json の Python: Attach using Process Id の構成が自動的に launch.json に追加されることになります。
前述の通り、上記の手順は launch.json が既に存在すること前提としたものとなります。launch.json の追加の仕方については下記ページで解説しておりますので、追加の仕方が分からない方はこちらをご参照ください。
追加した Attach 用のデバッグ構成の意味
uwsgi から実行されるアプリをデバッグするための準備は以上で完了です。
なので、あとは動作確認を行えば良いだけなのですが、念の為先ほど追加した構成 Python: Attach using Process Id の下記の設定項目について解説しておきます。
"request": "attach""processId": "${command:pickProcess}"
その他の設定項目については下記ページで解説していますので、詳しくはこちらを参考にしていただければと思います。
"request": "attach"
まず、"request" に "attach" を指定することで、起動中のプロセスにアタッチ(接続)してデバッグすることを実現しています。
プロセスとは簡単かつ大雑把にいえば “実行中のプログラム” で、コマンドやプログラムを実行することで起動されます(生成されると言った方が良いかも)。
"request" に "attach" を指定すれば、起動中のプロセス(既に実行中のプログラム)にアタッチし、そのプロセスの処理を停止させたりステップ実行させたりすることが可能になります。

"request" に指定できるもう1つの設定値には "launch" があります。"request" に "launch" を指定した場合、デバッガーからプロセスを起動し、その起動したプロセスをデバッグすることになります。
"type": "python" を指定している場合は、Python 用のデバッガーが python コマンドからスクリプトを実行することでプロセスを起動することになります。

下記ページで作成した launch.json の構成では "request" に "launch" を指定しているため、デバッガーから python manage.py runserver を実行してプロセスを起動し、その起動したプロセスをデバッグすることになります。
前述の通り、python manage.py runserver を実行すれば Django の開発用ウェブサーバーが起動し、そのウェブサーバーから同じプロセス上で Django のアプリが実行されることになるため、"request" に "launch" を指定すれば Django のアプリをデバッグすることが可能でした。

それに対し、uwsgi から Django のアプリを実行させる場合、uwsgi は Python スクリプトではないので "request" に "launch" を指定してデバッガーから起動させることができません。
なので、uwsgi をデバッガーから起動することなくデバッグできるように、"request" に "launch" ではなく "attach" を指定しています。"attach" を指定した場合、既に起動中のプロセスにアタッチしてデバッグを行うことが可能です。
uwsgi と Django のアプリは同じプロセス上で実行されますので、uwsgi にアタッチすれば Django のアプリにもアタッチすることになります。
ただし、"type": "python" を指定しているためデバッグできるのは Python スクリプト部分のみになります。
ただ、uwsgi の起動 で紹介したコマンドで uwsgi を起動した場合、ウェブブラウザ等からのリクエストがあった際には uwsgi から Django のウェブアプリが実行されます。そして、その Django のウェブアプリは Python スクリプトで作成されているため、Django のウェブアプリ自体はデバッグすることが可能になります。

なので、例えば views.py の関数の中にブレークポイントを設定しておけば、uwsgi からウェブアプリが実行されてその関数が呼ばれた際には、設定したブレークポイントで止めるようなことが可能です。もちろんそのあとは変数の中身を確認したり、ステップ実行したりすることも可能です。
全てのプロセスがアタッチできるとは限らないので注意してください
また、アタッチできたとしても、ステップ実行等を行うためにはデバッグしたいプログラムのソースコードが必要になります(C言語などの場合はさらにデバッグ情報も必要になる)
"processId": "${command:pickProcess}"
ただ、"request" に "attach" を指定した場合、どのプロセスにアタッチするかを指定する必要があります。この “どのプロセスにアタッチするか” をプロセス ID で指定できるように、構成に "processId" が用意されています。
"processId" には直接プロセス ID を指定することも可能ですが、"${command:pickProcess}" を指定した場合、デバッグ開始時に指定可能なプロセスの選択肢が表示され、その中から選択してアタッチ先のプロセスを指定することが可能になります。
今回の場合は、uwsgi のプロセス ID を "processId" に指定できるよう、デバッグ開始時に選択肢から uwsgi のプロセスを選択することになります。
スポンサーリンク
uwsgi から実行されるアプリをデバッグしてみる
では最後に uwsgi から実行されるアプリを実際にデバッグしてみましょう!
uwsgi を起動する
まずは uwsgi の起動 で紹介した下記の形式のコマンドを実行して uwsgi の起動を行なってください。
% uwsgi --http :ポート番号 --module プロジェクト名.wsgi --chdir プロジェクトのフォルダパス
uwsgi を起動すると、最後に下記のようなメッセージが表示されると思います。このメッセージの pid の右側に表示される数字が、以降の手順でアタッチするプロセスの ID となります(下記の場合は 47935)。この ID は念のため覚えておいてください。
spawned uWSGI worker 1 (and the only) (pid: 47395, cores: 1)
uwsgi にアタッチする
次に VSCode のウィンドウ左側の 実行とデバッグ ボタンをクリックし、さらに上側のプルダウンメニューをクリックします。そして、表示される構成の選択肢から Python: Attach using Process Id を選択します。

続いて、 先ほどクリックしたプルダウンメニューの左側にある デバッグの開始 ボタンをクリックします。

すると、アタッチ先のプロセスの選択肢が表示されますので、上側の入力フォームに uwsgi と入力してください。

uwsgi と入力して選択肢が1つに絞られたのであれば、その選択肢をクリックして選択してください。
uwsgi と入力しても、まだ選択肢が2つ以上存在する場合は、前述の uwsgi 実行時に確認したプロセス ID の選択肢をクリックして選択してください。選択すれば、画面が下の図のようなものに遷移し、デバッガーから指定した ID のプロセスへのアタッチの試行が行われます。

アタッチに成功した場合、下の図のような画面に遷移します。

ちょっと上の図だと分かりにくいかもしれませんが、デバッグ操作用のバーの一番右が四角のボタンから下記のようなコンセントのようなボタンに変化すれば、プロセスへのアタッチが成功したことになります。

ただ、私は Mac で確認しているのですが、どうも毎回アタッチに成功するわけではなく、時々下の図のようなメッセージが表示されてアタッチに失敗することがありました。

この場合は、一旦 uwsgi を終了してから uwsgi を起動する に戻り、uwsgi の起動からやり直すともしかしたら成功するかもしれません(uwsgi の再起動が必要かどうかは謎ですが、再起動からやった方が無難だと思います)。
起動するたびにプロセス ID は変化するので注意してください。
また、同様の手順を踏んでも Raspberry Pi OS では uwsgi へのアタッチは一度も成功しませんでした。そもそも他の普通の Python スクリプトへのアタッチもできなかったので何かしらの設定が別途必要なのかもしれないです…。
スポンサーリンク
アプリをデバッグする
アタッチに成功した場合は、あとは通常通りステップ実行とのデバッグを行うことが可能です。
まず、views.py の関数 or メソッドにブレークポイントを設定してください。
さらに、ウェブブラウザから URL の指定等によってウェブアプリを動作させてください。この際、ブレークポイントを設定した関数やメソッドが実行されるように URL を指定してください。
URL を指定すれば、ウェブブラウザからのリクエストを uwsgi が受け取って uwsgi から views.py の関数 or メソッドが実行され、ブレークポイントを通過する前にプログラムが停止するはずです。

ブレークポイントで停止できれば、後はいつも通りステップオーバーボタンやステップインボタンでプログラムをステップ実行することが可能です。
アタッチを解除したい場合は、デバッグ操作用のバーの一番右のコンセントみたいなボタンをクリックすれば良いです。

時々ですが、私の環境だとデバッグしている最中に下記のように Segmentation Fault が発生することがありました…。この場合はuwsgi を再起動して再度同じ手順を行う必要があります(bind error が発生する場合はゾンビプロセスが残っている可能性があるため、kill コマンド等でプロセスを終了させる必要があります)。
!!! uWSGI process 48700 got Segmentation Fault !!! Sat Apr 9 07:05:58 2022 - SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request /debug/ (ip 127.0.0.1) !!! *** backtrace of 48700 *** 0 uwsgi 0x0000000107ad030c uwsgi_backtrace + 44 1 uwsgi 0x0000000107ad0841 uwsgi_segfault + 49 2 libsystem_platform.dylib 0x00007fff206cdd7d _sigtramp + 29 〜略〜 26 Python 0x0000000107e70494 pythread_wrapper + 36 27 libsystem_pthread.dylib 0x00007fff206888fc _pthread_start + 224 28 libsystem_pthread.dylib 0x00007fff20684443 thread_start + 15 *** end of backtrace *** zsh: segmentation fault uwsgi --http :8000 --module debug_project.wsgi --chdir
まとめ
このページでは、uwsgi から実行される Django のアプリを VSCode からデバッグ(ステップ実行)するための方法について解説しました!
uwsgi から同じプロセス上で Django のアプリが動作するため、uwsgi にアタッチすることで uwsgi から実行される Django のアプリを VSCode からデバッグすることが可能になります。
これにより、より本番環境に近い状態での Django のアプリのデバッグを行うことができるようになります。
今回は Apache や Nginx を用意せずに動作させましたが、これらを利用する場合も uwsgi と Django のアプリは同じプロセス上で動作するはずですので、同様に uwsgi にアタッチすることでデバッグを行うことができると思います。
ただ、私が試した感じだと動作が不安定でしたし、OS によっては同じようにデバッグできないこともあったのでこの辺りは注意していただければと思います。
また、デバッグの種類には launch だけでなく attach も存在することは是非覚えておいてください!Django だけでなく他のプロセスから実行されるプログラムも結構ありますので、今後のデバッグで役に立つ可能性もあるかもしれないです!

