Rails logger messages test.log? - ruby-on-rails

Is it possible to configure rails to show logger.debug messages (from logger.debug statements inside controllers) to display inside test.log (or to the console) when running unit and functional tests?
I added the following to test_helper.rb. I see messages from logger.debug statements directly inside tests but no messages from logger statements inside controller methods?
def logger
RAILS_DEFAULT_LOGGER
end

Works fine for me. Have you set your config.log_level to something specific?
Eitherway,
config.log_level = :debug
should work?

From Rails 3.2 upwards the method in test_helper.rb should look like this:
def logger
Rails.logger
end

Related

Approach to a custom rails logger

My Rails application runs in Heroku; recently, we have changed the Heroku LOG_LEVEL to WARN as the system logs flooded with so many unwanted information. But still, in some of the areas, I wanted to use Rails.logger.info;
Currently, in Heroku we have this:
LOG_LEVEL = WARN
And in production.rb, still that is
config.log_level = :info
config.log_formatter = ::Logger::Formatter.new
The above configuration we didn't change it, as the precedence is for LOG_LEVEL if we set that. So with the above configuration, if we put Rails.logger.info "Hello world," that will not work because the logger will only handle the logs equal or higher to warn in importance.
So we have tried one other way.
Created a new initializer called custom_logger.rb; we put
$INFO_LOGGER = Rails.logger.dup
$INFO_LOGGER.level = :info
then wherever we wanted to use info, we just called $INFO_LOGGER.info "Hello World," this prints
Is this a correct approach, like using the global variable?
Is this a correct approach, like using the global variable?
This question could be considered opinion based, so in my opinion I would not recommend it. Additionally the question posed in the title is regarding a custom logger and while we could implement one to facilitate the request I would propose a simpler solution that will still log exactly what you want, to the current log file, and without the need for a custom logger, a secondary logger, or any kind of global variable.
My Suggestion:
Rails uses ActiveSupport::Logger by default which is essentially just a ruby Logger.
If there are messages you always want logged regardless of the level you can use Logger#unknown.
Per the Documents for the Logger class:
Levels:
UNKNOWN - An unknown message that should always be logged.
Logger#unknown
Log an UNKNOWN message. This will be printed no matter what the logger's level is.
So You can use this to your advantage for the messages that you always want to show while still avoiding the noise of the standard info messages:
For Example:
Rails.logger.info "Noisy message" # won't show when LOG_LEVEL > INFO
Rails.logger.unknown "VERY IMPORTANT MESSAGE" # will show no matter what the level is set to
You don't want to use global variables. Instead create a custom class for example
class MyLogger
class << self
def info(*args)
new.info(*args)
end
end
delegate :info, to: :logger
attr_reader :logger
def initialize
#logger = ActiveSupport::Logger.new(Rails.root.join("log/my_logger.#{Rails.env}.log"))
#logger.formatter = ::Logger::Formatter.new
end
end
Now you can call MyLogger.info("this is a test message") and it will output the message in the log file regardless of the LOG_LEVEL or config.log_level = :info

Logging in a gem that is used both inside and outside rails

What's a proper approach to this: I've got a gem that can be used both with or without rails - if it is used within rails, I'd like to re-use rails-services e.g. the configured logger. If it is outside of rails (e.g. in a sinatra-app), I want to fall back on the Logger from stdlib: What is a safe way for a gem to determine, if we're in a rails-app or not?!
I've tried approaches like:
#logger = defined?("Rails") ? eval("Rails.logger") : Logger.new(STDOUT)
But this only gives me an "uninitialized Constant"...
So close! Drop the quotes / eval:
#logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
I'd also encourage that you provide a config hook where the user can specify a Logger-compatible log sink. Defaults are nice but sometimes you need to configure things.

How do I output a Rails logger in Delayed_Jobs?

