FEATURE: All 500 errors now show up in Logster
Added Discourse.handle_request_exception()
This commit is contained in:
parent
5657006aca
commit
68ccd2d664
|
@ -65,7 +65,7 @@ class ApplicationController < ActionController::Base
|
|||
ActionController::UnknownController,
|
||||
AbstractController::ActionNotFound].include? exception.class
|
||||
begin
|
||||
ErrorLog.report_async!(exception, self, request, current_user)
|
||||
Discourse.handle_request_exception(exception, self, request, current_user)
|
||||
rescue
|
||||
# dont care give up
|
||||
end
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
# TODO:
|
||||
# a mechanism to iterate through errors in reverse
|
||||
# async logging should queue, if dupe stack traces are found in batch error should be merged into prev one
|
||||
|
||||
class ErrorLog
|
||||
|
||||
@lock = Mutex.new
|
||||
|
||||
def self.filename
|
||||
"#{Rails.root}/log/#{Rails.env}_errors.log"
|
||||
end
|
||||
|
||||
def self.clear!(_guid)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def self.clear_all!()
|
||||
File.delete(ErrorLog.filename) if File.exists?(ErrorLog.filename)
|
||||
end
|
||||
|
||||
def self.report_async!(exception, controller, request, user)
|
||||
Thread.new do
|
||||
report!(exception, controller, request, user)
|
||||
end
|
||||
end
|
||||
|
||||
def self.report!(exception, controller, request, user)
|
||||
add_row!(
|
||||
date: DateTime.now,
|
||||
guid: SecureRandom.uuid,
|
||||
user_id: user && user.id,
|
||||
parameters: request && request.filtered_parameters.to_json,
|
||||
action: controller.action_name,
|
||||
controller: controller.controller_name,
|
||||
backtrace: sanitize_backtrace(exception.backtrace).join("\n"),
|
||||
message: exception.message,
|
||||
url: "#{request.protocol}#{request.env["HTTP_X_FORWARDED_HOST"] || request.env["HTTP_HOST"]}#{request.fullpath}",
|
||||
exception_class: exception.class.to_s
|
||||
)
|
||||
end
|
||||
|
||||
def self.add_row!(hash)
|
||||
data = hash.to_xml(skip_instruct: true)
|
||||
# use background thread to write the log cause it may block if it gets backed up
|
||||
@lock.synchronize do
|
||||
File.open(filename, "a") do |f|
|
||||
f.flock(File::LOCK_EX)
|
||||
f.write(data)
|
||||
f.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.each(&blk)
|
||||
skip(0, &blk)
|
||||
end
|
||||
|
||||
def self.skip(skip=0)
|
||||
pos = 0
|
||||
return [] unless File.exists?(filename)
|
||||
|
||||
loop do
|
||||
lines = ""
|
||||
File.open(self.filename, "r") do |f|
|
||||
f.flock(File::LOCK_SH)
|
||||
f.pos = pos
|
||||
while !f.eof?
|
||||
line = f.readline
|
||||
lines << line
|
||||
break if line.starts_with? "</hash>"
|
||||
end
|
||||
pos = f.pos
|
||||
end
|
||||
if lines != "" && skip == 0
|
||||
h = {}
|
||||
e = Nokogiri.parse(lines).children[0]
|
||||
e.children.each do |inner|
|
||||
h[inner.name] = inner.text
|
||||
end
|
||||
yield h
|
||||
end
|
||||
skip-=1 if skip > 0
|
||||
break if lines == ""
|
||||
end
|
||||
end
|
||||
|
||||
def self.sanitize_backtrace(trace)
|
||||
re = Regexp.new(/^#{Regexp.escape(Rails.root.to_s)}/)
|
||||
trace.map { |line| Pathname.new(line.gsub(re, "[RAILS_ROOT]")).cleanpath.to_s }
|
||||
end
|
||||
|
||||
private_class_method :sanitize_backtrace
|
||||
end
|
|
@ -26,6 +26,29 @@ module Discourse
|
|||
}.merge(context))
|
||||
end
|
||||
|
||||
def self.handle_request_exception(ex, controller, request, current_user)
|
||||
cm = RailsMultisite::ConnectionManagement
|
||||
context = {
|
||||
current_db: cm.current_db,
|
||||
current_hostname: cm.current_hostname,
|
||||
rails_action: controller.action_name,
|
||||
rails_controller: controller.controller_name,
|
||||
}
|
||||
|
||||
env = request.env.dup
|
||||
|
||||
context.each do |key, value|
|
||||
Logster.add_to_env(env, key, value)
|
||||
end
|
||||
|
||||
begin
|
||||
Thread.current[Logster::Logger::LOGSTER_ENV] = env
|
||||
Logster.logger.fatal("#{ex.class.to_s}: #{ex.message} in #{controller.controller_name}##{controller.action_name}")
|
||||
ensure
|
||||
Thread.current[Logster::Logger::LOGSTER_ENV] = nil
|
||||
end
|
||||
end
|
||||
|
||||
# Expected less matches than what we got in a find
|
||||
class TooManyMatches < Exception; end
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
require 'spec_helper'
|
||||
describe ErrorLog do
|
||||
|
||||
def boom
|
||||
raise "boom"
|
||||
end
|
||||
|
||||
def exception
|
||||
begin
|
||||
boom
|
||||
rescue => e
|
||||
return e
|
||||
end
|
||||
end
|
||||
|
||||
def controller
|
||||
DraftController.new
|
||||
end
|
||||
|
||||
def request
|
||||
ActionController::TestRequest.new(host: 'test')
|
||||
end
|
||||
|
||||
describe "add_row!" do
|
||||
it "creates a non empty file on first call" do
|
||||
ErrorLog.clear_all!
|
||||
ErrorLog.add_row!(hello: "world")
|
||||
expect(File.exists?(ErrorLog.filename)).to eq true
|
||||
end
|
||||
end
|
||||
|
||||
describe "logging data" do
|
||||
it "is able to read the data it writes" do
|
||||
ErrorLog.clear_all!
|
||||
ErrorLog.report!(exception, controller, request, nil)
|
||||
ErrorLog.report!(exception, controller, request, nil)
|
||||
i = 0
|
||||
ErrorLog.each do |h|
|
||||
i += 1
|
||||
end
|
||||
expect(i).to eq 2
|
||||
end
|
||||
|
||||
it "is able to skip rows" do
|
||||
ErrorLog.clear_all!
|
||||
ErrorLog.report!(exception, controller, request, nil)
|
||||
ErrorLog.report!(exception, controller, request, nil)
|
||||
ErrorLog.report!(exception, controller, request, nil)
|
||||
ErrorLog.report!(exception, controller, request, nil)
|
||||
i = 0
|
||||
ErrorLog.skip(3) do |h|
|
||||
i += 1
|
||||
end
|
||||
expect(i).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue