1

As described here, I'm trying to modify the standard rails logger such that it will provide the log level, timestamp and filename + line number of the log statement.

This is what my logger class looks like in config/initializers/logger.rb:

class ActiveSupport::Logger::SimpleFormatter
  def call(severity, time, progname, msg)
    "[#{severity} #{time} #{caller(0).first.match(/.*:\d+/)[0]}] #{msg}\n"
  end
end 

However, this log line ALWAYS produces a log message containing "logger.rb:3" Clearly that's wrong. It is printing the filename and line number of the line within the logger.rb file. I need to get the call stack and go up one stack frame and get it from there. How can I do it? Is it even possible?

This solution using caller works in a very simple stand-alone ruby program. But when I run my whole Rails app, caller returns something very different and alien than it does when running it in a standalone ruby file.

Rails does something very funky with The caller variable. It purports to contain the call stack. But it doesn't. It contains references to a lot of other code (presumably rails infrastructure), but no other file from my application -- notably not the file from which this log line is called. See here (snipped version shown below).

/Users/myUser/my_rails_app/config/initializers/logger.rb:16:in `call'
/Users/myUser/.rbenv/versions/1.9.3-p484/lib/ruby/gems/1.9.1/gems/activesupport-4.0.8/lib/active_support/tagged_logging.rb:21:in `call'
/Users/myUser/.rbenv/versions/1.9.3-p484/lib/ruby/1.9.1/logger.rb:491:in `format_message'

<SNIPPED!>

/Users/myUser/.rbenv/versions/1.9.3-p484/lib/ruby/1.9.1/webrick/httpserver.rb:94:in `run'
/Users/myUser/.rbenv/versions/1.9.3-p484/lib/ruby/1.9.1/webrick/server.rb:191:in `block in start_thread'

When I write a simple ruby (without Rails) program to test caller, it works completely as it should:

def foo
  puts caller[0]
end

def bar
  foo
end

bar

yields:

/Users/myUser/rubyTest.rb:9:in `bar'

Why does this work in standalone Ruby, but fail in rails?

Community
  • 1
  • 1
Saqib Ali
  • 11,931
  • 41
  • 133
  • 272
  • Unrelated, but I'm not sure I like the idea of patching an existing class when you could just create your own formatter class. – Dave Newton Jul 08 '14 at 21:17

1 Answers1

1

Take a look at Ruby's caller_locations method.

http://www.ruby-doc.org/core-2.0.0/Kernel.html#method-i-caller_locations

I use caller_locations(2,1)[0] in a special notification method I wrote in order to get where the actual error comes from.

Philip Hallstrom
  • 19,673
  • 2
  • 42
  • 46
  • This looks like exactly what I need. But unfortunately I'm using Ruby 1.9.3 and it seems like this method only exists in 2.0.0 and onwards. :( – Saqib Ali Jul 09 '14 at 01:18