Skip to content

Commit

Permalink
Add support for Action Cable
Browse files Browse the repository at this point in the history
Refactor log subscribers & create a new one to support logging of Action Cable events

Monkey-patch Action Cable server class to silence default Action Cable logger

Monkey-patch Action Cable Channel and Connection classes to support logging subscribe, unsubscribe, connect & disconnect events

Update log formatters to support Action Cable log data
  • Loading branch information
xlts committed Jan 8, 2019
1 parent f5ea39e commit c1d1957
Show file tree
Hide file tree
Showing 16 changed files with 639 additions and 136 deletions.
43 changes: 33 additions & 10 deletions lib/lograge.rb
@@ -1,4 +1,5 @@
require 'lograge/version'
require 'lograge/formatters/helpers/method_and_path'
require 'lograge/formatters/cee'
require 'lograge/formatters/json'
require 'lograge/formatters/graylog2'
Expand All @@ -8,11 +9,19 @@
require 'lograge/formatters/logstash'
require 'lograge/formatters/ltsv'
require 'lograge/formatters/raw'
require 'lograge/log_subscriber'
require 'lograge/log_subscribers/base'
require 'lograge/log_subscribers/action_cable'
require 'lograge/log_subscribers/action_controller'
require 'lograge/silent_logger'
require 'lograge/ordered_options'
require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/string/inflections'

if defined?(ActionCable)
require 'lograge/rails_ext/action_cable/channel/base'
require 'lograge/rails_ext/action_cable/connection/base'
end

# rubocop:disable ModuleLength
module Lograge
module_function
Expand Down Expand Up @@ -63,10 +72,14 @@ def before_format(data, payload)
def ignore_actions(actions)
ignore(lambda do |event|
params = event.payload
Array(actions).include?("#{params[:controller]}##{params[:action]}")
Array(actions).include?("#{controller_field(params)}##{params[:action]}")
end)
end

def controller_field(params)
params[:controller] || params[:channel_class] || params[:connection_class]
end

def ignore_tests
@ignore_tests ||= []
end
Expand Down Expand Up @@ -122,6 +135,8 @@ def setup(app)
keep_original_rails_log

attach_to_action_controller
attach_to_action_cable if defined?(ActionCable)

set_lograge_log_options
setup_custom_payload
support_deprecated_config # TODO: Remove with version 1.0
Expand All @@ -139,24 +154,29 @@ def set_formatter
end

def attach_to_action_controller
Lograge::RequestLogSubscriber.attach_to :action_controller
Lograge::LogSubscribers::ActionController.attach_to :action_controller
end

def attach_to_action_cable
Lograge::LogSubscribers::ActionCable.attach_to :action_cable
end

def setup_custom_payload
return unless lograge_config.custom_payload_method.respond_to?(:call)

base_controller_classes = Array(lograge_config.base_controller_class)
base_controller_classes.map! { |klass| klass.try(:constantize) }
if base_controller_classes.empty?
base_controller_classes << ActionController::Base
base_classes = Array(lograge_config.base_controller_class)
base_classes.map! { |klass| klass.try(:constantize) }
if base_classes.empty?
base_classes << ActionController::Base
base_classes << ActionCable::Channel::Base if defined?(ActionCable)
end

base_controller_classes.each do |base_controller_class|
extend_base_controller_class(base_controller_class)
base_classes.each do |base_class|
extend_base_class(base_class)
end
end

def extend_base_controller_class(klass)
def extend_base_class(klass)
append_payload_method = klass.instance_method(:append_info_to_payload)
custom_payload_method = lograge_config.custom_payload_method

Expand All @@ -181,6 +201,9 @@ def keep_original_rails_log
return if lograge_config.keep_original_rails_log

require 'lograge/rails_ext/rack/logger'

require 'lograge/rails_ext/action_cable/server/base' if defined?(ActionCable)

Lograge.remove_existing_log_subscriptions
end

Expand Down
4 changes: 3 additions & 1 deletion lib/lograge/formatters/graylog2.rb
@@ -1,6 +1,8 @@
module Lograge
module Formatters
class Graylog2
include Lograge::Formatters::Helpers::MethodAndPath

