Logging all method calls in a Rails app - ruby-on-rails

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.

Related

Detailed statement trace in Rails 2.3

A while back, I remember using a piece of code (4-5 lines), added to the script/server file, which would show a puts trace of every method call when webrick was running. The output was something like:
Entering: x method
Exiting: x method
I cannot for the life of me remember how it was done, or how to replicate it. Anyone have any ideas?
Hard to say, there are any number of ways to do this, from Kernel.set_trace_func, or tracepoint, or rbtrace, or Unroller (unclear how well it works these days).
You might be thinking specifically of this SO answer, though.

puts statements for debug

When I code, I make quite intense use of "puts" statements for debugging. It allows me to see what happens in the server.
When the code is debugged, I use to remove these "puts" statements for I don't know what reason.
Is it a good idea or should I leave them instead to give more clarity to my server logs?
You should use the logger instead of puts. Use this kind of statements:
Rails.logger.debug "DEBUG: #{self.inspect} #{caller(0).first}" if Rails.logger.debug?
If you want to see the debugging in the real-time (almost), just use the tail command in another terminal window:
tail -F log/development.log | grep DEBUG
Then you do not need to remove these statements in production, and they will not degrade performance too much, because if logger.debug? will prevent the (possibly expensive) construction of the message string.
Using standard output for debugging is usually a bad practice. In cases you need such debug, use the diagnostic STDERR, as in:
STDERR.puts "DEBUG: xyzzy"
Most of the classes in Rails (models, controllers and views) have the method logger, so if possible use it instead of the full Rails.logger.
If you are using older versions of Rails, use the constant RAILS_DEFAULT_LOGGER instead of Rails.logger.
use the logger : http://guides.rubyonrails.org/debugging_rails_applications.html#the-logger
I use the rails_dt gem designed specifically to make such kind of debugging easier.
Using Rails.logger or puts directly is somewhat cumbersome, since it requires you to put a lot of decorative stuff (DEBUG, *** etc.) around debug messages to make them different from regular, useful messages.
Also, it's often difficult to find and defuse the debug output generated by Rails.logger or puts if the message doesn't appear to contain enough searchable characters.
rails_dt prints the origin (file, line), so finding the position in code is easy. Also, you will never confuse DT.p with anything, it clearly does debug output and nothing else.
Example:
DT.p "Hello, world!"
# Sent to console, Rails log, dedicated log and Web page, if configured.
[DT app/controllers/root_controller.rb:3] Hello, world!
Gem is available here.

"Correct" way to write log output from a background (Resque) job?

Resque jobs are just plain old ruby objects. I can use puts calls inside them to produce output into the console, or I can instantiate a standard Ruby Logger class with STDOUT and use that.
But is there a correct approach to logging in Rails, from places that aren't controllers or models? I see Rails.logger returns a BufferedLogger, but when I call info or warn etc on it, nothing happens. If I call flush on it, it just returns an empty array and nothing is output.
What's the convention here?
I'm not really sure that there is a convention. I had a pretty ugly logging system up until just recently. Now I use lumber to integrate log4r with Rails. That really made logging much nicer because I now have named loggers (e.g., logger matches the class name -- great for filtering output) and I can control log levels on a per-logger (i.e., per-class) basis.
There's also a GELF adapter for log4r if you want to use graylog2 to aggregate your logs.

How can I see what actually happens when a Test::Unit test runs?

In a Rails application I have a Test::Unit functional test that's failing, but the output on the console isn't telling me much.
How can I view the request, the response, the flash, the session, the variables set, and so on?
Is there something like...
rake test specific_test_file --verbose
You can add puts statements to your test case as suggested, or add calls to Rails.logger.debug() to your application code and watch your log/development.log to trace through what's happening.
In your test you have access to a bunch of resources you can user to debug your test.
p #request
p #response
p #controller
p flash
p cookie
p session
Also, remember that your action should be as simple as possibile and all the specific action execution should be tested by single Unit test.
Functional test should be reserved to the the overall action execution.
What does it mean in practice? If something doesn't work in your action, and your action calls 3 Model methods, you should be able to easily isolate the problem just looking at the unit tests. If one (or more) unit test fails, then you know which method is the guilty.
If all the unit tests pass, then the problem is the action itself but it should be quite easy to debug since you already tested the methods separately.
in the failing test use p #request etc. its ugly, but it can work
An answer to a separate question suggested
rake test TESTOPTS=-v
The slick way is to use pry and pry-nav gems. Be sure to include them in your test gem group. I use them in the development group as well. The great thing about pry and pry nav is you can step through your code with a console, so you can not only see the code as it's executed, but you can also enter console commands during the test.
You just enter binding.pry in the places in the code you want to trigger the console. Then using the 'step' command, you can move line by line through the code as it's executed.

How to determine the value of a controller variable during execution in Ruby on Rails?

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.

Resources