class Gallus::Log

Public: The brain of logging. All defined loggers inherit from this class.

Attributes

level[RW]

Public: Logger name, log level and context serializtion handler.

name[RW]

Public: Logger name, log level and context serializtion handler.

output[R]

Public: A list with configured outputs.

parent[R]

Internal: Parent logger. Used for testing purposes.

Public Class Methods

[](name) click to toggle source

Public: Returns logger registered under given name.

# File lib/gallus/log.rb, line 27
def [](name)
  configure(name)
end
configure(name = '', &block) click to toggle source

Public: Configures logger with given name. When no name specified, root logger will be configured.

Example:

Gallus::Log.configure do |log|
  log.level = :INFO
  log.output << -> (event) { puts event.inspect }
end

Returns configured logger.

# File lib/gallus/log.rb, line 22
def configure(name = '', &block)
  Repository.get_or_create_logger(name, &block)
end
current_thread_context() { |current ||= {}| ... } click to toggle source

Public: Yields context for current thread. Just to conform with the behavior of global_context we’re using block call here as well.

Example:

log.current_thread_context { |ctx| ctx[:location] = "Castle Black" }
log.info("I know nothing!", name: "Jon Snow")
# => I know nothing! name="Jon Snow" location="Castle Black"
# File lib/gallus/log.rb, line 79
def current_thread_context
  yield (Thread.current[:log_context] ||= {})
end
define_log_methods!(log_level) click to toggle source

Internal: Performance magic. It dynamically defines log level methods to avoid overhead of not-logged levels. For example if log level is WARN it’ll define empty ‘trace`, `debug` and `info` methods and fully working `warn` and `error`. Effectively log methods call `log` under the hood.

# File lib/gallus/log.rb, line 39
def define_log_methods!(log_level)
  Level.each do |level|
    method_name = level.name.downcase
    remove_method(method_name) if method_defined?(method_name)

    if level >= log_level
      define_method(method_name) do |message = nil, payload = {}, &block|
        log(level, message, payload, &block)
      end
    else
      define_method(method_name) do |message = nil, payload = {}, &block|
        # supressed...
      end
    end
  end
end
delete(name) click to toggle source

Internal: For testing purposes we should be able to remove logger with given name.

# File lib/gallus/log.rb, line 32
def delete(name)
  Repository.delete_with_children(name)
end
global_context() { |global_context| ... } click to toggle source

Public: Yields global context. Only block calls are allowed since this operation must be thread-safe.

Example:

log.global_context { |ctx| ctx[:location] = "Castle Black" }
samwell_log.info("I always wanted to be a Wizard", name: "Samwell Tarly")
# => I always wanted to be a Wizard; name="Samwell Tarly" location="Castle Black"
jon_snow_log.info("I know nothing", name: "Jon Snow")
# => I know nothing; name="Jon Snow" location="Castle Black"
# File lib/gallus/log.rb, line 66
def global_context
  @@global_context_mutex.synchronize { yield @@global_context }
end
new(parent, name) { |self| ... } click to toggle source

Internal: Constructs new logger with configuration inherited from given parent. Yields itself so it can be reconfigured with a block. Don’t use this method directly. Use Gallus::Log.configure class method if you wanna define or reconfigure a logger.

# File lib/gallus/log.rb, line 101
def initialize(parent, name, &block)
  @parent, @name = parent, name.to_s

  if parent
    @output = @parent.output.dup
    self.level = @parent.level
  end

  @output ||= []

  yield self if block_given?
end
root() click to toggle source

Public: Returns root logger.

# File lib/gallus/log.rb, line 84
def root
  @@root
end

Public Instance Methods

current_thread_context(&block) click to toggle source

Public: Shortand to Gallus::Log.current_thread_context.

# File lib/gallus/log.rb, line 128
def current_thread_context(&block)
  self.class.current_thread_context(&block)
end
global_context(&block) click to toggle source

Public: Shortand to Gallus::Log.global_context.

# File lib/gallus/log.rb, line 123
def global_context(&block)
  self.class.global_context(&block)
end
level=(level) click to toggle source

Public: Changing log level means that we have to redefine logging methods.

# File lib/gallus/log.rb, line 115
def level=(level)
  level = level.is_a?(Level) ? level : Level[level.to_s]
  return if @level == level
  self.class.class_eval { define_log_methods!(level) }
  @level = level
end

Private Instance Methods

log(level, message = nil, payload = {}, &block) click to toggle source

Internal: Actual logging. Takes payload and merges it into contexts, serializes context variables using configured serialization handler and finally sends it to each defined output.

# File lib/gallus/log.rb, line 149
def log(level, message = nil, payload = {}, &block)
  message ||= block.call if block_given?
  event = Event.new(@name, level, message.to_s, merged_context.merge(payload))
  output.each { |out| out.call(event) }
end
merged_context() click to toggle source

Internal: Merges data from all contexts and provides them as a single hash. Order:

  1. Global context.

  2. Curreant thread context.

  3. Self context.

# File lib/gallus/log.rb, line 140
def merged_context
  {}.tap do |merged|
    self.class.global_context { |ctx| merged.merge!(ctx) }
    self.class.current_thread_context { |ctx| merged.merge!(ctx) }
  end
end