diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index fe60409f75b..01a32663258 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -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 diff --git a/app/models/error_log.rb b/app/models/error_log.rb deleted file mode 100644 index 8c7944e8625..00000000000 --- a/app/models/error_log.rb +++ /dev/null @@ -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? "" - 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 diff --git a/lib/discourse.rb b/lib/discourse.rb index 71bc387e344..eb0026b89de 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -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 diff --git a/spec/models/error_log_spec.rb b/spec/models/error_log_spec.rb deleted file mode 100644 index e0576ac8d1e..00000000000 --- a/spec/models/error_log_spec.rb +++ /dev/null @@ -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