Say I have a loop in my code that calls the rails debugger a few times
def show
animals = ['dog', 'cat', 'owl', 'tiger']
for animal in animals
debugger
# do something else
end
Assuming I started my server with the --debugger option, when this page is viewed, the debugger is going to stop for every run of the loop.
I can type cont every time it stops so the request continues, but that's tedious, especially if we're not talking about it showing up 4 times as in this example, but 400.
Is there a way to let the debugger continue without pausing at each point of the loop?
My currently workaround is restarting the server, but that's time consuming.
Just put conditions on the debugger statement so that it stops only when you want it to, e.g.:
debugger if animal == 'tiger'
or if, say, you want to examine the code only on loop 384:
animals.each_with_index do |animal, i|
debugger if i == 384
# do something
end
or put in a variable that will let you continue ad hoc:
continue_debugger = false
animals.each do |animal|
debugger unless continue_debugger
# in the debugger type `p continue_debugger = true` then `c` when done
end
put your debugger statement somewhere before the iteration, then set a breakpoint inside the iteration which you can then clear later.
Example:
def index
debugger
#things = Thing.all
#things.each do |thing|
# ... something you want to check out in the debugger
thing.some_calculation
end
end
When you enter the debugger, set a breakpoint inside:
b app/controllers/things_controller.rb:42
(Where 42 is the line number you want to break at, like thing.some_calculation above. Note that it has to be an executable line of code -- comments, blank lines won't work). The debugger will show a breakpoint number and location:
Breakpoint 1 at .../app/controllers/things_controller.rb:42
Now, every time you continue, you will stop at the breakpoint. When you're done and want to complete the request, delete the breakpoint:
delete 1
continue once more, and you will complete the request!
It looks like in the source of ruby-debug, the call to debugger will always stop execution whenever it is hit. So one solution is to do as was suggested by Mori in his 'ad-hoc' solution, to make a conditional around the call to debugger that you can tweak inside the debugger session itself, such that you avoid calling debugger. This is probably the neatest solution, and what I would do unless you have some strong nagging purity issues with the code involved.
If you really want to only do this without some external conditional and inside the debugger session itself, it is possible. What you have to do is set a breakpoint in the code itself, then you can delete that breakpoint in the debugger when it is triggered:
require 'rubygems'
require 'ruby-debug'
Debugger.start
Debugger.add_breakpoint(__FILE__, __LINE__ + 2)
while true do
puts "Hi"
puts "mom"
end
Debugger.stop
This produces this sort of interaction:
Breakpoint 1 at debug_test.rb:10
debug_test.rb:10
puts "Hi"
(rdb:1) c
Hi
mom
Breakpoint 1 at debug_test.rb:10
debug_test.rb:10
puts "Hi"
(rdb:1) c
Hi
mom
Breakpoint 1 at debug_test.rb:10
debug_test.rb:10
puts "Hi"
(rdb:1) info b
Num Enb What
1 y at ./debug_test.rb:10
breakpoint already hit 3 times
(rdb:1) del 1
(rdb:1) c
Hi
mom
Hi
mom
Hi
mom
...and so on.
In this way, you are setting the breakpoint in code, then deleting it when you are done. Note that any time the line Debugger.add_breakpoint is called, it will re-set the breakpoint, so that's why it is outside of the loop and pointing 2 lines down. This technique can easily be extracted to require-ing a script that sets the breakpoint only when loading your server - Heck, you could write a whole framework class around controlling the Debugger module however you want. Of course, if you went this far, I would just create a singleton class that helps you implement Mori's ad-hoc solution and does or does-not call the debugger statement.
I came up with another answer to this today that I like even better:
debugger unless #no_debug
Use that on every line that has a debugger stop. When you want to stop stopping just set #no_debug to something.
I have another answer to this one: set a #debug on the class that you want to debug. That way you can do:
if (#debug && (the_condition)) then debugger end
or
debugger unless !#debug
then when you are done with the debugger just #debug = false and c.
However, I'm not really happy with having debugger 'hard stops' in live code. These are the kind of things that can be accidentally checked in and forgotten about until something breaks. The #debug would certainly fall under that as well. To that end I think my ideal solution would use Matt's idea and a script that sets up a breakpoint inside the object when the object is created. That way you'd have the debugging that you want but you wouldn't have any code in source control that is specifically for development. I'll update this answer if I find such a solution.
You can always comment out the debugger call from your code then type reload in your debug session. Then just cont once and the request will continue without triggering a debug session.
Because you're in development mode, you can just add the debugger call back in later and it will trigger correctly.
Putting this here as an alternative since this question showed up first in my own searches. Let's say you have a piece of code that isn't working under a specific circumstance, but works otherwise, and you have a whole slew of tests that exercise this but one specific test that fails. It's a PITA to have to continually type continue into the debug console until you get to the test you really want to debug, so I started using this convention:
In your code:
def some_common_function
debugger if defined? ::ASDF
# do something
end
Then in your test:
should "do this thing that it isn't doing under a specific circumstance" do
# setup the specific situation
::ASDF = true
# your tests
end
If I want control back, I just do
eval return
and I will exit the currently running function, which will usually kick me back to the IRB [rails console] prompt.
exit debugger out of the loop, use
exit-all
instead of
cont
Although, it will create an error and you might have to remove debugger and send request again but it will get you out of all the loops
Related
Sometimes I'm stuck in a long loop when using binding.pry.
I can quit the loop by exit-program, but the command exit rails console also.
Is there easy way to exit a long loop without quitting rails console?
I'm not sure this is what you're looking for but you may want to try the disable-pry command which will automatically iterate though your entire loop without exiting the session. Another option (albeit not great for long loops) would be to use exit or Ctrl+D which iterates through a single cycle of a loop. You would have to enter it repeatedly until your loop was complete, however it would allow you to hit another breakpoint if that's your goal.
For a little more control you may want to add another gem like byebug or pry-byebug.
debug = true
# start loop
binding.pry if debug
# end loop
You can exit each loop iteration individually with exit. Then, when you're ready to step out of debugging and continue the execution of the remaining code, enter debug = false. Then, exit will return you to the rails console session.
When I set a breakpoint with Byebug in Rails, I sometimes want it to finish executing, but the guide on github says to use exit which also exits Pry. Typing continue repeatedly can be annoying if the breakpoint is in a loop.
Is there anyway to stop byebug without exiting the Rails console?
When running byebug under the Rails console or in Rails' server I usually quit only byebug by hitting Ctrl+D.
The catch with this approach is, if you do this in Rails' server then Byebug will not stop and debug the next time it hits a byebug statement in your code anywhere. But it works perfectly in the Rails console.
Try !!!. It works on pry gem, but not sure if it does on byebug.
Well this isn't the most elegant solution but it works for me so far.
If you have a base controller in your rails application you can add an accessor to hold a variable saying whether you want debugging to happen or not:
attr_accessor :debugging
Then add/modify initializer to set the variable to true on each request (or each time there is an instance created for that object):
def initialize
#debugging=true
super
end
And finally, always use the byebug call with a conditional wherever you want this behavior:
byebug if debugging
Then when you are at the IRB console and you want to exit the debugger but continue executing the code you just set the variable:
#debugging=false; finish
You could even encapsulate this in a helper or do some OOP magic but this is a good starting point. Nice thing is that if you repeat the request you'll get the standard behavior again unless you set the variable to false again.
If you want to exit a loop try skip.
It'll runs until the next breakpoint as long as it is different from the current one.
Then, once you are out of the loop you can continue.
Typing finish in the console exits byebug, without closing pry/rails console/rails server.
Ctrl + D also works.
Go to your code and remove byebug and save, then in the buybug terminal write continue then press enter.
Tadaaa your app will continue and you will exit byebug all without closing your app.
Try continue or finish
Source: https://edgeguides.rubyonrails.org/debugging_rails_applications.html#resuming-execution
Remove "debugger from your code and type in "finish" in console
(byebug) quit
Really quit? (y/n) y
user ~
The only one that works quickly and without issues for me so far.
Is there an easy way to log all method calls in a Rails app?
My main use for this would be in testing (and in debugging tests). I want to have more of a history than a stacktrace provides (for instance, when running rspec with the '-b' option).
It's easy to do. Just add 5 lines of code into your script/server:
#!/usr/bin/env ruby
set_trace_func proc {
|event, file, line, id, binding, classname|
if event == "call" or event == "return"
printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
end
}
require File.expand_path('../../config/boot', __FILE__)
require 'commands/server'
It's described at http://phrogz.net/ProgrammingRuby/ospace.html#tracingyourprogramsexecution
Your application will become quite slow and you might get more output than you want. You can easily add more conditions on file/class/function names to avoid printing unwanted stuff.
Perftools might give you what you're looking for. It analyzes the entire process and can give you a graphical view that looks something like this. Rack perftools profiler is a rubygem that uses perftools and makes it easy to integrate with a Rails application, so I would recommend going with that if you want to try it.
Firstly stacktrace IS every method call that was on the stack at the time an error occurred, what other history could you want besides this?
Secondly, to answer your question, no there is no easy way to log all method calls. You could up your log level all the way to debug which should give you more stuff in the logs, but this will only be things that someone has actually chosen to log, unrelated to method calls.
It probably wouldn't be that difficult to patch ruby in such a way that every method call will print some log statements before and after the method execution, but this will once again be similar to what a stack trace would give you anyway and potentially less since you won't get line numbers etc.
If you want more info than the stack trace, logging is the way most people would do it.
NEWBIE logger question here:
What's the best way to log output to a development log for debugging purposes? How do you do it in a way that's quick, simple, effective?
To log in log/development.log:
Rails.logger.debug "Hello!"
Or, if you want to create a separate log, you could create a new logger in an initializer (config/initializers):
MyLogger = Logger.new(Rails.root.join("log", "custom.log"))
Then, in your app you can call:
MyLogger.debug "Hello!"
One option that I prefer over logging is using ruby debug. It allows you to put a break point anywhere in your code and inspect all local variables at that point in time. I find it more useful for tracking down bugs in cases where you have no friggin' idea what's going on and just want to look at everything.
Say you had a method like this and the behavior was not what you expected:
def my_method(arg)
# do something with argument
end
You could stick a debugger line in there:
def my_method(arg)
debugger
# do something with argument
end
You'll be able to then do things like this to get a better idea of what is going on:
p arg
p arg.method
p arg.another_method
p local_var
p local_var.method
What is the best way for me to determine a controller variable's value during execution?
For example, is there a way I can insert a break in the code, and cause the value of the variable to be output to the screen (or the log)?
Yes. The easiest way is to raise the value as a string. Like so: raise #foo.to_s
Or, you can install the debugger (gem install ruby-debug), and then start the development server with the --debugger flag. Then, in your code, call the debugger instruction.
Inside the debugger prompt, you have many commands, including p to print the value of a variable.
Update: here's a bit more about ruby-debug.
If you have a controller instance variable named #foo, then in your controller you can simply do something like:
logger.debug "#foo is: #{#foo}"
Additionally, you can output the value in your view template using:
<%= debug #foo %>
I prefer using the inspect method like so:
raise #foo.inspect
It has more information than to_s, like the attribute values.
Summary from Jordi Bunster, John Topley, and Jaryl:
I. Quick and dirty way:
raise #foo.inspect
in your controller. Or
<% raise #foo.inspect %>
in your view.
II. Proper logging to you development.log:
logger.debug "#foo == #{#foo.inspect}"
III. Full-fledged debugging:
Install the debugger (gem install ruby-debug), and then start the development server with the --debugger flag. Then, in your code, call the debugger instruction.
Inside the debugger prompt, you have many commands, including p to print the value of a variable.
Raising an exception is the fastest way if you just need to look at a value, but it's worth the time to learn how to use the debugger properly. It's rare that you would only need to just see the value of a variable, you are likely trying to find a bug in your code, and that's what a debugger is for.
Sending the info to the development log is slower than either of the other two options here so far if you learn how to use the debugger (who wants to read through log files). Use the logger for production, you are going to want to see what the value was when somebody calls you up and says everything is broken.
Well, I usually prefer the standard error output
$stderr.print("whatever")
Its simple and does the job.
Add pry-moves to Gemfile: gem 'pry-moves'
Insert binding.pry where you want to stop
Type variable's name to see its value
Then continue by typing c, move to next line with n or perform other debugging actions until you will resolve the issue.