I would like to log #cf in this delayed_job :
(CardReferral.all.map(&:email).map(&:downcase) - CardSignup.all.map(&:email).map(&:downcase)).each do |cf|
#cf = CardReferral.find_by_email(cf)
# <--- I want to add a Rails logger here
Notifier.deliver_referred_magic_email(User.find(#cf.user_id), #cf.email, #cf.name, #cf.message, subject, editor1)
end
Rails version in Rails 2.3.5 .
Any ideas?
The logger is accessible through the "logger" command in your models and controllers. You can call one of its methods to specify your message's log level (debug, info, warn, error, fatal), like this:
logger.debug("This will be logged")
You can find more in the Rails guides here.
It actually doesn't, add this in your task:
logger = Logger.new(STDOUT)

Getting delayed job to log

#Here is how I have delayed job set up.
Delayed::Worker.backend = :active_record
#Delayed::Worker.logger = Rails.logger
Delayed::Worker.logger = ActiveSupport::BufferedLogger.new("log/
##{Rails.env}_delayed_jobs.log", Rails.logger.level)
Delayed::Worker.logger.auto_flushing = 1
class Delayed::Job
def logger
Delayed::Worker.logger
end
end
if JobsCommon::check_job_exists("PeriodicJob").blank?
Delayed::Job.enqueue PeriodicJob.new(), 0, 30.seconds.from_now
end
#end
#Here is my simple job.
class PeriodicJob
def perform
Rails.logger.info "Periodic job writing #{Time.now}"
Delayed::Job.enqueue PeriodicJob.new(), 0,
30.seconds.from_now
end
end
I don't see any log messages from delayed job in my rails logs or delayed job log file, the only messages I see are jobs starting/success/failure in the delayed_jobs.log file.
this is causing big problems, including detecting bugs and memory leaks in workers almost impossible! Please help!
We've gotten it to work on Rails 3/Delayed Job 2.0.3 by hacking Rails.logger itself to use a different log file (the one we want for delayed_job entries) and also setting the delayed job logger to use the exact same object:
file_handle = File.open("log/#{Rails.env}_delayed_jobs.log", (File::WRONLY | File::APPEND | File::CREAT))
# Be paranoid about syncing, part #1
file_handle.sync = true
# Be paranoid about syncing, part #2
Rails.logger.auto_flushing = true
# Hack the existing Rails.logger object to use our new file handle
Rails.logger.instance_variable_set :#log, file_handle
# Calls to Rails.logger go to the same object as Delayed::Worker.logger
Delayed::Worker.logger = Rails.logger
If the above code doesn't work, try replacing Rails.logger with RAILS_DEFAULT_LOGGER.
This may be a simple workaround but it works well enough for me:
system("echo #{your message here} >> logfile.log")
Simple but works
I have it working with the following setup in initializer:
require 'delayed/worker'
Delayed::Worker.logger = Rails.logger
module Delayed
class Worker
def say_with_flushing(text, level = Logger::INFO)
if logger
say_without_flushing(text, level)
logger.flush
end
end
alias_method_chain :say, :flushing
end
end
i simply did this:
/config/environments/development.rb
MyApp::Application.configure do
[...]
[...]
[...]
Delayed::Worker.logger = Rails.logger
end
In every next request you do the mail will be appear on the log.
NOTE: Sometimes you have to refresh the page to the mail be logged on the log. Don't forget to restart the server ;)
DelayedJob does not seem to output if there is something wrong:
1- Non-active record classes need to be required and initialized:
How:
Create a file config/initializers/load_classes_for_dj.rb
Add to it the lines:
require 'lib/libtest/delayed_test.rb'
DelayedTest
Note that if you have '#{config.root}/lib/libtest' in config.autoload_paths in config/application.rb, you do not need to do the require.
Source:
Rails Delayed Job & Library Class
2- Classes that implement the Singleton module won't work by calling:
SingletonClass.instance.delay.sayhello
In order to fix that, do the following:
class SingletonClass
include Singleton
# create a class method that does the call for you
def self.delayed_sayhello
SingletonClass.instance.sayhello
end
def sayhello
# this is how you can actually write to delayed_job.log
# https://stackoverflow.com/questions/9507765/delayed-job-not-logging
Delayed::Worker.logger.add(Logger::INFO, "hello there")
end
end
In order to call the delayed class method, do the following:
SingletonClass.delay.delayed_sayhello
Yes, I am calling .delay on a class here. Since classes in Ruby are also objects, the call is valid here and allows me to access the class method "delayed_sayhello"
3- Do not pass ActiveRecord objects or some complex objects to your call but rather pass ids, look up the objects in the database in your delayed method, and then do your work:
DO NOT DO:
DelayedClass.new.delay.do_some_processing_on_album Album.first
DO THIS INSTEAD:
DelayedClass.new.delay.do_some_processing_on_album Album.first.id
and inside DelayedClass do_some_processing_on_album , do
a = Album.find_by_id id
There was a stackoverflow post about this that I saw a while ago -- not sure which :-)
4- For completion, this is how to do mailers (do not call the deliver method):
Notifier.delay.signup(user_id)
As per 3, do not pass the user's object but rather their id, do the lookup inside the signup method.
Now once you've ensured you have followed the guidelines above, you can use:
Delayed::Worker.logger.add(Logger::INFO, "hello")
If you are still facing issues, I suggest you break down your problem:
a- Create a new class
b- Make sure you have it included and initialized as per step 1
c- Add logging from step 4 and try calling MyNewClass.new.delay to see if it works
I hope this helps you guys :-)
Don't forget to change the ActiveRecord::Base.logger
Delayed::Worker.logger = Logger.new("log/delayed_job.log", 5, 104857600)
if caller.last =~ /script\/delayed_job/ or (File.basename($0) == "rake" and ARGV[0] =~ /jobs\:work/)
ActiveRecord::Base.logger = Delayed::Worker.logger
end
More detailed answer: Have delayed_job log "puts", sql queries and jobs status

How can I access the Rails logger from an initializer?

Following the advice from my previous question, I placed my background process in an initializer named scheduler.rb. However, I'm having a hard time getting the newly-scheduled processes to log to the Rails logs. Is there a simple way for me to access the same logs from the initializer, preferably by accessing Rails' default logger methods (logger.info, etc)?
Rails 3-
Simply use Rails.logger in your initializer
Rails.logger.info "blabla"
HTH
RAILS_DEFAULT_LOGGER was deprecated in Rails 3. The following steps work for me in Rails 3.1.
Set your logger in environment.rb before calling initialize! on your application:
Rails.logger = Logger.new(STDOUT)
MyServer::Application.initialize!
Then call the logger in your initializer.
Rails.logger.info "Hello, world!"
RAILS_DEFAULT_LOGGER.info "abc"

Resources