morimorihogeです。涼しくなってようやく生きていける感じになって何よりです。
今回はruby/debugに新しく導入されたChrome Devtools連携リモートデバッグ機能を動かしてみたので、そちらを紹介してみようと思います。
ことの起こり
新しいRuby標準デバッガとして開発が進んでいるruby/debugですが、先日こんなTweetがありました。
debug.gem and Chrome browser integration.
Thanks Ono-san! pic.twitter.com/3aUdH2zbEo— _ko1 (@_ko1) October 14, 2021
なにこれすごくない!?と思い、今回の記事を書くに至りました。
動きとしては、デバッガのコンソールで open chrome
コマンドを実行するとURLが表示され、そのURLにChromeでアクセスすると、Chrome搭載のChrome Devtools(JavaScriptデバッグなどで使えるやつ)を使ってRubyのデバッガにアタッチできる、というもののようです。発想がすごい。
今回はこれを普段使っているRailsアプリで実際に使ってみよう、という話になります。
まずは動作確認
まずは最もシンプルな形で動かしてみましょう。今回の動作環境はWindows 10 WSL2上のUbuntu環境ですが、macOSでも同じことができるはずです。
以下のような sample.rb
を用意します。 debugger
がデバッガ呼び出しに当たります。
require 'debug'
test_var = 'test'
debugger
そうしたら、debug gemをインストールして実行します(ruby 3.0.2p107で動作確認していますが、2.7等でも動作します)。
$ gem install debug
$ ruby sample.rb
すると、下図のように debugger
部分でコードが停止し、rdbgコンソールが開きます。
ここで open chrome
命令を実行すると、devtools://
で始まるURLが表示されます。
このURLにアクセスするとChromeが開発者コンソールの画面を開きますので「Sources」タブを開いてみましょう。
はい。いい感じにデバッガが開きました。右上の方にstep over他一般的なデバッガ用の操作ボタンがあるので、ソースを見ながらこの辺りを見ていくことができます。
また「Console」タブに移動すると、デバッガが停止している状態のコンテキストで任意のRubyコードを実行できます。
ChromeのデバッグコンソールでRubyのコードを動かせる、というところでなんか楽しくなってきましたね 🎉
Railsで動かす: テストコード編
さて、うまいこと動いたので次は手持ちのRailsのコードでやってみましょう。
※今回普通に手元の業務で使ってるコードでやったのでモザイク多めですが、それだけ普通のRailsプロジェクトでももう使えると思っていただければ幸いです
まずはbyebugの代わりにdebug gemに入れ替えるため、Gemfileを編集します。Bye-bye buybug!今までありがとう!
group :development, :test do
# gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'debug'
あとは普通にbundle
しましょう。
ローカルでrspecなどのテストコードを動かしている場合、もうあとはデバッガ起動したい部分にdebugger
を埋め込み、open chrome
するだけで対応できます。
一方で、使っている環境がDockerを使っている場合、追加の設定が必要になります。
open chrome
コマンドはデフォルト設定では127.0.0.1、ポートは任意でLISTENするようになっていますが、これだとローカルのブラウザ環境からアクセスするのにはうまくいきません。
docker-composeコマンドでRailsコンテナに入ってrspecなどの実行を行っている場合には、以下のようなコマンドでコンテナを立ち上げましょう。
これでコンテナ外からruby/debugの開いたポートにアクセスすることができるようになります。
docker-compose run --rm -p '23456:23456' \
-e RUBY_DEBUG_HOST=0.0.0.0 \
-e RUBY_DEBUG_PORT=23456 \
rails bash
この状態でdebugger
を含むテストを実行し、開いたrdbgコンソールからopen chrome
すると、以下のように指定したホスト:ポートでLISTENしてくれます。
あとは先ほどと同じようにアクセスしますが、Windows/WSL2環境ではChromeで開く際にURL末尾のホストIPを0.0.0.0から127.0.0.1にする必要がありました。
これは、アプリケーションコンテナからは 0.0.0.0:23456
でLISTENしていますが、ホストからはコンテナに繋ぐ必要があるためかなと思うのですが、docker ps
の結果では 0.0.0.0:23456->23456/tcp
で開いているようにもなっており、WSL2のポート開放周りの問題というか仕様?かもしれません。
というわけで、attachできました。sample.rbの場合と同様に操作可能です。
step intoでライブラリコードに潜っていくことももちろんできます。
Consoleタブでputsするとちゃんとrpsec側の実行中コンソールに出ます。
Railsで動かす:Railsサーバー編
さて、今度は実際に動かしているRailsサーバー中でデバッガをアタッチしてみます。
まず、pumaを使っている場合(恐らく現代の大多数のRails)、少なくとも現行のdebugバージョン(1.3.1)だとmultiple worker環境でうまく動かない(後述)ようなので、puma.rbを修正する、または環境変数WEB_CONCURRENCYを1に指定します。
# config/puma.rb の該当行をよしなに編集する
# Worker数を1プロセスに指定(threadsは複数でも動作するようだ)
workers 1
# preload_app!が有効になっている場合、コメントアウトする
#preload_app!
この状態でPumaを起動するとPuma起動時に「in single mode...」と出ますので、こうなっていればOKです。
あとはこれまで通りにやればOKです。docker-composeからRailsサーバーを起動するようにしている場合は以下のように環境変数、公開ポートを指定してやれば良いでしょう。
services:
rails:
environment:
# use ruby/debug
- RUBY_DEBUG_HOST=0.0.0.0
- RUBY_DEBUG_PORT=23456
ports:
- '23456:23456'
docker-compose up
で起動したら、docker attach #{コンテナ名}
とすることでRailsサーバーのプロセスに接続できます。
この状態でdebuggerを含む処理が実行されるとその時点でデバッグコンソールが立ち上がります。
※docker attachしたコンソールから抜けたい場合はCtrl-C
ではなくCtrl-P
Ctrl-Q
で抜けましょう。Ctrl-C
だとプロセスが終了してしまいます。このあたりはDockerの使い方に関する部分なので、よく分からなければDockerのドキュメントなどを参照して下さい。
まとめ
debug gemは今まさに活発に開発が進行中で、どんどん新機能や対応が進んでいます。今回のChrome Devtools連携機能についてもOpen Chrome automaticallyというPRが上がっていたりなどまだまだ改善が進みそうな気配です。
お使いのRailsプロジェクトでもサクッと気軽に使い始められるdebug gem、皆さまもぜひ試してみましょう 😊
Railsサーバーあれこれ
今回pumaで最初うまくいかなくて色々試しましたが、Webrick(
rails s -u 'webrick'
)は問題なし、pumaはmultiple workerの時のみChrome Devtoolでアタッチした直後に接続が切れてしまいうまくいきませんでした。ReaderThreadError等が出ているので、pumaがcluster modeの場合の何かが問題なのかもしれません。