Perl のリモートデバッグ体験の模索

最近,Perl の開発してるときに DDP とかでダンプするのが億劫になってきたのと, 動かしつつデバッガーでブレークポイント置くみたいな体験できないかな,という気持ちが高まってきたので, そういうことができないか,というのを模索してみることにした.

前提

目下使っているエディタは VSCode である. これのデバッガー機能が使えればナイスな感じがしてくる.

環境は Docker で構築されている.Plack で動いている.Plack は正直わかってない.

ただ,調べてもあまり Perl + VSCode のリモートデバッグでやったぜみたいなものはあまり出てこない.

素直に Perl Debug

素直に Perl Debug という拡張を使ってみることにした

1. Perl Debug のインストール

marketplace.visualstudio.com

2. Devel::vscode の導入

あとは Devel::vscode も導入しておく:

metacpan.org

3. アプリケーション側の設定

ブートストラップ的なコードを起動する際に,PERLDB_OPTS にリモートのどこにアクセスするのか指定しておく.今回は Docker のコンテナ内からホストなので host.docker.internal:9875 とかにしておく.

あとは Devel::vscode をロードしておくために -d:vscode=fork=break とかを指定しておく.これは先述した Perl Debug のページに説明がある:

PERLDB_OPTS="RemotePort=host.docker.internal:9875" carton exec -- perl -d:vscode=fork=break "path/to/bootstrap.pl" "$@"

4. launch.json の設定

VS Code 側の launch.json はあわせてこうしておく:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Remote Perl",
            "type": "perl",
            "port": 9875,
            "request": "launch",
            "root": "${workspaceRoot}",
            "program": "${workspaceRoot}/${relativeFile}",
            "console": "remote",
            "sessions": "watch",
            "debugLog": true,
            "debugRaw": true,
            "stopOnEntry": true
        
        }
    ]
}

コンテナ内ではアプリケーションコードは /app/ 以下に置いていて,ホスト側のワークスペースでのパスと微妙に対応しないので,シンボリックリンクをはっておく.

これで 9875 番で待機している VS Code につないでくれるはずだ.

5. おもむろにデバッグ

と,待っていたら,とりあえずスクリプトの先頭で止まってくれた:

f:id:mangano-ito:20200313203248p:plain

しばらく待ってるとコールスタックが山盛り積まれはじめた:

f:id:mangano-ito:20200313205145p:plain f:id:mangano-ito:20200313205945p:plain

先頭では止まることができるけど,それ以降ロードされたコードで止まれないみたいな感じになっている.なので,肝心のアプリケーション側のコードで止まれない.

デバッグコンソールを見ていると vscode: new loaded source (ロードされたソースへのパス) とは出てきている.

Perl Debug のコードだとこの辺りだろうか.新しく読み込まれたソースファイルをローズするところがうまくいかない感じがしている:

vscode-perl-debug/adapter.ts at 8778e42e4f3b85f9732d82d9559a38eda61095b0 · raix/vscode-perl-debug · GitHub

vscode-perl-debug/adapter.ts at 8778e42e4f3b85f9732d82d9559a38eda61095b0 · raix/vscode-perl-debug · GitHub

といったところでうまく行かなすぎて頓挫した.Perl Debug 自体をデバッグして追っていけばなにか分かるかもしれないが元気が出なかった.

あとfork しているあたりが不穏で,そこからうまく行ってなさそうな気もしている.

DBGp

もうひとつ見つけた:

metacpan.org

これは DBGp というプロトコルを使ってデバッグできるようにしてくれるもの,ということで,DBGp というのは PHPデバッグに使われている xdebugプロトコルである.

xdebug.org

xdebug はリモート側で動いている PHP から クライアントのデバッガーに対してコネクションをはってデバッグするというものになっている.

これにのっとるということで,いわば xdebugPerl 版のアダプタみたいになっているようだ.

ただ VSCode で DBGp に対応してるデバッグ拡張が PHP Debug しかなくて,これでうまくいくのかが不安しかない:

marketplace.visualstudio.com

DBGp トライ

さっそく使ってみようということで,やることは以下:

  1. Plack::Middleware::DBGp 追加
  2. Plackbuilder のところで use してコネクションの情報を設定しておく
  3. PHP Debug 拡張を入れておく
  4. launch.json にデバッガーの設定を追加
  5. おもむろにデバッグをはじめる

1. cpanfile にいれる

requires 'Plack::Middleware::DBGp';

2. use する

use Plack::Middleware::DBGp (
    remote_host => 'host.docker.internal:9000',
);
use Plack::Builder;

# ...

builder {
    # ...
    enable 'DBGp';
    $app;
};

4. launch.json 設定

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "php",
            "request": "launch",
            "name": "DBGp",
            "program": "${workspaceFolder}/${relativeFile}",
            "pathMappings": {
                "<rootOnRemote>/": "${workspaceFolder}/"
            },
            "stopOnEntry": true,
            "port": 9000,
        }
    ]
}

5. おもむろにデバッグをはじめる

ブレークポイント置いて待ってたけど

f:id:mangano-ito:20200313190802p:plain

まったく始まる気配ゼロ. 大失敗.

DBGp デバッグデバッグ

しかたないのでコネクションが来てるかだけでも確認してみる. ということで,WiresharkTCP 9000 番に DBGp っぽいのが来てるか確認することに.

xdebug.org

DBGpプロトコルXML を投げつけられて始まるので,XML が投げつけられてきているか確認すればよさそう.

f:id:mangano-ito:20200313191007p:plain

見た感じでは,XML は投げつけられてきている.

そもそも VS Code でできるのか

当初から脳裏によぎってたように PHP Debug の拡張では難しいのではないか,という疑問がある.

ということでモジュールのページの確認がとれてる拡張のリストに名前のあった Sublime Text のプラグインで確認してみた:

f:id:mangano-ito:20200313195406p:plain

コネクションは来た.けど,それ最初以降進めなくて詰んだ.

IntelliJ IDEA

qiita.com

この記事を参考に IntelliJ IDEA でやってみたけど, これでも最初のところでは止まるけど,それ以降ロードされたものでうまく行かなかった.

ので,なにかが決定的に欠けててうまく行ってない説が濃厚.

結論

盛大に頓挫した.まったくできない,とかではなくて,微妙にできてるのがたちが悪くて諦めきれない感じなっている.Perl 力が低くて勘所がわからないのも関係してそうな気がしている.

fork しているあたりでうまく行ってない説がある.ふんわりとそこが境界になっている気がしている.

なので,スキをみて試行錯誤したい所存だけど,この検証だけでも結構時間がかかってしまって,非常に精神力を必要とするものになっている.

他のフレームワーク

余談として Laravel とかはフレームワーク側でがんばって,ルーティングとか SQL のトレース情報をページ上なり Chrome の拡張なりで確認できるものがあったりする:

qiita.com

github.com

Perl でもお手製で Socket.IO とかなんなりの手段を使って各種トレースを投げつけるようにすれば,こういうこともできたりするだろうな,と夢想したりした.