Permalink
Browse files

moved to store dump in database

  • Loading branch information...
1 parent f0abe9d commit 5cf8677e422a99f94a014f4765c6520a6d3ef96d @mkristian committed Nov 3, 2011
View
20 MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008 Kristian Meier
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
2 Mavenfile
@@ -1 +1 @@
-properties["jruby.plugins.version"] = "0.26.0-SNAPSHOT"
+#properties["jruby.plugins.version"] = "0.26.0-SNAPSHOT"
View
7 ixtlan-error-handler.gemspec
@@ -19,8 +19,13 @@ Gem::Specification.new do |s|
s.files += Dir['lib/**/*']
s.files += Dir['spec/**/*']
s.test_files += Dir['spec/**/*_spec.rb']
- s.add_development_dependency 'rspec', '2.4.0'
+ s.add_dependency 'slf4r', '~> 0.4.2'
+ s.add_development_dependency 'rspec', '2.6.0'
s.add_development_dependency 'rake', '0.8.7'
+ DM_VERSION = '1.2.0'
+ s.add_development_dependency 'dm-core', DM_VERSION
+ s.add_development_dependency 'dm-migrations', DM_VERSION
+ s.add_development_dependency 'dm-sqlite-adapter', DM_VERSION
end
# vim: syntax=Ruby
View
124 lib/ixtlan/errors/error_dumper.rb
@@ -1,85 +1,109 @@
require 'ixtlan/errors/mailer'
require 'fileutils'
+require 'slf4r/logger'
+
+# unless Fixnum.respond_to? :days
+# class Fixnum
+# def days
+# self
+# end
+
+# def ago
+# DateTime.now - 86000 * self
+# end
+# end
+# end
module Ixtlan
module Errors
class ErrorDumper
- attr_accessor :dump_dir, :email_from, :email_to, :keep_dumps
+ private
+
+ include ::Slf4r::Logger
+
+ public
+
+ attr_accessor :from_email, :to_emails, :keep_dumps, :base_url
- def keep_dumps
- @keep_dumps ||= 90
+ def initialize
+ @keep_dumps = 0
end
def keep_dumps=(ttl)
@keep_dumps = ttl.to_i
- cleanup
+ daily_cleanup
end
-
- def dump_dir
- if @dump_dir.blank?
- @dump_dir = File.join(Rails.root, "log", "errors")
- FileUtils.mkdir_p(@dump_dir)
- end
- @dump_dir
+
+ def error_dump_model(model = nil)
+ @error_dump ||= model.nil? ? ::Error : model.classify
end
- def dump_dir=(dir)
- @dump_dir = dir
- FileUtils.mkdir_p(@dump_dir) unless dir.blank?
- @dump_dir
- end
-
def dump(controller, exception)
- cleanup
- log_file = log_filename
- logger = Logger.new(log_file)
+ daily_cleanup
- dump_environment(logger, exception, controller)
- Mailer.error_notification(@email_from, @email_to, exception, log_file).deliver unless (@email_to.blank? || @email_from.blank?)
- log_file
+ error = dump_environment(exception, controller)
+ Mailer.error_notification(@from_email, @to_emails, exception, "#{@base_url}/#{error.id}").deliver unless (@to_emails.blank? || @from_email.blank?)
+ "#{@base_url}/#{error.id}"
end
private
- def log_filename(time = Time.now)
- error_log_id = "#{time.tv_sec}#{time.tv_usec}"
- File.join(dump_dir, "error-#{error_log_id}.log")
- end
+ def dump_environment(exception, controller)
+ dump = error_dump_model.new
+
+ dump.request = dump_hashmap(controller.request.env)
- def dump_environment_header(logger, header)
- logger.error("\n===================================================================\n#{header}\n===================================================================\n");
- end
+ dump.response = dump_hashmap(controller.response.headers)
- def dump_environment(logger, exception, controller)
- dump_environment_header(logger, "REQUEST DUMP");
- dump_hashmap(logger, controller.request.env)
+ dump.session = dump_hashmap(controller.session)
- dump_environment_header(logger, "RESPONSE DUMP");
- dump_hashmap(logger, controller.response.headers)
+ dump.parameters = dump_hashmap(controller.params)
- dump_environment_header(logger, "SESSION DUMP");
- dump_hashmap(logger, controller.session)
+ dump.message = exception.message
+
+ dump.clazz = exception.class.to_s
+
+ dump.backtrace = exception.backtrace.join("\n") if exception.backtrace
- dump_environment_header(logger, "PARAMETER DUMP");
- map = {}
- dump_hashmap(logger, controller.params.each{ |k,v| map[k]=v })
+ dump if dump.save
+ end
- dump_environment_header(logger, "EXCEPTION");
- logger.error("#{exception.class}:#{exception.message}")
- logger.error("\t" + exception.backtrace.join("\n\t")) if exception.backtrace
+ def dump_hashmap(map, indent = '')
+ result = ''
+ map.each do |key,value|
+ if value.is_a? Hash
+ result << "#{indent}#{key} => {\n"
+ result << dump_hashmap(value, "#{indent} ")
+ result << "#{indent}}\n"
+ else
+ result << "#{indent}#{key} => #{value.nil? ? 'nil': value}\n"
+ end
+ end
+ result
end
- def dump_hashmap(logger, map)
- for key,value in map
- logger.error("\t#{key} => #{value.inspect}")
+ def daily_cleanup
+ if(@last_cleanup.nil? || @last_cleanup < 1.days.ago)
+ @last_cleanup = Date.today
+ begin
+ delete_all
+ logger.info("cleaned error dumps")
+ rescue Exception => e
+ logger.error("cleanup error dumps", e)
+ end
end
end
- def cleanup
- ref_log_file = log_filename(keep_dumps.ago)
- Dir[File.join(dump_dir, "error-*.log")].each do |f|
- FileUtils.rm(f) if File.basename(f) < ref_log_file
+ private
+
+ if defined? ::DataMapper
+ def delete_all
+ error_dump_model.all(:created_at.lte => keep_dumps.days.ago).destroy!
+ end
+ else # ActiveRecord
+ def delete_all
+ error_dump_model.all(:conditions => ["created_at <= ?", keep_dumps.days.ago]).each(&:delete)
end
end
end
View
15 lib/ixtlan/errors/error_handler.rb
@@ -14,23 +14,12 @@ def page_not_found(exception)
log_user_error(exception)
error_page(:not_found, "page not found")
end
- #status = rescue_responses[exception.class.name]
- #status = status == :internal_server_error ? :not_found : status
- #error_page(status, "page not found")
def stale_resource(exception)
log_user_error(exception)
error_page(:conflict, "stale resource")
end
- # respond_to do |format|
- # format.html {
- # render_stale_error_page
- # }
- # format.xml { head :conflict }
- # end
- # end
-
def render_error_page_with_session(status)
render :template => "errors/error_with_session", :status => status
end
@@ -39,10 +28,6 @@ def render_error_page(status)
render :template => "errors/error", :status => status
end
- # def render_stale_error_page
- # render :template => "errors/stale", :status => :conflict
- # end
-
private
if defined? ::Ixtlan::Audit
View
4 lib/ixtlan/errors/mailer.rb
@@ -2,9 +2,9 @@ module Ixtlan
module Errors
class Mailer < ActionMailer::Base
- def error_notification(email_from, emails_to, exception, error_file)
+ def error_notification(email_from, emails_to, exception, error_url)
@subject = exception.message
- @text = "#{error_file}"
+ @text = "#{error_url}"
@recipients = emails_to
@from = email_from
@sent_on = Time.now
View
7 lib/ixtlan/errors/railtie.rb
@@ -14,11 +14,8 @@ class Railtie < Rails::Railtie
ActionMailer::Base.view_paths= [ActionMailer::Base.view_paths, path].flatten
end
- app.config.class.class_eval do
- attr_accessor :error_dumper, :skip_rescue_module
- app.config.error_dumper = ErrorDumper.new
- app.config.skip_rescue_module = false
- end
+ app.config.error_dumper = ErrorDumper.new
+ app.config.skip_rescue_module = false
end
config.after_initialize do |app|
View
64 spec/error_dumper_spec.rb
@@ -1,3 +1,27 @@
+require 'dm-core'
+require 'dm-migrations'
+require 'slf4r/ruby_logger'
+
+class Error
+ include DataMapper::Resource
+
+ property :id, Serial
+
+ property :message, String
+ property :clazz, String
+ property :request, Text
+ property :response, Text
+ property :session, Text
+ property :parameters, Text
+ property :backtrace, Text
+
+ property :created_at, DateTime
+
+ before :save do
+ self.created_at = DateTime.now
+ end
+end
+
module Ixtlan
module Errors
module ActionMailer
@@ -62,8 +86,11 @@ def blank?
end
class Fixnum
+ def days
+ self
+ end
def ago
- DateTime.now - self.to_i
+ DateTime.now - 86000 * self
end
end
@@ -76,37 +103,44 @@ def tv_usec
end
end
+DataMapper.setup(:default, "sqlite3::memory:")
+DataMapper.finalize
+DataMapper.repository.auto_migrate!
+
describe Ixtlan::Errors::ErrorDumper do
before :each do
@dumper = Ixtlan::Errors::ErrorDumper.new
- @dumper.dump_dir = "target"
+ @dumper.base_url = "http://localhost"
@controller = Controller.new
end
it "should dump env and not send notification" do
- file = @dumper.dump(@controller, StandardError.new("dump it"))
- File.exists?(file).should be_true
- @dumper.email_from = "asd"
- file = @dumper.dump(@controller, StandardError.new("dump it"))
- File.exists?(file).should be_true
- @dumper.email_from = nil
- @dumper.email_to = "dsa"
- file = @dumper.dump(@controller, StandardError.new("dump it"))
- File.exists?(file).should be_true
+ url = @dumper.dump(@controller, StandardError.new("dump it"))
+ url.should =~ /http:\/\/localhost\/[0-9]+/
+ @dumper.from_email = "asd"
+ url = @dumper.dump(@controller, StandardError.new("dump it"))
+ url.should =~ /http:\/\/localhost\/[0-9]+/
+ @dumper.from_email = nil
+ @dumper.to_emails = "dsa"
+ url = @dumper.dump(@controller, StandardError.new("dump it"))
+ url.should =~ /http:\/\/localhost\/[0-9]+/
end
it "should clean up error dumps" do
+ Error.create(:message => 'msg')
+ Error.all.size.should > 0
@dumper.keep_dumps = 0
+ Error.all.size.should == 0
@dumper.dump(@controller, StandardError.new("dump it"))
- Dir['target/error-*'].size.should == 1
+ Error.all.size.should == 1
@dumper.dump(@controller, StandardError.new("dump it"))
- Dir['target/error-*'].size.should == 1
+ Error.all.size.should == 2
end
it "should send notifications" do
- @dumper.email_to = "das"
- @dumper.email_from = "asd"
+ @dumper.to_emails = "das"
+ @dumper.from_email = "asd"
@dumper.dump(@controller, StandardError.new("dump it"))
Ixtlan::Errors::ActionMailer::Base.delivered.should be_true
end

0 comments on commit 5cf8677

Please sign in to comment.