jcollum
jcollum

Reputation: 46589

how do I get all my rake tasks to write to the same log file?

I have two rake tasks that I'd like to run nightly. I'd like them to log to one file. I thought this would do the trick (got it here: Rake: logging any task executing):

application.rb

module Rake
  class Task
    alias_method :origin_invoke, :invoke if method_defined?(:invoke)
    def invoke(*args)
      @logger = Logger.new('rake_tasks_log.log')
      @logger.info "#{Time.now} -- #{name} -- #{args.inspect}"
      origin_invoke(args)
    end
  end
end

and then in the rakefile:

task :hello do
  @logger.warn "Starting Hello task"
  puts "Hello World!"
  puts "checking connection "
  checkConnection
  puts "done checking"
  @logger.debug "End hello rake task"
end

But when I run the task I get:

private method 'warn' called for nil:NilClass

I've tried a couple of flavors of that call to logging (@, @@, no @) to no avail. Read several threads on here about it. The rubyonrails.org site doesn't mention logging in rake tasks. The tasks that I'm invoking are fairly complex (about 20-40 mins to complete) so I'll really want to know what went wrong if they fail. I'd prefer for DRY reasons to only create the logger object once.

Upvotes: 0

Views: 2205

Answers (2)

jcollum
jcollum

Reputation: 46589

I ended up solving this (or at least well enough) by making a "log" task and depending on that in other tasks. Not really ideal, since that means having to include that dependency in any new task, but I have only a few tasks so this will do fine. I'm aware that there is a "file" task but it didn't seem to want to work in Windows, so I chose this because it seems to be more cross platform and it's more explicit.

I need a logger object because I am passing that object into some method calls in the [...] sections. There's enough begin/rescue/end in there that writing to the output stream wouldn't work (I think).

@log_file =  "log/tasks.log"
directory "log"

task :check_log => ["log"] do
  log = @log_file
  puts 'checking log existence'
  if not FileTest.exists? ("./#{log}")
    puts 'creating log file'
    File.open(log, 'w')
  end
end

task :check_connection  => [:check_log] do
  begin
    conn = Mongo::Connection.new
    [...]
  end
end


task :nightly_tasks => [:check_connection, :environment ] do
  for i in 1..2
     logger.warn "#########################"
  end
  [...]
  logger.warn "nightly tasks complete"
end

def logger
  @@logger ||= Logger.new( File.join(Rails.root, @log_file) )
end

Upvotes: 1

Josh
Josh

Reputation: 945

Unless you're wrapping everything in giant begin/rescue's and catching errors that way, the best way to log errors is to catch all output from stderr and stdout with something like:

rake your:job 2>&1 >> /var/log/rake.log

You could also set your Rails environment to use the system logger as well.

Upvotes: 1

Related Questions