Skip to content

Commit 71fd027

Browse files
committed
feat: log foreign key constraint errors as warn as 99% of the time they are transitory and unreproducible and should not cause alarms to be raised
1 parent 1e097b3 commit 71fd027

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

lib/pact_broker/api/resources/error_handler.rb

+10-3
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ class ErrorHandler
88

99
include PactBroker::Logging
1010

11+
WARNING_ERROR_CLASSES = [Sequel::ForeignKeyConstraintViolation]
12+
1113
def self.call e, request, response
1214
error_reference = generate_error_reference
13-
if reportable?(e)
15+
if log_as_warning?(e)
16+
logger.warn("Error reference #{error_reference}", e)
17+
elsif reportable?(e)
1418
log_error(e, "Error reference #{error_reference}")
1519
report(e, error_reference, request)
16-
else
17-
logger.info "Error reference #{error_reference} - #{e.class} #{e.message}\n#{e.backtrace.join("\n")}"
20+
logger.info("Error reference #{error_reference}", e)
1821
end
1922
response.body = response_body_hash(e, error_reference).to_json
2023
end
@@ -27,6 +30,10 @@ def self.reportable?(e)
2730
!e.is_a?(PactBroker::Error) && !e.is_a?(JSON::GeneratorError)
2831
end
2932

33+
def self.log_as_warning?(e)
34+
WARNING_ERROR_CLASSES.any? { |clazz| e.is_a?(clazz) }
35+
end
36+
3037
def self.display_message(e, error_reference)
3138
if PactBroker.configuration.show_backtrace_in_error_response?
3239
e.message || obfuscated_error_message(error_reference)

lib/pact_broker/db/log_quietener.rb

+7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ def info *args
1616
def error *args
1717
if error_is_about_table_not_existing?(args)
1818
__getobj__().debug(*reassure_people_that_this_is_expected(args))
19+
elsif foreign_key_error?(args)
20+
__getobj__().warn(*args)
1921
else
2022
__getobj__().error(*args)
2123
end
@@ -28,6 +30,11 @@ def error_is_about_table_not_existing?(args)
2830
args.first.include?("no such view"))
2931
end
3032

33+
# Foreign key exceptions are almost always transitory and unreproducible by this stage
34+
def foreign_key_error?(args)
35+
args.first.is_a?(String) && args.first.downcase.include?("foreign key")
36+
end
37+
3138
def reassure_people_that_this_is_expected(args)
3239
message = args.shift
3340
message = message + " Don't panic. This happens when Sequel doesn't know if a table/view exists or not."

spec/lib/pact_broker/db/log_quietener_spec.rb

+10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ module DB
2323
end
2424
end
2525

26+
context "when the error is a foreign key constraint violation" do
27+
before do
28+
subject.error("SQLite3::ConstraintException: FOREIGN KEY constraint failed: delete from pacticipants where id = 1")
29+
end
30+
31+
it "logs the message at warn level" do
32+
expect(logs.string).to include "WARN -- :"
33+
end
34+
end
35+
2636
context "when the error is NOT for a table or view that does not exist" do
2737
before do
2838
subject.error("foo bar")

0 commit comments

Comments
 (0)