Link to Japanese version:
https://techracho.bpsinc.jp/hachi8833/2022_09_01 (Hashnode has issues generating the right link for this url)
Link to my talk: ruby/debug - The best investment for your productivity
Switching to a new debugger and potentially changing your debugging process could be scary. So I hope this post can help you get familiar with
ruby/debug and make the migration smoother.
(In the rest of the article, I'll use
debug to refer to
- I'm not as experienced with
debug. So please let me know if I listed incorrect/outdated information.
- Its purpose is to give a higher-level comparison. To learn more about
debug's specific usages, please check its official documentation.
- It doesn't contain all the features but should already cover most of them.
Before we get into individual features, I want to quickly mention some advantages of
Immune from the compatibility issue with Zeitwerk
- Powerful breakpoints and tracers
- Convenient remote debugging functionality and VSCode integration
- Direct integration from IRB
- Less flexible on thread control
- Doesn't work well with Fiber yet
- Less learning resources
- No per-project configuration
3.1 comes with
v1.4, I recommend always using its latest release)
|Supported Ruby version||2.5+||2.6+|
|Has C extension||Yes||Yes|
|Latest version||11.1.3 (23 Apr 2020)||1.8.0 (9 May 2023)|
|Via debugger statement|
User Experience Features
|Edit source file|
Code evaluation in REPL is more or less the same between
debug, that is:
- If the expression doesn't match a console command, like
my_method(arg), it'll be evaluated as Ruby code
- If the expression matches a console command, like
n, you can use console commands to evaluate it
|Execute debugger commands|
|Avoid expression/command conflicts|
Flow Control & Frame Navigation
debug provides the same stepping commands as
byebug does. So
byebug users can switch to
debug without learning new behaviors.
|Move to |
|Move up a frame|
|Move down a frame|
|Move up n frames||No|
|Move down n frames||No|
|Continue the program|
|Quit the debugger|
|Kill the program|
As previously mentioned,
debug stops all threads when suspended and doesn't allow per-thread management at the moment. So it has simpler thread-related commands.
|Thread suspension||Only the current thread||All threads|
|List all threads|
|Switch to thread|
|Stop a thread||No|
|Resume a thread||No|
byebug already has decent breakpoints support,
debug takes it to another level by:
- Allowing breakpoints to execute commands with
- Supporting call-location-based triggering condition with the
- Supporting specialized
|On a method|
|With a condition|
|With a path condition||No|
|To run a command and continue||No|
|To run a command before stopping||No|
|Instance variable watch breakpoint||No|
|List all breakpoints|
|Set a breakpoint|
|Delete a breakpoint|
|Delete all breakpoints|
debug contains values of method call or block arguments. This small improvement can save you from inspecting them manually between frames.
The filtering support can help you focus on relevant frames and ignore the ones from frameworks or libraries.
|Displaying method/block arguments in backtrace||No||Yes|
|Limit the number of backtraces||No|
|Show local varibales|
|Show instance variables|
|Show global varibales|
|Show only arguments||No (included in |
|Filter variables/constants by names||No|
debug doesn't have a dedicated command to list an object's methods, it has a
ls command that's similar to
I will write another dedicated article to introduce
debug's tracing functionalities, but I encourage you to already give them a try from time to time, especially:
trace exception- to monitor exceptions raised in your code. You may be surprised by the exceptions raised and rescued in your application under the surface.
trace object <expr>- to observe an object's activities: receiving a method call or being passed to a method call.
|Global variable tracer||No|
|Allow multiple tracers||No||Yes|
|Method call tracer||No|
|Ruby object tracer||No|
|Filter tracing output||No|
|Disable the specific tracer||No|
debug supports a wide range of configurations to make it fit your needs. But it doesn't support per-project RC files due to security concerns.
|List all configs||No|
|Show a config|
|Set a config|
|RC file name|
|RC file locations|
Remote debugging functionality is becoming crucial as we start containerizing our development environment and don't always have direct standard IO access. It's also crucial for connecting to different debugger clients like VSCode or Chrome.
So if you have needs in this area, migrating to
debug is your best option.
|Connect via TCP/IP||Yes||Yes|
|Connect via Unix Domain Socket||No||Yes|
|VSCode integration through Debug Adapter Protocol (DAP)||No||Yes|
|Chrome integration through Chrome DevTools Protocol (CDP)||No||Yes|
To most users, switching from
debug should take little effort. But the potential productivity gain from
debug's features could be significant.
byebug is a great debugger and has served the community well for many years.
But as its development slows down (last release was 2 years ago) and
debug receives constant updates from the Ruby core, the gap between them will only widen.
debug to your toolbelt and exploring its powerful features will be a great productivity investment for the long term.