Class: Logging::Logger

Inherits:
Object
  • Object
show all
Defined in:
lib/logging/logger.rb

Overview

The Logger class is the primary interface to the Logging framework. It provides the logging methods that will be called from user methods, and it generates logging events that are sent to the appenders (the appenders take care of sending the log events to the logging destinations – files, sockets, etc).

Logger instances are obtained from the Repository and should not be directly created by users.

Example:

log = Logging::Logger['my logger']
log.add_appenders( Logging::Appender.stdout )   # append to STDOUT
log.level = :info                               # log 'info' and above

log.info 'starting foo operation'
...
log.info 'finishing foo operation'
...
log.fatal 'unknown exception', exception

Direct Known Subclasses

RootLogger

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ Logger

call-seq:

Logger.new( name )
Logger[name]

Returns the logger identified by name.

When name is a String or a Symbol it will be used “as is” to retrieve the logger. When name is a Class the class name will be used to retrieve the logger. When name is an object the name of the object’s class will be used to retrieve the logger.

Example:

obj = MyClass.new

log1 = Logger.new(obj)
log2 = Logger.new(MyClass)
log3 = Logger['MyClass']

log1.object_id == log2.object_id         # => true
log2.object_id == log3.object_id         # => true


139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/logging/logger.rb', line 139

def initialize( name )
  case name
  when String
    raise(ArgumentError, "logger must have a name") if name.empty?
  else raise(ArgumentError, "logger name must be a String") end

  repo = ::Logging::Repository.instance
  @name = name
  @parent = repo.parent(name)
  @appenders = []
  @additive = true
  @trace = false
  self.level = @parent.level

  repo.children(name).each {|c| c.parent = self}
end

Instance Attribute Details

#additiveObject

class << self



115
116
117
# File 'lib/logging/logger.rb', line 115

def additive
  @additive
end

#levelObject

class << self



115
116
117
# File 'lib/logging/logger.rb', line 115

def level
  @level
end

#nameObject (readonly)

class << self



115
116
117
# File 'lib/logging/logger.rb', line 115

def name
  @name
end

#parentObject

class << self



115
116
117
# File 'lib/logging/logger.rb', line 115

def parent
  @parent
end

#traceObject

class << self



115
116
117
# File 'lib/logging/logger.rb', line 115

def trace
  @trace
end

Class Method Details

.define_log_methods(logger) ⇒ Object

This is where the actual logging methods are defined. Two methods are created for each log level. The first is a query method used to determine if that perticular logging level is enabled. The second is the actual logging method that accepts a list of objects to be logged or a block. If a block is given, then the object returned from the block will be logged.

Example

log = Logging::Logger['my logger']
log.level = :warn

log.info?                               # => false
log.warn?                               # => true
log.warn 'this is your last warning'
log.fatal 'I die!', exception

log.debug do
  # expensive method to construct log message
  msg
end


87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/logging/logger.rb', line 87

