探した感じ、巷に溢れている記事はsbtを通さないものしかなく、マルチプロジェクトだと動かなかったりするので汎用的にうごかせる設定(コマンドで立ち上げたsbtのtestに対してリモートデバッグする)をまとめました。
概要
Inttelijのリモートデバッガはシンプルな構成だとサクッと動くのですが、
マルチプロジェクトを使ってたり、テストフレームワークが混在していたり等々があると期待通り動かすのに一手間かかります。
runは問題ない
手元で動作確認をする時、runして状態を見たい際は以下のようなコマンドで実行してます。
sbt 'project $pjName' -jvm-debug $port -Dconfig.file=$file run
testの場合
sbt (test|testOnly)
時は-jvm-debugだけではうまく動いてくれず、毎回以下の設定をtestタスクのjavaOptionに指定してdebugしたり
javaOptions in Test ++= Seq("-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9999")
IntellijIDEA上でテストにたいして一つ一つdebug confを作って、-Dconfig~などのテストに必要な設定を与えたりしていました。
これだと面倒なので、Intellij上とは別のteminalで立ち上げたsbt shellから実行したテストをデバッグできるようにしました。
これならtestOption等で指定したデフォルトオプションも読み込め、汎用的に使えて幸せ
jdwp
Java TM Debug Wire Protocol (JDWP) の略で、debuggerと、JVM との間の通信に使用するプロトコルです。詳しくは↓
https://docs.oracle.com/javase/jp/6/technotes/guides/jpda/jdwp-spec.html
以下2つの構成を取ることが出来ます。
- JVM(sbt) = Server, Debugger(Intellij) = Client
- JVM(sbt) = Client, Debugger(Inttelij) = Server
どっちでもよいのですが、JVMがサーバーのパターンだとDebugger起動忘れてsuspendしっぱなしが起こり得るのでDebugger側をサーバーにした手順を記します。(簡単に変えられるのでお好みでどうぞ)
debugタスク追加
↓のConfigの作り方を参考にうちのsbtにremote debugger用オプションを組み込んだConfigを追加しました。
https://www.scala-sbt.org/0.13/docs/Testing.html#Additional+test+configurations+with+shared+sources
ミニマムだと↓のような感じ
lazy val debugTest = config("debug") extend Test
lazy val root = (project in file("./"))
.configs(debugTest)
.settings(
fork in DebugTest := true,
javaOptions in DebugTest ++= Seq("-agentlib:jdwp=transport=dt_socket,server=n,suspend=n,address=41230"
)
.settings(inConfig(DebugTest)(Defaults.testTasks))
※javaOption in Testでもいいんじゃないのと思うかもですが、CIのときにdebuggerがないと
JVMがClientの場合=コケる or JVMがServerの場合=debugger接続待ちのまま止まる)ので別Configを用意する必要がありました。
導入手順
-
緑色に点滅している状態で、breakpointを貼ってターミナルを立ち上げ、お好きに
debug:test
なりdebug:testOnly *Hogehoge
行う。
※1度の実行(debug:test等)が終わると、Debuggerが停止するので再度実行したい場合は4,5の手順を繰り返し行う
おまけ: JVMをサーバーにしたいときの注意点
Intellijのdebuggerは接続のタイミングがシビアなのか、debuggerが接続するまで待機するsuspend=y
を指定しないとつながらなかったので注意