diff --git a/.changesets/do-not-log-long-error-messages-to-internal-appsignal-log.md b/.changesets/do-not-log-long-error-messages-to-internal-appsignal-log.md new file mode 100644 index 00000000..b2c6ac25 --- /dev/null +++ b/.changesets/do-not-log-long-error-messages-to-internal-appsignal-log.md @@ -0,0 +1,6 @@ +--- +bump: patch +type: fix +--- + +Do not log long (error) messages to the internal AppSignal log. If an error like `ActionController::BadRequest` occurred and the error message contained the entire file upload, this would grow the `appsignal.log` file quickly if the error happens often. Internal log messages are now truncated by default. diff --git a/lib/appsignal/utils/integration_logger.rb b/lib/appsignal/utils/integration_logger.rb index af80232e..09c48094 100644 --- a/lib/appsignal/utils/integration_logger.rb +++ b/lib/appsignal/utils/integration_logger.rb @@ -3,6 +3,31 @@ module Appsignal module Utils class IntegrationLogger < ::Logger + MAX_MESSAGE_LENGTH = 2_000 + + def add(severity, message = nil, progname = nil) + if message.nil? && !block_given? + # When called as logger.error("msg"), the message is in progname + progname = truncate_message(progname) + elsif message + message = truncate_message(message) + elsif block_given? + message = truncate_message(yield) + end + super + end + + private + + def truncate_message(message) + return message unless message.is_a?(String) + + if message.length > MAX_MESSAGE_LENGTH + "#{message[0, MAX_MESSAGE_LENGTH]}..." + else + message + end + end end end end diff --git a/spec/lib/appsignal/utils/integration_logger_spec.rb b/spec/lib/appsignal/utils/integration_logger_spec.rb index f88740dc..d58f8f5b 100644 --- a/spec/lib/appsignal/utils/integration_logger_spec.rb +++ b/spec/lib/appsignal/utils/integration_logger_spec.rb @@ -12,10 +12,58 @@ logger.info("info message") logger.warn("warning message") logger.error("error message") + logger.error(ExampleStandardError.new("example error with message")) + logger.info { "block error message" } expect(logs).to contains_log(:debug, "debug message") expect(logs).to contains_log(:info, "info message") expect(logs).to contains_log(:warn, "warning message") expect(logs).to contains_log(:error, "error message") + expect(logs).to contains_log(:error, "example error with message") + expect(logs).to contains_log(:info, "block error message") + end + + describe "message truncation" do + it "does not truncate short messages" do + logger.error("Short error message") + + expect(logs).to contains_log(:error, "Short error message") + end + + context "when calling logger.error(message)" do + it "truncates long messages" do + long_message = "a" * 2500 + logger.error(long_message) + + expect(logs).to contains_log(:error, "#{"a" * 2000}...") + end + end + + context "when calling logger.error { message }" do + it "truncates long messages passed as a block" do + long_message = "a" * 2500 + logger.error { long_message } + + expect(logs).to contains_log(:error, "#{"a" * 2000}...") + end + end + + context "when calling logger.add(severity, message)" do + it "truncates long messages" do + long_message = "a" * 2500 + logger.add(Logger::ERROR, long_message) + + expect(logs).to contains_log(:error, "#{"a" * 2000}...") + end + end + + context "when calling logger.error(progname) { message }" do + it "truncates long messages from block" do + long_message = "a" * 2500 + logger.error("progname") { long_message } + + expect(logs).to contains_log(:error, "#{"a" * 2000}...") + end + end end end