123456789_123456789_123456789_123456789_123456789_

Class: ActiveSupport::LogSubscriber

Relationships & Source Files
Namespace Children
Modules:
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Subscriber
Instance Chain:
self, Subscriber
Inherits: ActiveSupport::Subscriber
Defined in: activesupport/lib/active_support/log_subscriber.rb,
activesupport/lib/active_support/log_subscriber/test_helper.rb

Overview

LogSubscriber is an object set to consume Notifications with the sole purpose of logging them. The log subscriber dispatches notifications to a registered object based on its given namespace.

An example would be Active Record log subscriber responsible for logging queries:

module ActiveRecord
  class LogSubscriber < ActiveSupport::LogSubscriber
    attach_to :active_record

    def sql(event)
      info "#{event.payload[:name]} (#{event.duration}) #{event.payload[:sql]}"
    end
  end
end

ActiveRecord::LogSubscriber.logger must be set as well, but it is assigned automatically in a Rails environment.

After configured, whenever a "sql.active_record" notification is published, it will properly dispatch the event (ActiveSupport::Notifications::Event) to the sql method.

Being an Notifications consumer, LogSubscriber exposes a simple interface to check if instrumented code raises an exception. It is common to log a different message in case of an error, and this can be achieved by extending the previous example:

module ActiveRecord
  class LogSubscriber < ActiveSupport::LogSubscriber
    def sql(event)
      exception = event.payload[:exception]

      if exception
        exception_object = event.payload[:exception_object]

        error "[ERROR] #{event.payload[:name]}: #{exception.join(', ')} " \
              "(#{exception_object.backtrace.first})"
      else
        # standard logger code
      end
    end
  end
end

LogSubscriber also has some helpers to deal with logging. For example, .flush_all! will ensure that all logs are flushed, and it is called in ::Rails::Rack::Logger after a request finishes.

Constant Summary

Class Attribute Summary

Subscriber - Inherited

Class Method Summary

Subscriber - Inherited

.attach_to

Attach the subscriber to a namespace.

.detach_from

Detach the subscriber from a namespace.

.method_added

Adds event subscribers for all new methods added to the class.

.new, .subscribers, .add_event_subscriber, .fetch_public_methods, .find_attached_subscriber, .invalid_event?, .pattern_subscribed?, .prepare_pattern, .remove_event_subscriber

Instance Attribute Summary

Subscriber - Inherited

Instance Method Summary

Subscriber - Inherited

Constructor Details

.newLogSubscriber

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 133

def initialize
  super
  @event_levels = {}
end

Class Attribute Details

.colorize_logging (rw) Also known as: #colorize_logging

[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 83

mattr_accessor :colorize_logging, default: true

.log_levels (rw)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 84

class_attribute :log_levels, instance_accessor: false, default: {} # :nodoc:

.log_levels?Boolean (rw)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 84

class_attribute :log_levels, instance_accessor: false, default: {} # :nodoc:

.logger (rw)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 93

def logger
  @logger ||= if defined?(Rails) && Rails.respond_to?(:logger)
    Rails.logger
  end
end

.logger=(value) (rw)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 105

attr_writer :logger

Class Method Details

.attach_to

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 99

def attach_to(...) # :nodoc:
  result = super
  set_event_levels
  result
end

.fetch_public_methods(subscriber, inherit_all) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 117

def fetch_public_methods(subscriber, inherit_all)
  subscriber.public_methods(inherit_all) - LogSubscriber.public_instance_methods(true)
end

.flush_all!

This method is for internal use only.

Flush all log_subscribers’ logger.

[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 112

def flush_all!
  logger.flush if logger.respond_to?(:flush)
end

.log_subscribers

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 107

def log_subscribers
  subscribers
end

.set_event_levels (private)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 121

def set_event_levels
  if subscriber
    subscriber.event_levels = log_levels.transform_keys { |k| "#{k}.#{namespace}" }
  end
end

.subscribe_log_level(method, level) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 127

def subscribe_log_level(method, level)
  self.log_levels = log_levels.merge(method => LEVEL_CHECKS.fetch(level))
  set_event_levels
end

Instance Attribute Details

#colorize_logging (rw)

[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 83

mattr_accessor :colorize_logging, default: true

#event_levels=(value) (writeonly)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 158

attr_writer :event_levels # :nodoc:

Instance Method Details

#call(event)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 146

def call(event)
  super if logger
rescue => e
  log_exception(event.name, e)
end

#color(text, color, mode_options = {}) (private)

This method is for internal use only.

Set color by using a symbol or one of the defined constants. Set modes by specifying bold, italic, or underline options. Inspired by Highline, this method will automatically clear formatting at the end of the returned ::String.

[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 172

def color(text, color, mode_options = {}) # :doc:
  return text unless colorize_logging
  color = self.class.const_get(color.upcase) if color.is_a?(Symbol)
  mode = mode_from(mode_options)
  clear = "\e[#{MODES[:clear]}m"
  "#{mode}#{color}#{text}#{clear}"
end

#log_exception(name, e) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 186

def log_exception(name, e)
  ActiveSupport.error_reporter.report(e, source: name)

  if logger
    logger.error "Could not log #{name.inspect} event. #{e.class}: #{e.message} #{e.backtrace}"
  end
end

#logger

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 138

def logger
  LogSubscriber.logger
end

#mode_from(options) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 180

def mode_from(options)
  modes = MODES.values_at(*options.compact_blank.keys)

  "\e[#{modes.join(";")}m" if modes.any?
end

#publish_event(event)

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 152

def publish_event(event)
  super if logger
rescue => e
  log_exception(event.name, e)
end

#silenced?(event) ⇒ Boolean

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/log_subscriber.rb', line 142

def silenced?(event)
  logger.nil? || @event_levels[event]&.call(logger)
end