class Gallus::Log
Public: The brain of logging. All defined loggers inherit from this class.
Attributes
Public: Logger name, log level and context serializtion handler.
Public: Logger name, log level and context serializtion handler.
Public: A list with configured outputs.
Internal: Parent logger. Used for testing purposes.
Public Class Methods
Public: Returns logger registered under given name.
# File lib/gallus/log.rb, line 27 def [](name) configure(name) end
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
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
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
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
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
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
Public: Returns root logger.
# File lib/gallus/log.rb, line 84 def root @@root end
Public Instance Methods
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
Public: Shortand to Gallus::Log.global_context
.
# File lib/gallus/log.rb, line 123 def global_context(&block) self.class.global_context(&block) end
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
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
Internal: Merges data from all contexts and provides them as a single hash. Order:
-
Global context.
-
Curreant thread context.
-
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