module LogStasher

Constants

REQUEST_CONTEXT_KEY
STORE_KEY
VERSION

Attributes

backtrace[RW]
controller_monkey_patch[RW]
enabled[RW]
log_controller_parameters[RW]
logger[RW]
logger_path[RW]
source[RW]

Public Instance Methods

add_custom_fields(&block) click to toggle source
# File lib/logstasher.rb, line 61
def add_custom_fields(&block)
  wrapped_block = Proc.new do |fields|
    LogStasher.custom_fields.concat(LogStasher.store.keys)
    instance_exec(fields, &block)
  end
  ::ActionController::Metal.send(:define_method, :logtasher_add_custom_fields_to_payload, &wrapped_block)
  ::ActionController::Base.send(:define_method, :logtasher_add_custom_fields_to_payload, &wrapped_block)
end
add_custom_fields_to_request_context(&block) click to toggle source
# File lib/logstasher.rb, line 70
def add_custom_fields_to_request_context(&block)
  wrapped_block = Proc.new do |fields|
    instance_exec(fields, &block)
    LogStasher.custom_fields.concat(fields.keys)
  end
  ::ActionController::Metal.send(:define_method, :logstasher_add_custom_fields_to_request_context, &wrapped_block)
  ::ActionController::Base.send(:define_method, :logstasher_add_custom_fields_to_request_context, &wrapped_block)
end
add_default_fields_to_payload(payload, request) click to toggle source
# File lib/logstasher.rb, line 50
def add_default_fields_to_payload(payload, request)
  payload[:ip] = request.remote_ip
  payload[:route] = "#{request.params[:controller]}##{request.params[:action]}"
  payload[:request_id] = request.env['action_dispatch.request_id']
  self.custom_fields += [:ip, :route, :request_id]
  if self.log_controller_parameters
    payload[:parameters] = payload[:params].except(*::ActionController::LogSubscriber::INTERNAL_PARAMS)
    self.custom_fields += [:parameters]
  end
end
add_default_fields_to_request_context(request) click to toggle source
# File lib/logstasher.rb, line 79
def add_default_fields_to_request_context(request)
  request_context[:request_id] = request.env['action_dispatch.request_id']
end
build_logstash_event(data, tags) click to toggle source
# File lib/logstasher.rb, line 178
def build_logstash_event(data, tags)
  ::LogStash::Event.new(data.merge('source' => self.source, 'tags' => tags))
end
called_as_console?() click to toggle source
# File lib/logstasher.rb, line 124
def called_as_console?
  defined?(Rails::Console) && true || false
end
called_as_rake?() click to toggle source
# File lib/logstasher.rb, line 120
def called_as_rake?
  File.basename($0) == 'rake'
end
clear_request_context() click to toggle source
# File lib/logstasher.rb, line 83
def clear_request_context
  request_context.clear
end
configured_to_suppress_app_logs?(config) click to toggle source
# File lib/logstasher.rb, line 135
def configured_to_suppress_app_logs?(config)
  # This supports both spellings: "suppress_app_log" and "supress_app_log"
  !!(config.suppress_app_log.nil? ? config.supress_app_log : config.suppress_app_log)
end
custom_fields() click to toggle source
# File lib/logstasher.rb, line 140
def custom_fields
  Thread.current[:logstasher_custom_fields] ||= []
end
custom_fields=(val) click to toggle source
# File lib/logstasher.rb, line 144
def custom_fields=(val)
  Thread.current[:logstasher_custom_fields] = val
end
enabled?() click to toggle source
# File lib/logstasher.rb, line 210
def enabled?
  self.enabled || false
end
log(severity, message, additional_fields={}) click to toggle source

Log an arbitrary message.

Usually invoked by the level-based wrapper methods defined below.

Examples

LogStasher.info("message")
LogStasher.info("message", tags:"tag1")
LogStasher.info("message", tags:["tag1", "tag2"])
LogStasher.info("message", timing:1234)
LogStasher.info(custom1:"yes", custom2:"no")
# File lib/logstasher.rb, line 159
def log(severity, message, additional_fields={})
  if self.logger && self.logger.send("#{severity}?")

    data = {'level' => severity}
    if message.respond_to?(:to_hash)
      data.merge!(message.to_hash)
    else
      data['message'] = message
    end

    # tags get special handling
    tags = Array(additional_fields.delete(:tags) || 'log')

    data.merge!(additional_fields)
    self.logger << build_logstash_event(data, tags).to_json + "\n"

  end
end
remove_existing_log_subscriptions() click to toggle source
# File lib/logstasher.rb, line 24
def remove_existing_log_subscriptions
  ::ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
    case subscriber.class.name
      when 'ActionView::LogSubscriber'
        unsubscribe(:action_view, subscriber)
      when 'ActionController::LogSubscriber'
        unsubscribe(:action_controller, subscriber)
      when 'ActionMailer::LogSubscriber'
        unsubscribe(:action_mailer, subscriber)
      when 'ActiveRecord::LogSubscriber'
        unsubscribe(:active_record, subscriber)
    end
  end
end
request_context() click to toggle source
# File lib/logstasher.rb, line 190
def request_context
  RequestStore.store[REQUEST_CONTEXT_KEY] ||= {}
end
set_data_for_console() click to toggle source
# File lib/logstasher.rb, line 116
def set_data_for_console
  self.request_context['request_id'] = "#{Process.pid}" if self.called_as_console?
end
set_data_for_rake() click to toggle source
# File lib/logstasher.rb, line 112
def set_data_for_rake
  self.request_context['request_id'] = ::Rake.application.top_level_tasks if self.called_as_rake?
end
setup(config) click to toggle source
# File lib/logstasher.rb, line 96
def setup(config)
  # Path instrumentation class to insert our hook
  if (! config.controller_monkey_patch && config.controller_monkey_patch != false) || config.controller_monkey_patch == true 
    require 'logstasher/rails_ext/action_controller/metal/instrumentation'
  end
  self.suppress_app_logs(config)
  self.logger_path = config.logger_path || "#{Rails.root}/log/logstash_#{Rails.env}.log"
  self.logger = config.logger || new_logger(self.logger_path)
  self.logger.level = config.log_level || Logger::WARN
  self.source = config.source unless config.source.nil?
  self.log_controller_parameters = !! config.log_controller_parameters
  self.backtrace = !! config.backtrace unless config.backtrace.nil?
  self.set_data_for_rake
  self.set_data_for_console
end
setup_before(config) click to toggle source
# File lib/logstasher.rb, line 87
def setup_before(config)
  require 'logstash-event'
  self.enabled = config.enabled
  LogStasher::ActiveSupport::LogSubscriber.attach_to :action_controller
  LogStasher::ActiveSupport::MailerLogSubscriber.attach_to :action_mailer
  LogStasher::ActiveRecord::LogSubscriber.attach_to :active_record
  LogStasher::ActionView::LogSubscriber.attach_to :action_view
end
store() click to toggle source
# File lib/logstasher.rb, line 182
def store
  if RequestStore.store[STORE_KEY].nil?
    # Get each store it's own private Hash instance.
    RequestStore.store[STORE_KEY] = Hash.new { |hash, key| hash[key] = {} }
  end
  RequestStore.store[STORE_KEY]
end
suppress_app_logs(config) click to toggle source
# File lib/logstasher.rb, line 128
def suppress_app_logs(config)
  if configured_to_suppress_app_logs?(config)
    require 'logstasher/rails_ext/rack/logger'
    LogStasher.remove_existing_log_subscriptions
  end
end
unsubscribe(component, subscriber) click to toggle source
# File lib/logstasher.rb, line 39
def unsubscribe(component, subscriber)
  events = subscriber.public_methods(false).reject{ |method| method.to_s == 'call' }
  events.each do |event|
    ::ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
      if listener.instance_variable_get('@delegate') == subscriber
        ::ActiveSupport::Notifications.unsubscribe listener
      end
    end
  end
end
watch(event, opts = {}, &block) click to toggle source
# File lib/logstasher.rb, line 194
def watch(event, opts = {}, &block)
  event_group = opts[:event_group] || event
  ::ActiveSupport::Notifications.subscribe(event) do |*args|
    # Calling the processing block with the Notification args and the store
    block.call(*args, store[event_group])
  end
end

Private Instance Methods

new_logger(path) click to toggle source
# File lib/logstasher.rb, line 216
def new_logger(path)
  if path.is_a? String
    FileUtils.touch path # prevent autocreate messages in log
  end
  Logger.new path
end