Skip to content

Commit

Permalink
Overwrite middleware to handle errors in logstash compatible format.
Browse files Browse the repository at this point in the history
  • Loading branch information
Marc Grimme committed Jun 30, 2016
1 parent 8e7d5df commit dc69286
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 1 deletion.
11 changes: 11 additions & 0 deletions lib/logstasher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require 'logstasher/active_record/log_subscriber'
require 'logstasher/action_view/log_subscriber'
require 'logstasher/rails_ext/action_controller/base'
require 'logstasher/rails_ext/rack/debug_exceptions'
require 'request_store'
require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/string/inflections'
Expand Down Expand Up @@ -137,6 +138,16 @@ def configured_to_suppress_app_logs?(config)
!!(config.suppress_app_log.nil? ? config.supress_app_log : config.suppress_app_log)
end

def modify_middleware(app)
if enabled
if configured_to_suppress_app_logs? app.config.logstasher
app.middleware.swap ::ActionDispatch::DebugExceptions, ::LogStasher::ActionDispatch::DebugExceptions
else
app.middleware.swap ::ActionDispatch::DebugExceptions, ::LogStasher::ActionDispatch::TwoWayDebugExceptions
end
end
end

def custom_fields
Thread.current[:logstasher_custom_fields] ||= []
end
Expand Down
38 changes: 38 additions & 0 deletions lib/logstasher/rails_ext/rack/debug_exceptions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'action_dispatch'
require 'active_support/all'

module LogStasher
module ActionDispatch
def build_exception_hash(wrapper)
exception = wrapper.exception
trace = wrapper.application_trace
trace = wrapper.framework_trace if trace.empty?

{ error:
({ exception: exception.class.name, message: exception.message, trace: trace}.
merge!( exception.respond_to?(:annotated_source_code) && { annotated_source_code: exception.annoted_source_code } || {} ))
}
end

class DebugExceptions < ::ActionDispatch::DebugExceptions
include ::LogStasher::ActionDispatch

private
def log_error(env, wrapper)
LogStasher.logger << LogStasher.build_logstash_event(build_exception_hash(wrapper), ["exception"]).to_json + "\n"
end

end

class TwoWayDebugExceptions < ::ActionDispatch::DebugExceptions
include ::LogStasher::ActionDispatch

private
def log_error(env, wrapper)
LogStasher.logger << LogStasher.build_logstash_event(build_exception_hash(wrapper), ["exception"]).to_json + "\n"

super(env, wrapper)
end
end
end
end
8 changes: 7 additions & 1 deletion lib/logstasher/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
require 'action_view/log_subscriber'
require 'action_controller/log_subscriber'
require 'socket'
require 'action_dispatch'
require 'active_support/all'

module LogStasher
class Railtie < Rails::Railtie
Expand All @@ -21,7 +23,7 @@ class Railtie < Rails::Railtie
# Load and ERB templating of YAML files
LOGSTASHER = File.exists?(config_file) ? YAML.load(ERB.new(File.read(config_file)).result).symbolize_keys : nil

initializer :logstasher, :before => :load_config_initializers do |app|
initializer :logstasher, before: :load_config_initializers do |app|
if LOGSTASHER.present?
# process common configs
LogStasher.process_config(app.config.logstasher, LOGSTASHER)
Expand All @@ -38,6 +40,10 @@ class Railtie < Rails::Railtie
LogStasher.setup(config.logstasher) if config.logstasher.enabled
end
end

initializer 'logstasher.insert_middleware', after: :load_config_initializers do |app|
LogStasher.modify_middleware app
end
end

def process_config(config, yml_config)
Expand Down
72 changes: 72 additions & 0 deletions spec/lib/logstasher/rails_ext/rack/debug_exceptions_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
require 'spec_helper'

shared_examples 'MyApp' do
before do
class MyApp
def initialize()
end
def call(*args)
raise Exception.new("My Exception")
end
end
end

let(:app) { MyApp.new }
let(:environment) { { 'action_dispatch.show_exceptions' => true } }
let(:logger) { double }
subject{ described_class.new(app) }

before(:each) do
allow(LogStasher).to receive(:logger).and_return(logger)
allow(LogStasher.logger).to receive(:'<<').and_return(true)
end
end

shared_examples 'build_exception_hash' do
describe '#build_exception_hash' do
let (:wrapper) { double(exception: Exception.new("My Exception"), application_trace: [ "line5" ]) }
it do
hash = subject.build_exception_hash(wrapper)

expect(hash).to match({:error=>{:exception=>"Exception", :message=>"My Exception", :trace=>["line5"]}})
end
end
end

describe ::LogStasher::ActionDispatch::DebugExceptions do
include_examples 'MyApp'

describe 'calls LogStasher.logger with json format exception' do
describe '#log_error' do
it do
expect(LogStasher).to receive(:build_logstash_event)
expect(LogStasher.logger).to receive(:'<<').and_return(true)
expect{ subject.call(environment) }.to raise_error(Exception, "My Exception")
end
end
end

include_examples 'build_exception_hash'
end

describe ::LogStasher::ActionDispatch::TwoWayDebugExceptions do
include_examples 'MyApp'

let(:logger_2nd) { double }
before(:each) do
allow(subject).to receive(:logger).and_return(logger_2nd)
end

describe 'calls LogStasher.logger with json format exception' do
describe '#log_error' do
it do
expect(LogStasher).to receive(:build_logstash_event)
expect(LogStasher.logger).to receive(:'<<').and_return(true)
expect(logger_2nd).to receive(:fatal).and_return(true)
expect{ subject.call(environment) }.to raise_error(Exception, "My Exception")
end
end
end

include_examples 'build_exception_hash'
end

0 comments on commit dc69286

Please sign in to comment.