Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Properly using Log4r in Ruby Application

I must really be missing something obvious, but I'm having trouble with general use of Log4r in my Ruby application. I am able to log without issue, but the overhead seems clunky the way I have it setup. I'm basically passing the full path to a filename to log in each class in my application. The ruby script that is called pulls the log file from one of the arguments in ARGV which is then passed around and set in each class that I call in ruby. In each class I use the patternFormatter to insert the class/file name into the log statement.

Is there a better way to make this work? It feels like no matter what I think of will require something to be passed to each class in my ruby application. I could set the log file in a yaml configuration file instead, but then I would be passing around the configuration file to each class as well.

Any advice? If this doesn't make sense I could try and post some more specific code samples to further explain what I mean.

Thanks!

like image 434
Spencer Avatar asked Mar 18 '10 19:03

Spencer


2 Answers

I'm the maintainer of log4r,

For individual scripts (different .rb files), you could approach this in a few different ways (fitting, I know), first, be mindful that the features I'm covering here are available in >= 1.1.4.

One way would be to set a different PatternFormatter string per script (if you create a yaml or xml configuration file, you can specify different patterns on a per class name basis).

Another way would be to use one of GDC, NDC or MDC in a PatternFormatter.

GDC will set a "Global Diagnostic Context" which is to say, it's a value that is available from all threads running a script. You can use it by putting %g in the pattern and setting the value via GDC.set(String) for more detailed information, see: http://log4r.rubyforge.org/manual.html

NDC and MDC are Nested and Mapped Diagnostic Contexts respectively. The pattern for these is to use %x and %X{Symbol|Object}, and to set them via NDC.set(String) and MDC.put(Symbol|Object, Object)

Yet another way would be to use the Pattern %t, which prints out the filename and line number of where the call was made.

The trade off between each of these methods is that they are progressively more expensive in CPU resource use. I tend to first use GDC for the sort of thing you're asking for.

like image 166
C G-K Avatar answered Oct 12 '22 00:10

C G-K


Hmm, any reason why you don't instantiate Log4r::Logger class at the beginning of your script and pass the instance around? You don't even have to pass it around, you can always get it by name from Logger class:

run.rb:

require 'log4r'
require 'class_a'

logger = Log4r::Logger.new('test')
logger.outputters << Log4r::Outputter.stdout
logger.outputters << Log4r::FileOutputter.new('logtest', :filename =>  'logtest.log')
logger.info('started script')
a = A.new
a.do_something
logger.info('finishing')

class_a.rb:

class A
  def do_something
    logger = Log4r::Logger['test']
    logger.info('in do_something')
    puts 'hi!'
  end
end

and when you run run.rb you get:

$ ruby run.rb 
 INFO test: started script
 INFO test: in do_something
hi!
 INFO test: finishing

and a log file named logtest.log on disk.

like image 26
Mladen Jablanović Avatar answered Oct 11 '22 22:10

Mladen Jablanović