如何让 Rails.logger 在运行 rspec 时打印到控制台/stdout?

与 title 相同: 如何在运行 rspec 时将 Rails.logger打印到控制台/stdout。

Rails.logger.info "I WANT this to go to console/stdout when rspec is running"
puts "Like how the puts function works"

我还是希望 Rails.logger也变成 log/test.log

130885 次浏览

You can define a method in spec_helper.rb that sends a message both to Rails.logger.info and to puts and use that for debugging:

def log_test(message)
Rails.logger.info(message)
puts message
end

A solution that I like, because it keeps rspec output separate from actual rails log output, is to do the following:

  • Open a second terminal window or tab, and arrange it so that you can see both the main terminal you're running rspec on as well as the new one.
  • Run a tail command in the second window so you see the rails log in the test environment. By default this can be like $ tail -f $RAILS_APP_DIR/logs/test.log or tail -f $RAILS_APP_DIR\logs\test.log for Window users
  • Run your rspec suites

If you are running a multi-pane terminal like iTerm, this becomes even more fun and you have rspec and the test.log output side by side.

Tail the log as a background job (&) and it will interleave with rspec output.

tail -f log/test.log &
bundle exec rspec

When you're done with the log, bring it back into the foreground with fg and exit the tail with ctrl-c as usual.

For Rails 4, see this answer.

For Rails 3.x, configure a logger in config/environments/test.rb:

config.logger = Logger.new(STDOUT)
config.logger.level = Logger::ERROR

This will interleave any errors that are logged during testing to STDOUT. You may wish to route the output to STDERR or use a different log level instead.

Sending these messages to both the console and a log file requires something more robust than Ruby's built-in Logger class. The logging gem will do what you want. Add it to your Gemfile, then set up two appenders in config/environments/test.rb:

logger = Logging.logger['test']
logger.add_appenders(
Logging.appenders.stdout,
Logging.appenders.file('example.log')
)
logger.level = :info
config.logger = logger

For Rails 4.x the log level is configured a bit different than in Rails 3.x

Add this to config/environment/test.rb

# Enable stdout logger
config.logger = Logger.new(STDOUT)


# Set log level
config.log_level = :ERROR

The logger level is set on the logger instance from config.log_level at: https://github.com/rails/rails/blob/v4.2.4/railties/lib/rails/application/bootstrap.rb#L70

Environment variable

As a bonus, you can allow overwriting the log level using an environment variable with a default value like so:

# default :ERROR
config.log_level = ENV.fetch("LOG_LEVEL", "ERROR")

And then running tests from shell:

# Log level :INFO (the value is uppercased in bootstrap.rb)
$ LOG_LEVEL=info rake test


# Log level :ERROR
$ rake test

I had similar problem in rails 5.0. My api/request specs did not output errors into console, but into log/test.log file. Other test types were outputting errors to console normally.

Changing config.action_dispatch.show_exceptions to false fixed the problem:

# config/environments/test.rb
config.action_dispatch.show_exceptions = false

Addition to existing answers, if your requirement is to print logs in STDOUT as well as log file, then you can use Log broadcast.

One of my use-case was rake seed/tasks should print logs in STDOUT as well as log files.

Rails.logger.extend(
ActiveSupport::Logger.broadcast(
ActiveSupport::Logger.new($stdout)
)
)