mirror of
https://github.com/discourse/discourse.git
synced 2025-04-18 08:39:05 +08:00
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,
|
ActionController::UnknownController,
|
||||||
AbstractController::ActionNotFound].include? exception.class
|
AbstractController::ActionNotFound].include? exception.class
|
||||||
begin
|
begin
|
||||||
ErrorLog.report_async!(exception, self, request, current_user)
|
Discourse.handle_request_exception(exception, self, request, current_user)
|
||||||
rescue
|
rescue
|
||||||
# dont care give up
|
# dont care give up
|
||||||
end
|
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))
|
}.merge(context))
|
||||||
end
|
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
|
# Expected less matches than what we got in a find
|
||||||
class TooManyMatches < Exception; end
|
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…
x
Reference in New Issue
Block a user