def call(data)
# Cloning because we don't want to mess with the original when mutating keys.
data_clone = data.clone
Expand All @@ -23,7 +25,7 @@ def underscore_prefix(key)
end

def short_message(data)
"[#{data[:status]}] #{data[:method]} #{data[:path]} (#{data[:controller]}##{data[:action]})"
"[#{data[:status]}]#{method_and_path_string(data)}(#{data[:controller]}##{data[:action]})"
end
end
end
Expand Down
12 changes: 12 additions & 0 deletions lib/lograge/formatters/helpers/method_and_path.rb
@@ -0,0 +1,12 @@
module Lograge
module Formatters
module Helpers
module MethodAndPath
def method_and_path_string(data)
method_and_path = [data[:method], data[:path]].compact
method_and_path.any?(&:present?) ? " #{method_and_path.join(' ')} " : ' '
end
end
end
end
end
4 changes: 3 additions & 1 deletion lib/lograge/formatters/logstash.rb
@@ -1,11 +1,13 @@
module Lograge
module Formatters
class Logstash
include Lograge::Formatters::Helpers::MethodAndPath

def call(data)
load_dependencies
event = LogStash::Event.new(data)

event['message'] = "[#{data[:status]}] #{data[:method]} #{data[:path]} (#{data[:controller]}##{data[:action]})"
event['message'] = "[#{data[:status]}]#{method_and_path_string(data)}(#{data[:controller]}##{data[:action]})"
event.to_json
end

Expand Down
121 changes: 0 additions & 121 deletions lib/lograge/log_subscriber.rb

This file was deleted.

32 changes: 32 additions & 0 deletions lib/lograge/log_subscribers/action_cable.rb
@@ -0,0 +1,32 @@
module Lograge
module LogSubscribers
class ActionCable < Base
%i(perform_action subscribe unsubscribe connect disconnect).each do |method_name|
define_method(method_name) do |event|
process_main_event(event)
end
end

private

def initial_data(payload)
{
method: {},
path: {},
format: {},
params: payload[:data],
controller: payload[:channel_class] || payload[:connection_class],
action: payload[:action]
}
end

def default_status
200
end

def extract_runtimes(event, _payload)
{ duration: event.duration.to_f.round(2) }
end
end
end
end
73 changes: 73 additions & 0 deletions lib/lograge/log_subscribers/action_controller.rb
@@ -0,0 +1,73 @@
module Lograge
module LogSubscribers
class ActionController < Base
def process_action(event)
process_main_event(event)
end

def redirect_to(event)
RequestStore.store[:lograge_location] = event.payload[:location]
end

def unpermitted_parameters(event)
RequestStore.store[:lograge_unpermitted_params] ||= []
RequestStore.store[:lograge_unpermitted_params].concat(event.payload[:keys])
end

private

def initial_data(payload)
{
method: payload[:method],
path: extract_path(payload),
format: extract_format(payload),
controller: payload[:controller],
action: payload[:action]
}
end

def extract_path(payload)
path = payload[:path]
strip_query_string(path)
end

def strip_query_string(path)
index = path.index('?')
index ? path[0, index] : path
end

if ::ActionPack::VERSION::MAJOR == 3 && ::ActionPack::VERSION::MINOR.zero?
def extract_format(payload)
payload[:formats].first
end
else
def extract_format(payload)
payload[:format]
end
end

def extract_runtimes(event, payload)
data = { duration: event.duration.to_f.round(2) }
data[:view] = payload[:view_runtime].to_f.round(2) if payload.key?(:view_runtime)
data[:db] = payload[:db_runtime].to_f.round(2) if payload.key?(:db_runtime)
data
end

def extract_location
location = RequestStore.store[:lograge_location]
return {} unless location

RequestStore.store[:lograge_location] = nil
{ location: strip_query_string(location) }
end

def extract_unpermitted_params
unpermitted_params = RequestStore.store[:lograge_unpermitted_params]
return {} unless unpermitted_params

RequestStore.store[:lograge_unpermitted_params] = nil
{ unpermitted_params: unpermitted_params }
end
end
end
end

0 comments on commit c1d1957

Please sign in to comment.