def define_log_methods( logger )
  ::Logging::LEVELS.each do |name,num|
    code =  "undef :#{name}  if method_defined? :#{name}\n"
    code << "undef :#{name}? if method_defined? :#{name}?\n"

    if logger.level > num
      code << <<-CODE
        def #{name}?( ) false end
        def #{name}( data = nil ) false end
      CODE
    else
      code << <<-CODE
        def #{name}?( ) true end
        def #{name}( data = nil )
          data = yield if block_given?
          log_event(::Logging::LogEvent.new(@name, #{num}, data, @trace))
          true
        end
      CODE
    end

    logger.meta_eval code
  end
end

.new(*args) ⇒ Object Also known as: []

Overrides the new method such that only one Logger will be created for any given logger name.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/logging/logger.rb', line 48

def new( *args )
  return super if args.empty?

  repo = ::Logging::Repository.instance
  name = repo.to_key(args.shift)

  @mutex.synchronize do
    logger = repo[name]
    if logger.nil?
      logger = super(name, *args)
      repo[name] = logger
    end
    logger
  end
end

.rootObject

call-seq:

Logger.root

Returns the root logger.



39
40
41
# File 'lib/logging/logger.rb', line 39

def root
  ::Logging::Repository.instance[:root]
end

Instance Method Details

#<<(msg) ⇒ Object

call-seq:

log << "message"

Log the given message without any formatting and without performing any level checks. The message is logged to all appenders. The message is passed up the logger tree if this logger’s additivity is true.



177
178
179
180
# File 'lib/logging/logger.rb', line 177

def <<( msg )
  @appenders.each {|a| a << msg}
  @parent << msg if @additive
end

#<=>(other) ⇒ Object

call-seq:

log <=> other

Compares this logger by name to another logger. The normal return codes for String objects apply.



162
163
164
165
166
167
168
# File 'lib/logging/logger.rb', line 162

def <=>( other )
  case other
  when self; 0
  when ::Logging::RootLogger; 1
  when ::Logging::Logger; @name <=> other.name
  else raise ArgumentError, 'expecting a Logger instance' end
end

#add(lvl, data = nil) ⇒ Object

call-seq:

add( severity, message = nil ) {block}

Log a message if the given severity is high enough. This is the generic logging method. Users will be more inclined to use #debug, #info, #warn, #error, and #fatal.

Message format: message can be any object, but it has to be converted to a String in order to log it. The Logging::format_as method is used to determine how objects chould be converted to strings. Generally, inspect is used.

A special case is an Exception object, which will be printed in detail, including message, class, and backtrace.

If a message is not given, then the return value from the block is used as the message to log. This is useful when creating the actual message is an expensive operation. This allows the logger to check the severity against the configured level before actually constructing the message.

This method returns true if the message was logged, and false is returned if the message was not logged.



206
207
208
209
210
211
212
213
# File 'lib/logging/logger.rb', line 206

def add( lvl, data = nil )
  lvl = Integer(lvl)
  return false if lvl < level

  data = yield if block_given?
  log_event(::Logging::LogEvent.new(@name, lvl, data, @trace))
  true
end

#add_appenders(*args) ⇒ Object

call-seq:

add_appenders( appenders )

Add the given appenders to the list of appenders, where appenders can be either a single appender or an array of appenders.



308
309
310
311
312
313
314
315
# File 'lib/logging/logger.rb', line 308

def add_appenders( *args )
  args.flatten.each do |arg|
    o = arg.kind_of?(::Logging::Appender) ? arg : ::Logging::Appender[arg]
    raise ArgumentError, "unknown appender '#{arg}'" if o.nil?
    @appenders << o unless @appenders.include?(o)
  end
  self
end

#appenders=(args) ⇒ Object

call-seq:

appenders = app

Clears the current list of appenders and replaces them with app, where app can be either a single appender or an array of appenders.



297
298
299
300
# File 'lib/logging/logger.rb', line 297

def appenders=( args )
  @appenders.clear
  add_appenders(*args) unless args.nil?
end

#clear_appendersObject

call-seq:

clear_appenders

Remove all appenders from this logger.



344
# File 'lib/logging/logger.rb', line 344

def clear_appenders( ) @appenders.clear end

#meta_eval(code) ⇒ Object

call-seq:

meta_eval( code )

Evaluates the given string of code if the singleton class of this Logger object.



378
379
380
381
# File 'lib/logging/logger.rb', line 378

def meta_eval( code )
  meta = class << self; self end
  meta.class_eval code
end

#remove_appenders(*args) ⇒ Object

call-seq:

remove_appenders( appenders )

Remove the given appenders from the list of appenders. The appenders to remove can be identified either by name using a String or by passing the appender instance. appenders can be a single appender or an array of appenders.



325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/logging/logger.rb', line 325

def remove_appenders( *args )
  args.flatten.each do |arg|
    @appenders.delete_if do |a|
      case arg
      when String; arg == a.name
      when ::Logging::Appender; arg.object_id == a.object_id
      else
        raise ArgumentError, "#{arg.inspect} is not a 'Logging::Appender'"
      end
    end
  end
  self
end