From ef02add1d404a844db2bb42f5e7c95d79b6a25d4 Mon Sep 17 00:00:00 2001 From: Wout Date: Wed, 17 Jun 2020 19:43:34 +0100 Subject: [PATCH 01/18] Move from Logger to Log, fix failing specs, bump to Crystal 0.35.0 (#65) --- shard.yml | 4 +- spec/raven/client_spec.cr | 2 +- spec/raven/event_spec.cr | 1 + spec/raven/instance_spec.cr | 37 +++++++++---------- spec/raven/logger_spec.cr | 23 ++++++++++-- spec/raven/processors/sanitize_data_spec.cr | 24 ++++++------ spec/raven/processors/utf8_conversion_spec.cr | 2 +- src/raven/backtrace.cr | 4 +- src/raven/client.cr | 26 ++++++++----- src/raven/configuration.cr | 8 ++-- src/raven/event.cr | 2 +- src/raven/instance.cr | 12 ++++-- src/raven/logger.cr | 10 ++--- src/raven/transports/http.cr | 6 +-- 14 files changed, 94 insertions(+), 67 deletions(-) diff --git a/shard.yml b/shard.yml index 37c37f5..0b2fdca 100644 --- a/shard.yml +++ b/shard.yml @@ -15,12 +15,12 @@ development_dependencies: version: ~> 0.4.0 ameba: github: crystal-ameba/ameba - version: ~> 0.11.0 + version: ~> 0.12.0 targets: crash_handler: main: src/crash_handler.cr -crystal: 0.32.0 +crystal: 0.35.0 license: MIT diff --git a/spec/raven/client_spec.cr b/spec/raven/client_spec.cr index 97683ec..0570efd 100644 --- a/spec/raven/client_spec.cr +++ b/spec/raven/client_spec.cr @@ -96,7 +96,7 @@ describe Raven::Client do last_event[:options].should eq({:content_type => "application/octet-stream"}) last_event[:data].should be_a(String) io = IO::Memory.new(last_event[:data].as(String)) - Gzip::Reader.open(io) do |gzip| + Compress::Gzip::Reader.open(io) do |gzip| data = JSON.parse(gzip.gets_to_end) data.as_h?.should_not be_nil data["event_id"].should eq(event.id) diff --git a/spec/raven/event_spec.cr b/spec/raven/event_spec.cr index 4848d11..a364a69 100644 --- a/spec/raven/event_spec.cr +++ b/spec/raven/event_spec.cr @@ -104,6 +104,7 @@ describe Raven::Event do context "with tags context specified" do it "merges tags data" do + Raven::Context.clear! Raven.tags_context({"key" => "value"}) with_event_hash(tags: {"foo" => "bar"}, clear: false) do |hash| diff --git a/spec/raven/instance_spec.cr b/spec/raven/instance_spec.cr index adff4d4..869301b 100644 --- a/spec/raven/instance_spec.cr +++ b/spec/raven/instance_spec.cr @@ -1,4 +1,5 @@ require "../spec_helper" +require "log/spec" module Raven::Test class BaseException < ::Exception; end @@ -16,25 +17,20 @@ private class InstanceTest < Raven::Instance end end -private class LoggerTest < Raven::Logger - getter infos = [] of String - - def info(message, *args) - super.tap do - @infos << message - end - end -end - -def build_configuration +def build_instance_configuration Raven::Configuration.new.tap do |config| config.dsn = "dummy://12345:67890@sentry.localdomain:3000/sentry/42" - config.logger = LoggerTest.new(nil) + config.logger = Raven::Logger.new(Log::MemoryBackend.new, :info) end end def with_instance(context = nil) - yield InstanceTest.new(context, build_configuration) + yield InstanceTest.new(context, build_instance_configuration) +end + +private def get_logs_from_backend(instance : InstanceTest) + backend = instance.logger.backend.as(Log::MemoryBackend) + Log::EntriesChecker.new(backend.entries) end describe Raven::Instance do @@ -215,7 +211,8 @@ describe Raven::Instance do instance.configuration.silence_ready = false instance.report_status - instance.logger.as(LoggerTest).infos.should contain(ready_message) + + get_logs_from_backend(instance).check(:info, ready_message) end end @@ -224,7 +221,8 @@ describe Raven::Instance do instance.configuration.silence_ready = true instance.report_status - instance.logger.as(LoggerTest).infos.should_not contain(ready_message) + + get_logs_from_backend(instance).empty end end @@ -234,7 +232,8 @@ describe Raven::Instance do instance.configuration.dsn = "dummy://foo" instance.report_status - instance.logger.as(LoggerTest).infos.first.should contain(not_ready_message) + + get_logs_from_backend(instance).check(:info, /#{not_ready_message}/) end end @@ -244,9 +243,9 @@ describe Raven::Instance do instance.configuration.environments = %w(production) instance.report_status - instance.logger.as(LoggerTest).infos.should contain( - "#{not_ready_message}: Not configured to send/capture in environment 'default'" - ) + + get_logs_from_backend(instance) + .check(:info, "#{not_ready_message}: Not configured to send/capture in environment 'default'") end end end diff --git a/spec/raven/logger_spec.cr b/spec/raven/logger_spec.cr index 4c3ebec..cf153d7 100644 --- a/spec/raven/logger_spec.cr +++ b/spec/raven/logger_spec.cr @@ -1,12 +1,29 @@ require "../spec_helper" +require "log/spec" describe Raven::Logger do + it "should log to a given backend" do + backend = Log::MemoryBackend.new + log = Raven::Logger.new(backend, :info) + + log.info { "Oh YAZ!" } + log.fatal { "Oh noes!" } + + logs = Log::EntriesChecker.new(backend.entries) + + logs.check(:info, "Oh YAZ!") + logs.next(:fatal, "Oh noes!") + end + it "should log to a given IO" do io = IO::Memory.new + backend = Log::IOBackend.new(io) + log = Raven::Logger.new(backend, :info) - logger = Raven::Logger.new(io) - logger.fatal("Oh noes!") + log.info { "Oh YAZ!" } + log.fatal { "Oh noes!" } - io.to_s.should match(/FATAL -- sentry: Oh noes!\n\Z/) + io.to_s.should match(/INFO - sentry: Oh YAZ!\n/) + io.to_s.should match(/FATAL - sentry: Oh noes!\n\Z/) end end diff --git a/spec/raven/processors/sanitize_data_spec.cr b/spec/raven/processors/sanitize_data_spec.cr index 73913b5..b84d2e9 100644 --- a/spec/raven/processors/sanitize_data_spec.cr +++ b/spec/raven/processors/sanitize_data_spec.cr @@ -9,9 +9,11 @@ end STRING_MASK = Raven::Processor::SanitizeData::STRING_MASK INT_MASK = Raven::Processor::SanitizeData::INT_MASK -describe Raven::Processor::SanitizeData do - processor = build_processor(Raven::Processor::SanitizeData) +private def test_processor + build_processor(Raven::Processor::SanitizeData) +end +describe Raven::Processor::SanitizeData do context "configuration for sanitize fields" do it "should union default sanitize fields with user-defined sanitize fields" do with_processor(SanitizeDataTest) do |processor| @@ -133,7 +135,7 @@ describe Raven::Processor::SanitizeData do }, } - result = processor.process(data_with_embedded_json) + result = test_processor.process(data_with_embedded_json) result = result.to_any_json JSON.parse(result["data", "json"].as(String)).should eq(%w(foo bar)) @@ -148,7 +150,7 @@ describe Raven::Processor::SanitizeData do }, } - result = processor.process(data_with_invalid_json) + result = test_processor.process(data_with_invalid_json) result = result.to_any_json expect_raises(JSON::ParseException) do @@ -162,7 +164,7 @@ describe Raven::Processor::SanitizeData do "ccnumba_int" => 4242424242424242, } - result = processor.process(data) + result = test_processor.process(data) result["ccnumba"].should eq(STRING_MASK) result["ccnumba_int"].should eq(INT_MASK) @@ -192,7 +194,7 @@ describe Raven::Processor::SanitizeData do "symbol_hash_array" => [{:password => "secret"}], } - result = processor.process(data) + result = test_processor.process(data) result["string_hash_array"].should eq([{"password" => STRING_MASK}]) result["symbol_hash_array"].should eq([{:password => STRING_MASK}]) @@ -208,7 +210,7 @@ describe Raven::Processor::SanitizeData do }, } - result = processor.process(data) + result = test_processor.process(data) result = result.to_any_json result["sentry.interfaces.Http", "data", "query_string"].as(String).should_not contain("secret") @@ -223,7 +225,7 @@ describe Raven::Processor::SanitizeData do }, } - result = processor.process(data) + result = test_processor.process(data) result = result.to_any_json result["sentry.interfaces.Http", "data", :query_string].as(String).should_not contain("secret") @@ -238,7 +240,7 @@ describe Raven::Processor::SanitizeData do }, } - result = processor.process(data) + result = test_processor.process(data) result.should eq(data) end @@ -252,7 +254,7 @@ describe Raven::Processor::SanitizeData do }, } - result = processor.process(data) + result = test_processor.process(data) result.should eq(data) end end @@ -264,7 +266,7 @@ describe Raven::Processor::SanitizeData do :millis_since_epoch => "1507671610403", } - result = processor.process(data) + result = test_processor.process(data) result.should eq(data) end end diff --git a/spec/raven/processors/utf8_conversion_spec.cr b/spec/raven/processors/utf8_conversion_spec.cr index 91a5f35..f6c047a 100644 --- a/spec/raven/processors/utf8_conversion_spec.cr +++ b/spec/raven/processors/utf8_conversion_spec.cr @@ -27,7 +27,7 @@ describe Raven::Processor::UTF8Conversion do it "should retain #cause and #callstack in cleaned up Exception" do ex = Exception.new(nil, Exception.new) - ex.callstack = CallStack.new + ex.callstack = Exception::CallStack.new results = processor.process(ex) results.cause.should eq(ex.cause) diff --git a/src/raven/backtrace.cr b/src/raven/backtrace.cr index 64ee5ea..cf6d58e 100644 --- a/src/raven/backtrace.cr +++ b/src/raven/backtrace.cr @@ -32,12 +32,12 @@ module Raven def_equals @lines def to_s(io : IO) : Nil - @lines.join('\n', io) + @lines.join(io, '\n') end def inspect(io : IO) : Nil io << "#' end end diff --git a/src/raven/client.cr b/src/raven/client.cr index 681839c..280bbb9 100644 --- a/src/raven/client.cr +++ b/src/raven/client.cr @@ -1,6 +1,6 @@ require "base64" require "json" -require "zlib" +require "compress/gzip" module Raven # Encodes events and sends them to the Sentry server. @@ -36,7 +36,9 @@ module Raven def send_feedback(event_id : String, data : Hash) unless configuration.valid? - logger.debug "Client#send_feedback with event id '#{event_id}' failed: #{configuration.error_messages}" + logger.debug { + "Client#send_feedback with event id '#{event_id}' failed: #{configuration.error_messages}" + } return false end transport.send_feedback(event_id, data) @@ -44,14 +46,16 @@ module Raven def send_event(event : Event | Event::HashType, hint : Event::Hint? = nil) unless configuration.valid? - logger.debug "Client#send_event with event '#{event}' failed: #{configuration.error_messages}" + logger.debug { + "Client#send_event with event '#{event}' failed: #{configuration.error_messages}" + } return false end if event.is_a?(Event) configuration.before_send.try do |before_send| event = before_send.call(event, hint) unless event - logger.info "Discarded event because before_send returned nil" + logger.info { "Discarded event because before_send returned nil" } return end end @@ -61,7 +65,7 @@ module Raven failed_send nil, event return end - logger.info "Sending event #{event[:event_id]} to Sentry" + logger.info { "Sending event #{event[:event_id]} to Sentry" } content_type, encoded_data = encode(event) begin @@ -84,7 +88,7 @@ module Raven case configuration.encoding when .gzip? io_gzipped = IO::Memory.new - Gzip::Writer.open(io_gzipped) do |gzip| + Compress::Gzip::Writer.open(io_gzipped) do |gzip| IO.copy(io, gzip) end io_gzipped.rewind @@ -127,14 +131,16 @@ module Raven private def failed_send(ex, event) if ex @state.failure - logger.warn "Unable to record event with remote Sentry server \ - (#{ex.class} - #{ex.message}): #{ex.backtrace[0..10].join('\n')}" + logger.warn { + "Unable to record event with remote Sentry server \ + (#{ex.class} - #{ex.message}): #{ex.backtrace[0..10].join('\n')}" + } else - logger.warn "Not sending event due to previous failure(s)" + logger.warn { "Not sending event due to previous failure(s)" } end message = get_log_message(event) - logger.warn "Failed to submit event: #{message}" + logger.warn { "Failed to submit event: #{message}" } configuration.transport_failure_callback.try &.call(event) end diff --git a/src/raven/configuration.cr b/src/raven/configuration.cr index c79d40c..672118a 100644 --- a/src/raven/configuration.cr +++ b/src/raven/configuration.cr @@ -107,9 +107,9 @@ module Raven # NOTE: DSN component - set automatically if DSN provided. property host : String? - # Logger used by Raven. You can use any other `::Logger`, + # Logger used by Raven. You can use any other `::Log`, # defaults to `Raven::Logger`. - property logger : ::Logger + property logger : ::Log # Timeout waiting for the Sentry server connection to open in seconds. property connect_timeout : Time::Span = 1.second @@ -278,7 +278,7 @@ module Raven @current_environment = current_environment_from_env @exclude_loggers = [Logger::PROGNAME] @excluded_exceptions = IGNORE_DEFAULT.dup - @logger = Logger.new(STDOUT) + @logger = Logger.new(Log::IOBackend.new(STDOUT)) @processors = DEFAULT_PROCESSORS.dup @sanitize_data_for_request_methods = DEFAULT_REQUEST_METHODS_FOR_DATA_SANITIZATION.dup @release = detect_release @@ -355,7 +355,7 @@ module Raven if commit = ENV["HEROKU_SLUG_COMMIT"]? return commit end - logger.warn(HEROKU_DYNO_METADATA_MESSAGE) + logger.warn { HEROKU_DYNO_METADATA_MESSAGE } nil end diff --git a/src/raven/event.cr b/src/raven/event.cr index feeedbc..1c48feb 100644 --- a/src/raven/event.cr +++ b/src/raven/event.cr @@ -101,7 +101,7 @@ module Raven {% end %} new(**options).tap do |event| - exc.callstack ||= CallStack.new + exc.callstack ||= Exception::CallStack.new add_exception_interface(event, exc) end end diff --git a/src/raven/instance.cr b/src/raven/instance.cr index 3b1293c..ff49e7c 100644 --- a/src/raven/instance.cr +++ b/src/raven/instance.cr @@ -51,9 +51,11 @@ module Raven def report_status return if configuration.silence_ready? if configuration.capture_allowed? - logger.info "Raven #{VERSION} ready to catch errors" + logger.info { "Raven #{VERSION} ready to catch errors" } else - logger.info "Raven #{VERSION} configured not to capture errors: #{configuration.error_messages}" + logger.info { + "Raven #{VERSION} configured not to capture errors: #{configuration.error_messages}" + } end end @@ -129,7 +131,9 @@ module Raven # ``` def capture(obj : Exception | String, **options, &block) unless configuration.capture_allowed?(obj) - logger.debug "'#{obj}' excluded from capture: #{configuration.error_messages}" + logger.debug { + "'#{obj}' excluded from capture: #{configuration.error_messages}" + } return false end default_options = { @@ -149,7 +153,7 @@ module Raven begin async.call(event) rescue ex - logger.error "Async event sending failed: #{ex.message}" + logger.error { "Async event sending failed: #{ex.message}" } send_event(event, hint) end else diff --git a/src/raven/logger.cr b/src/raven/logger.cr index 4d4ca1b..d578133 100644 --- a/src/raven/logger.cr +++ b/src/raven/logger.cr @@ -1,13 +1,11 @@ -require "logger" +require "log" module Raven - class Logger < ::Logger + class Logger < ::Log PROGNAME = "sentry" - def self.new(*args, **options) - super.tap do |logger| - logger.progname = PROGNAME - end + def self.new(backend : Backend?, level : Severity = :info) + new(PROGNAME, backend, level) end end end diff --git a/src/raven/transports/http.cr b/src/raven/transports/http.cr index 1867219..c8cc651 100644 --- a/src/raven/transports/http.cr +++ b/src/raven/transports/http.cr @@ -42,7 +42,7 @@ module Raven str << "/api/embed/error-page/?" str << params end - logger.debug "HTTP Transport connecting to #{path}" + logger.debug { "HTTP Transport connecting to #{path}" } client = build_client client.post(path, form: data, headers: headers).tap do |response| @@ -52,7 +52,7 @@ module Raven def send_event(auth_header, data, **options) unless configuration.capture_allowed? - logger.debug "Event not sent: #{configuration.error_messages}" + logger.debug { "Event not sent: #{configuration.error_messages}" } return end @@ -66,7 +66,7 @@ module Raven if configuration.encoding.gzip? headers["Content-Encoding"] = "gzip" end - logger.debug "HTTP Transport connecting to #{configuration.dsn}" + logger.debug { "HTTP Transport connecting to #{configuration.dsn}" } client = build_client client.post("#{path}/api/#{project_id}/store/", headers, data).tap do |response| From e816652c2d789975e899f979736b5f25e52416a0 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Wed, 17 Jun 2020 20:56:28 +0200 Subject: [PATCH 02/18] Specs cleanup --- spec/raven/backtrace_line_spec.cr | 2 +- spec/raven/breadcrumb_buffer_spec.cr | 2 +- spec/raven/client_spec.cr | 9 ++----- spec/raven/client_state_spec.cr | 2 +- spec/raven/configuration_spec.cr | 4 ++-- spec/raven/event_spec.cr | 15 +++++++----- spec/raven/instance_spec.cr | 35 +++++++++++++--------------- spec/raven/logger_spec.cr | 19 +++------------ spec/spec_helper.cr | 7 ++++++ 9 files changed, 42 insertions(+), 53 deletions(-) diff --git a/spec/raven/backtrace_line_spec.cr b/spec/raven/backtrace_line_spec.cr index 533bedf..692f223 100644 --- a/spec/raven/backtrace_line_spec.cr +++ b/spec/raven/backtrace_line_spec.cr @@ -1,6 +1,6 @@ require "../spec_helper" -def with_line(path = "#{__DIR__}/foo.cr", method = "foo_bar?") +private def with_line(path = "#{__DIR__}/foo.cr", method = "foo_bar?") line = "#{path}:1:7 in '#{method}'" yield Raven::Backtrace::Line.parse(line) end diff --git a/spec/raven/breadcrumb_buffer_spec.cr b/spec/raven/breadcrumb_buffer_spec.cr index 4b2a7a4..3294dee 100644 --- a/spec/raven/breadcrumb_buffer_spec.cr +++ b/spec/raven/breadcrumb_buffer_spec.cr @@ -1,6 +1,6 @@ require "../spec_helper" -def with_breadcrumb_buffer +private def with_breadcrumb_buffer breadcrumbs = Raven::BreadcrumbBuffer.new(10) yield breadcrumbs end diff --git a/spec/raven/client_spec.cr b/spec/raven/client_spec.cr index 0570efd..8b13572 100644 --- a/spec/raven/client_spec.cr +++ b/spec/raven/client_spec.cr @@ -1,6 +1,6 @@ require "../spec_helper" -class ClientTest < Raven::Client +private class ClientTest < Raven::Client def generate_auth_header super end @@ -10,12 +10,7 @@ class ClientTest < Raven::Client end end -def build_configuration - Raven::Configuration.new - .tap(&.dsn = "dummy://12345:67890@sentry.localdomain:3000/sentry/42") -end - -def with_client +private def with_client yield ClientTest.new(build_configuration) end diff --git a/spec/raven/client_state_spec.cr b/spec/raven/client_state_spec.cr index 6862eed..a8820ac 100644 --- a/spec/raven/client_state_spec.cr +++ b/spec/raven/client_state_spec.cr @@ -1,7 +1,7 @@ require "../spec_helper" require "timecop" -def with_client_state +private def with_client_state yield Raven::Client::State.new end diff --git a/spec/raven/configuration_spec.cr b/spec/raven/configuration_spec.cr index f43230b..68006a2 100644 --- a/spec/raven/configuration_spec.cr +++ b/spec/raven/configuration_spec.cr @@ -12,13 +12,13 @@ private class RandomSampleFail < Random::PCG32 end end -def with_configuration +private def with_configuration with_clean_env do yield Raven::Configuration.new end end -def with_configuration_with_dsn +private def with_configuration_with_dsn with_configuration do |configuration| configuration.dsn = "http://12345:67890@sentry.localdomain:3000/sentry/42" yield configuration diff --git a/spec/raven/event_spec.cr b/spec/raven/event_spec.cr index a364a69..a8ca6e6 100644 --- a/spec/raven/event_spec.cr +++ b/spec/raven/event_spec.cr @@ -4,7 +4,7 @@ module Raven::Test class Exception < ::Exception; end end -def with_event(clear = true, **opts) +private def with_event(clear = true, **opts) if clear Raven::Context.clear! Raven::BreadcrumbBuffer.clear! @@ -13,18 +13,24 @@ def with_event(clear = true, **opts) yield event end -def with_event_hash(**opts) +private def with_event_hash(**opts) with_event(**opts) do |event| yield event.to_hash end end -def exception_value_from_event_hash(hash, index) +private def exception_value_from_event_hash(hash, index) ex_values = hash.to_any_json[:exception, :values].as(Array) ex_values[index].as(Hash) end describe Raven::Event do + around_each do |example| + Raven::Context.clear! + example.run + Raven::Context.clear! + end + context "with fully implemented event" do opts = { message: "test", @@ -104,7 +110,6 @@ describe Raven::Event do context "with tags context specified" do it "merges tags data" do - Raven::Context.clear! Raven.tags_context({"key" => "value"}) with_event_hash(tags: {"foo" => "bar"}, clear: false) do |hash| @@ -191,8 +196,6 @@ describe Raven::Event do {% for key in %i(user extra tags) %} context "with {{key.id}} context specified" do it "prioritizes event context" do - Raven::Context.clear! - Raven.{{key.id}}_context({ "context_event_key" => "context_value", "context_key" => "context_value", diff --git a/spec/raven/instance_spec.cr b/spec/raven/instance_spec.cr index 869301b..a5f8744 100644 --- a/spec/raven/instance_spec.cr +++ b/spec/raven/instance_spec.cr @@ -17,18 +17,11 @@ private class InstanceTest < Raven::Instance end end -def build_instance_configuration - Raven::Configuration.new.tap do |config| - config.dsn = "dummy://12345:67890@sentry.localdomain:3000/sentry/42" - config.logger = Raven::Logger.new(Log::MemoryBackend.new, :info) - end -end - -def with_instance(context = nil) - yield InstanceTest.new(context, build_instance_configuration) +private def with_instance(context = nil) + yield InstanceTest.new(context, build_configuration) end -private def get_logs_from_backend(instance : InstanceTest) +private def log_entries_checker_for(instance) backend = instance.logger.backend.as(Log::MemoryBackend) Log::EntriesChecker.new(backend.entries) end @@ -212,7 +205,8 @@ describe Raven::Instance do instance.report_status - get_logs_from_backend(instance).check(:info, ready_message) + log_entries_checker_for(instance) + .check(:info, ready_message) end end @@ -221,8 +215,8 @@ describe Raven::Instance do instance.configuration.silence_ready = true instance.report_status - - get_logs_from_backend(instance).empty + log_entries_checker_for(instance) + .empty end end @@ -232,8 +226,8 @@ describe Raven::Instance do instance.configuration.dsn = "dummy://foo" instance.report_status - - get_logs_from_backend(instance).check(:info, /#{not_ready_message}/) + log_entries_checker_for(instance) + .check(:info, /#{not_ready_message}/) end end @@ -243,9 +237,10 @@ describe Raven::Instance do instance.configuration.environments = %w(production) instance.report_status - - get_logs_from_backend(instance) - .check(:info, "#{not_ready_message}: Not configured to send/capture in environment 'default'") + log_entries_checker_for(instance) + .check(:info, + "#{not_ready_message}: Not configured to send/capture in environment 'default'" + ) end end end @@ -254,7 +249,9 @@ describe Raven::Instance do it "sends the result of Event.capture" do with_instance do |instance| event = instance.capture("Test message") - instance.last_sent_event.try(&.id).should eq(event.as?(Raven::Event).try(&.id)) + + last_sent_event = instance.last_sent_event.should_not be_nil + last_sent_event.id.should eq(event.as(Raven::Event).id) end end end diff --git a/spec/raven/logger_spec.cr b/spec/raven/logger_spec.cr index cf153d7..7731e19 100644 --- a/spec/raven/logger_spec.cr +++ b/spec/raven/logger_spec.cr @@ -4,26 +4,13 @@ require "log/spec" describe Raven::Logger do it "should log to a given backend" do backend = Log::MemoryBackend.new - log = Raven::Logger.new(backend, :info) - log.info { "Oh YAZ!" } - log.fatal { "Oh noes!" } + logger = Raven::Logger.new(backend, :info) + logger.info { "Oh YAZ!" } + logger.fatal { "Oh noes!" } logs = Log::EntriesChecker.new(backend.entries) - logs.check(:info, "Oh YAZ!") logs.next(:fatal, "Oh noes!") end - - it "should log to a given IO" do - io = IO::Memory.new - backend = Log::IOBackend.new(io) - log = Raven::Logger.new(backend, :info) - - log.info { "Oh YAZ!" } - log.fatal { "Oh noes!" } - - io.to_s.should match(/INFO - sentry: Oh YAZ!\n/) - io.to_s.should match(/FATAL - sentry: Oh noes!\n\Z/) - end end diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index ca8c162..3315cde 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -48,3 +48,10 @@ def build_exception_with_two_causes rescue exception exception end + +def build_configuration + Raven::Configuration.new.tap do |config| + config.dsn = "dummy://12345:67890@sentry.localdomain:3000/sentry/42" + config.logger = Raven::Logger.new(Log::MemoryBackend.new, :info) + end +end From 904baaaa17336a5a53475f16d1ea46fe4473588d Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Wed, 17 Jun 2020 21:14:43 +0200 Subject: [PATCH 03/18] Prefer Path.[] over File.join --- spec/raven/version_spec.cr | 2 +- src/raven/configuration.cr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/raven/version_spec.cr b/spec/raven/version_spec.cr index 47241a1..9c1478f 100644 --- a/spec/raven/version_spec.cr +++ b/spec/raven/version_spec.cr @@ -7,7 +7,7 @@ describe Raven::VERSION do end it "should match shard.yml" do - version = YAML.parse(File.read(File.join(__DIR__, "../..", "shard.yml")))["version"].as_s + version = YAML.parse(File.read(Path[__DIR__, "..", "..", "shard.yml"]))["version"].as_s version.should eq Raven::VERSION end end diff --git a/src/raven/configuration.cr b/src/raven/configuration.cr index 672118a..0d9e5fa 100644 --- a/src/raven/configuration.cr +++ b/src/raven/configuration.cr @@ -360,11 +360,11 @@ module Raven end private def detect_release_from_capistrano - version = File.read(File.join(project_root, "REVISION")).strip rescue nil + version = File.read(Path[project_root, "REVISION"]).strip rescue nil return version if version # Capistrano 3.0 - 3.1.x - File.read_lines(File.join(project_root, "..", "revisions.log")) + File.read_lines(Path[project_root, "..", "revisions.log"]) .last.strip.sub(/.*as release ([0-9]+).*/, "\1") rescue nil end From d856f9bad67b285b401bc98edfae6e0c37b4630d Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Wed, 17 Jun 2020 21:32:51 +0200 Subject: [PATCH 04/18] Remove scoping to src/ dir from ameba check --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a95a9d8..dd6bce4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,4 @@ script: - crystal spec --release - crystal spec --release --no-debug - crystal tool format --check - - bin/ameba src + - bin/ameba From 109f8795ddc865a3bf9c7d51e344a2752bb85a9f Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Wed, 17 Jun 2020 21:33:19 +0200 Subject: [PATCH 05/18] Switch badge to travis-ci.com --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a977d4d..d26b050 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

- Build Status + Build Status Codacy Badge Releases License From 1c9b71d9b113fca4ec3b1b378a20e4b102762156 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Wed, 17 Jun 2020 21:41:44 +0200 Subject: [PATCH 06/18] Build crash_handler as a part of the CI checks --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index dd6bce4..cb518a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,5 +16,7 @@ script: - crystal spec --no-debug - crystal spec --release - crystal spec --release --no-debug + - shards build crash_handler + - shards build crash_handler --release - crystal tool format --check - bin/ameba From 435cff487879734062da477a44c1ed04a08a5229 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Wed, 17 Jun 2020 22:15:57 +0200 Subject: [PATCH 07/18] Use original key name instead of an alias in .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cb518a6..04390fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ crystal: - latest - nightly -matrix: +jobs: allow_failures: - crystal: nightly From c85bed45f54fd49c5f29c3bc002079726ef7ccb2 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Wed, 17 Jun 2020 22:16:02 +0200 Subject: [PATCH 08/18] =?UTF-8?q?Call=20=E2=80=9Cshards=20version=E2=80=9D?= =?UTF-8?q?=20instead=20of=20hardcoding=20VERSION=20value?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/raven/version.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raven/version.cr b/src/raven/version.cr index aef1cfa..ba68bff 100644 --- a/src/raven/version.cr +++ b/src/raven/version.cr @@ -1,3 +1,3 @@ module Raven - VERSION = "1.6.0" + VERSION = {{ `shards version "#{__DIR__}"`.chomp.stringify }} end From 941e7afa089fad56cab32f69c3a229de6c1bbad4 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Wed, 17 Jun 2020 22:16:07 +0200 Subject: [PATCH 09/18] Bump to v1.7.0-dev --- shard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shard.yml b/shard.yml index 0b2fdca..baf1223 100644 --- a/shard.yml +++ b/shard.yml @@ -1,5 +1,5 @@ name: raven -version: 1.6.0 +version: 1.7.0-dev authors: - Sijawusz Pur Rahnama From 000bbc306e7ddd348da8df4c2f96578bf03f07de Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Thu, 18 Jun 2020 00:49:45 +0200 Subject: [PATCH 10/18] Make crash_handler compile under Crystal 0.34.0+ --- src/crash_handler.cr | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/crash_handler.cr b/src/crash_handler.cr index 4eb3e74..3d3a424 100644 --- a/src/crash_handler.cr +++ b/src/crash_handler.cr @@ -50,11 +50,14 @@ module Raven delegate :context, :configuration, :configure, :capture, to: raven - property logger : ::Logger { - Logger.new({{ "STDOUT".id unless flag?(:release) }}).tap do |logger| - logger.level = {{ flag?(:debug) ? "Logger::DEBUG".id : "Logger::ERROR".id }} - logger.progname = "raven.crash_handler" - end + property logger : ::Log { + backend = Log::IOBackend.new(STDOUT) + level = case + when {{ flag?(:release) }} then Log::Severity::None + when {{ flag?(:debug) }} then Log::Severity::Debug + else Log::Severity::Error + end + Log.new("raven.crash_handler", backend, level) } def initialize(@name, @args) From c20e3dda87bca5e33dbc9c21ff8e5e55eeea3431 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Thu, 18 Jun 2020 16:14:22 +0200 Subject: [PATCH 11/18] Remove (now obsolete) proc setter overloads --- src/raven/configuration.cr | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/raven/configuration.cr b/src/raven/configuration.cr index 0d9e5fa..6a87ab5 100644 --- a/src/raven/configuration.cr +++ b/src/raven/configuration.cr @@ -49,14 +49,6 @@ module Raven # ``` property async : Proc(Event, Nil)? - # ditto - def async=(block : Event -> _) - @async = ->(event : Event) { - block.call(event) - nil - } - end - # Sets `async` callback to either `Fiber`-based implementation (see below), # or `nil`, depending on the given *switch* value. # @@ -239,14 +231,6 @@ module Raven # ``` property transport_failure_callback : Proc(Event::HashType, Nil)? - # ditto - def transport_failure_callback=(block : Event::HashType -> _) - @transport_failure_callback = ->(event : Event::HashType) { - block.call(event) - nil - } - end - # Optional `Proc`, called before sending an event to the server: # # ``` From 4663abd5cf1a1b0104522af3c73fdfbc0c3bdccc Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Thu, 18 Jun 2020 17:01:13 +0200 Subject: [PATCH 12/18] Remove Raven::Logger class in favor of using Log.for --- spec/raven/instance_spec.cr | 35 +++++++++++------------- spec/raven/logger_spec.cr | 16 ----------- spec/spec_helper.cr | 2 +- src/crash_handler.cr | 20 ++++++-------- src/raven/client.cr | 18 +++++------- src/raven/configuration.cr | 9 ++---- src/raven/instance.cr | 10 +++---- src/raven/integrations/kernel/at_exit.cr | 2 +- src/raven/log.cr | 5 ++++ src/raven/logger.cr | 11 -------- src/raven/transports/http.cr | 6 ++-- 11 files changed, 48 insertions(+), 86 deletions(-) delete mode 100644 spec/raven/logger_spec.cr create mode 100644 src/raven/log.cr delete mode 100644 src/raven/logger.cr diff --git a/spec/raven/instance_spec.cr b/spec/raven/instance_spec.cr index a5f8744..ea348bd 100644 --- a/spec/raven/instance_spec.cr +++ b/spec/raven/instance_spec.cr @@ -1,5 +1,4 @@ require "../spec_helper" -require "log/spec" module Raven::Test class BaseException < ::Exception; end @@ -21,11 +20,6 @@ private def with_instance(context = nil) yield InstanceTest.new(context, build_configuration) end -private def log_entries_checker_for(instance) - backend = instance.logger.backend.as(Log::MemoryBackend) - Log::EntriesChecker.new(backend.entries) -end - describe Raven::Instance do describe "#context" do it "is Raven.context by default" do @@ -203,10 +197,10 @@ describe Raven::Instance do with_instance do |instance| instance.configuration.silence_ready = false - instance.report_status - - log_entries_checker_for(instance) - .check(:info, ready_message) + Log.capture do |logs| + instance.report_status + logs.check(:info, ready_message) + end end end @@ -214,9 +208,10 @@ describe Raven::Instance do with_instance do |instance| instance.configuration.silence_ready = true - instance.report_status - log_entries_checker_for(instance) - .empty + Log.capture do |logs| + instance.report_status + logs.empty + end end end @@ -225,9 +220,10 @@ describe Raven::Instance do instance.configuration.silence_ready = false instance.configuration.dsn = "dummy://foo" - instance.report_status - log_entries_checker_for(instance) - .check(:info, /#{not_ready_message}/) + Log.capture do |logs| + instance.report_status + logs.check(:info, /#{not_ready_message}/) + end end end @@ -236,11 +232,12 @@ describe Raven::Instance do instance.configuration.silence_ready = false instance.configuration.environments = %w(production) - instance.report_status - log_entries_checker_for(instance) - .check(:info, + Log.capture do |logs| + instance.report_status + logs.check(:info, "#{not_ready_message}: Not configured to send/capture in environment 'default'" ) + end end end end diff --git a/spec/raven/logger_spec.cr b/spec/raven/logger_spec.cr deleted file mode 100644 index 7731e19..0000000 --- a/spec/raven/logger_spec.cr +++ /dev/null @@ -1,16 +0,0 @@ -require "../spec_helper" -require "log/spec" - -describe Raven::Logger do - it "should log to a given backend" do - backend = Log::MemoryBackend.new - - logger = Raven::Logger.new(backend, :info) - logger.info { "Oh YAZ!" } - logger.fatal { "Oh noes!" } - - logs = Log::EntriesChecker.new(backend.entries) - logs.check(:info, "Oh YAZ!") - logs.next(:fatal, "Oh noes!") - end -end diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 3315cde..567c790 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -1,4 +1,5 @@ require "spec" +require "log/spec" require "../src/raven" # Make sure we reset the env in case something leaks in @@ -52,6 +53,5 @@ end def build_configuration Raven::Configuration.new.tap do |config| config.dsn = "dummy://12345:67890@sentry.localdomain:3000/sentry/42" - config.logger = Raven::Logger.new(Log::MemoryBackend.new, :info) end end diff --git a/src/crash_handler.cr b/src/crash_handler.cr index 3d3a424..0e91ca3 100644 --- a/src/crash_handler.cr +++ b/src/crash_handler.cr @@ -1,5 +1,14 @@ require "./raven" +Log.setup do |c| + level = case + when {{ flag?(:release) }} then Log::Severity::None + when {{ flag?(:debug) }} then Log::Severity::Debug + else Log::Severity::Error + end + c.bind("raven.*", level, Log::IOBackend.new) +end + module Raven class CrashHandler # Example: @@ -50,16 +59,6 @@ module Raven delegate :context, :configuration, :configure, :capture, to: raven - property logger : ::Log { - backend = Log::IOBackend.new(STDOUT) - level = case - when {{ flag?(:release) }} then Log::Severity::None - when {{ flag?(:debug) }} then Log::Severity::Debug - else Log::Severity::Error - end - Log.new("raven.crash_handler", backend, level) - } - def initialize(@name, @args) context.extra.merge!({ process: {name: @name, args: @args}, @@ -68,7 +67,6 @@ module Raven private def configure! configure do |config| - config.logger = logger config.send_modules = false config.processors = [ Processor::UTF8Conversion, diff --git a/src/raven/client.cr b/src/raven/client.cr index 280bbb9..2ee2a28 100644 --- a/src/raven/client.cr +++ b/src/raven/client.cr @@ -9,7 +9,6 @@ module Raven USER_AGENT = "raven.cr/#{Raven::VERSION}" property configuration : Configuration - delegate logger, to: configuration @state : State @processors : Array(Processor) @@ -36,7 +35,7 @@ module Raven def send_feedback(event_id : String, data : Hash) unless configuration.valid? - logger.debug { + Log.debug { "Client#send_feedback with event id '#{event_id}' failed: #{configuration.error_messages}" } return false @@ -46,7 +45,7 @@ module Raven def send_event(event : Event | Event::HashType, hint : Event::Hint? = nil) unless configuration.valid? - logger.debug { + Log.debug { "Client#send_event with event '#{event}' failed: #{configuration.error_messages}" } return false @@ -55,7 +54,7 @@ module Raven configuration.before_send.try do |before_send| event = before_send.call(event, hint) unless event - logger.info { "Discarded event because before_send returned nil" } + Log.info { "Discarded event because before_send returned nil" } return end end @@ -65,7 +64,7 @@ module Raven failed_send nil, event return end - logger.info { "Sending event #{event[:event_id]} to Sentry" } + Log.info { "Sending event #{event[:event_id]} to Sentry" } content_type, encoded_data = encode(event) begin @@ -131,16 +130,13 @@ module Raven private def failed_send(ex, event) if ex @state.failure - logger.warn { - "Unable to record event with remote Sentry server \ - (#{ex.class} - #{ex.message}): #{ex.backtrace[0..10].join('\n')}" - } + Log.warn(exception: ex) { "Unable to record event with remote Sentry server" } else - logger.warn { "Not sending event due to previous failure(s)" } + Log.warn { "Not sending event due to previous failure(s)" } end message = get_log_message(event) - logger.warn { "Failed to submit event: #{message}" } + Log.warn { "Failed to submit event: #{message}" } configuration.transport_failure_callback.try &.call(event) end diff --git a/src/raven/configuration.cr b/src/raven/configuration.cr index 6a87ab5..171081c 100644 --- a/src/raven/configuration.cr +++ b/src/raven/configuration.cr @@ -99,10 +99,6 @@ module Raven # NOTE: DSN component - set automatically if DSN provided. property host : String? - # Logger used by Raven. You can use any other `::Log`, - # defaults to `Raven::Logger`. - property logger : ::Log - # Timeout waiting for the Sentry server connection to open in seconds. property connect_timeout : Time::Span = 1.second @@ -260,9 +256,8 @@ module Raven def initialize @current_environment = current_environment_from_env - @exclude_loggers = [Logger::PROGNAME] + @exclude_loggers = [Log.source] @excluded_exceptions = IGNORE_DEFAULT.dup - @logger = Logger.new(Log::IOBackend.new(STDOUT)) @processors = DEFAULT_PROCESSORS.dup @sanitize_data_for_request_methods = DEFAULT_REQUEST_METHODS_FOR_DATA_SANITIZATION.dup @release = detect_release @@ -339,7 +334,7 @@ module Raven if commit = ENV["HEROKU_SLUG_COMMIT"]? return commit end - logger.warn { HEROKU_DYNO_METADATA_MESSAGE } + Log.warn { HEROKU_DYNO_METADATA_MESSAGE } nil end diff --git a/src/raven/instance.cr b/src/raven/instance.cr index ff49e7c..28df104 100644 --- a/src/raven/instance.cr +++ b/src/raven/instance.cr @@ -25,8 +25,6 @@ module Raven # See `Raven::Configuration`. property configuration : Configuration { Configuration.new } - delegate logger, to: configuration - # The client object is responsible for delivering formatted data to the # Sentry server. property client : Client { Client.new(configuration) } @@ -51,9 +49,9 @@ module Raven def report_status return if configuration.silence_ready? if configuration.capture_allowed? - logger.info { "Raven #{VERSION} ready to catch errors" } + Log.info { "Raven #{VERSION} ready to catch errors" } else - logger.info { + Log.info { "Raven #{VERSION} configured not to capture errors: #{configuration.error_messages}" } end @@ -131,7 +129,7 @@ module Raven # ``` def capture(obj : Exception | String, **options, &block) unless configuration.capture_allowed?(obj) - logger.debug { + Log.debug { "'#{obj}' excluded from capture: #{configuration.error_messages}" } return false @@ -153,7 +151,7 @@ module Raven begin async.call(event) rescue ex - logger.error { "Async event sending failed: #{ex.message}" } + Log.error(exception: ex) { "Async event sending failed" } send_event(event, hint) end else diff --git a/src/raven/integrations/kernel/at_exit.cr b/src/raven/integrations/kernel/at_exit.cr index b189a39..b946136 100644 --- a/src/raven/integrations/kernel/at_exit.cr +++ b/src/raven/integrations/kernel/at_exit.cr @@ -1,6 +1,6 @@ at_exit do |_, exception| if exception - Raven.logger.debug "Caught a post-mortem exception: #{exception.inspect}" + Raven::Log.debug(exception: exception) { "Caught a post-mortem exception" } Raven.capture(exception) end end diff --git a/src/raven/log.cr b/src/raven/log.cr new file mode 100644 index 0000000..23eb8e0 --- /dev/null +++ b/src/raven/log.cr @@ -0,0 +1,5 @@ +require "log" + +module Raven + Log = ::Log.for(self) +end diff --git a/src/raven/logger.cr b/src/raven/logger.cr deleted file mode 100644 index d578133..0000000 --- a/src/raven/logger.cr +++ /dev/null @@ -1,11 +0,0 @@ -require "log" - -module Raven - class Logger < ::Log - PROGNAME = "sentry" - - def self.new(backend : Backend?, level : Severity = :info) - new(PROGNAME, backend, level) - end - end -end diff --git a/src/raven/transports/http.cr b/src/raven/transports/http.cr index c8cc651..cb0cbe6 100644 --- a/src/raven/transports/http.cr +++ b/src/raven/transports/http.cr @@ -42,7 +42,7 @@ module Raven str << "/api/embed/error-page/?" str << params end - logger.debug { "HTTP Transport connecting to #{path}" } + Log.debug { "HTTP Transport connecting to #{path}" } client = build_client client.post(path, form: data, headers: headers).tap do |response| @@ -52,7 +52,7 @@ module Raven def send_event(auth_header, data, **options) unless configuration.capture_allowed? - logger.debug { "Event not sent: #{configuration.error_messages}" } + Log.debug { "Event not sent: #{configuration.error_messages}" } return end @@ -66,7 +66,7 @@ module Raven if configuration.encoding.gzip? headers["Content-Encoding"] = "gzip" end - logger.debug { "HTTP Transport connecting to #{configuration.dsn}" } + Log.debug { "HTTP Transport connecting to #{configuration.dsn}" } client = build_client client.post("#{path}/api/#{project_id}/store/", headers, data).tap do |response| From f3cf0a0bae68e458f4da5f48104f6f11a9c4db39 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Fri, 19 Jun 2020 13:32:51 +0200 Subject: [PATCH 13/18] Add Raven::BreadcrumbLogBackend --- src/raven/configuration.cr | 12 +++-- src/raven/integrations/kernel/log.cr | 44 +++++++++++++++++ src/raven/integrations/kernel/logger.cr | 48 +++++-------------- .../shared/breadcrumb_log_helper.cr | 22 +++++++++ 4 files changed, 87 insertions(+), 39 deletions(-) create mode 100644 src/raven/integrations/kernel/log.cr create mode 100644 src/raven/integrations/shared/breadcrumb_log_helper.cr diff --git a/src/raven/configuration.cr b/src/raven/configuration.cr index 171081c..263af6d 100644 --- a/src/raven/configuration.cr +++ b/src/raven/configuration.cr @@ -82,9 +82,9 @@ module Raven # Whitelist of environments that will send notifications to Sentry. property environments = [] of String - # Logger "progname"s to exclude from breadcrumbs. + # `::Log#source` patterns excluded from breadcrumb recording. # - # Defaults to `[Raven::Logger::PROGNAME]`. + # Defaults to `raven.*`. # # NOTE: You should probably append to this rather than overwrite it. property exclude_loggers : Array(String) @@ -256,7 +256,7 @@ module Raven def initialize @current_environment = current_environment_from_env - @exclude_loggers = [Log.source] + @exclude_loggers = ["#{Log.source}.*"] @excluded_exceptions = IGNORE_DEFAULT.dup @processors = DEFAULT_PROCESSORS.dup @sanitize_data_for_request_methods = DEFAULT_REQUEST_METHODS_FOR_DATA_SANITIZATION.dup @@ -374,6 +374,12 @@ module Raven ENV["SENTRY_ENVIRONMENT"]? || "default" end + def ignored_logger?(source) + exclude_loggers.any? do |pattern| + ::Log::Builder.matches(source, pattern) + end + end + def capture_allowed? @errors = [] of String valid? && diff --git a/src/raven/integrations/kernel/log.cr b/src/raven/integrations/kernel/log.cr new file mode 100644 index 0000000..08229ea --- /dev/null +++ b/src/raven/integrations/kernel/log.cr @@ -0,0 +1,44 @@ +require "log" +require "../shared/breadcrumb_log_helper" + +module Raven + # ``` + # require "raven" + # require "raven/integrations/kernel/log" + # ``` + # + # `::Log::Backend` recording logged messages as breadcrumbs. + # + # ``` + # Log.setup do |c| + # c.bind "*", :info, Log::IOBackend.new + # c.bind "*", :info, Raven::BreadcrumbLogBackend.new + # end + # ``` + class BreadcrumbLogBackend < ::Log::Backend + include Raven::BreadcrumbLogHelper + + private BREADCRUMB_LEVELS = { + :trace => :debug, + :debug => :debug, + :info => :info, + :notice => :info, + :warn => :warning, + :error => :error, + :fatal => :critical, + } of ::Log::Severity => Raven::Breadcrumb::Severity + + def write(entry : ::Log::Entry) + message = entry.message + if ex = entry.exception + message += " -- (#{ex.class}): #{ex.message || "n/a"}" + end + record_breadcrumb( + BREADCRUMB_LEVELS[entry.severity]?, + entry.timestamp, + entry.source, + message, + ) + end + end +end diff --git a/src/raven/integrations/kernel/logger.cr b/src/raven/integrations/kernel/logger.cr index c3e9da9..0769699 100644 --- a/src/raven/integrations/kernel/logger.cr +++ b/src/raven/integrations/kernel/logger.cr @@ -1,47 +1,23 @@ require "logger" - -module Raven::Breadcrumb::Logger - private LOGGER_BREADCRUMB_LEVELS = { - ::Logger::DEBUG => Severity::DEBUG, - ::Logger::INFO => Severity::INFO, - ::Logger::WARN => Severity::WARNING, - ::Logger::ERROR => Severity::ERROR, - ::Logger::FATAL => Severity::CRITICAL, - } - - protected def self.ignored_logger?(progname) - Raven.configuration.exclude_loggers.includes?(progname) - end - - protected def record_breadcrumb(severity, datetime, progname, message) - return if Logger.ignored_logger?(progname) - Raven.breadcrumbs.record do |crumb| - crumb.timestamp = datetime - crumb.level = LOGGER_BREADCRUMB_LEVELS[severity]? - crumb.category = progname || "logger" - crumb.message = message - end - end -end +require "../shared/breadcrumb_log_helper" class Logger - include Raven::Breadcrumb::Logger + include Raven::BreadcrumbLogHelper - protected def self.deansify(message) - case message - when Nil then nil - when String then message.gsub(/\x1b[^m]*m/, "") - when Exception then deansify(message.message) - else deansify(message.to_s) - end - end + private BREADCRUMB_LEVELS = { + :debug => :debug, + :info => :info, + :warn => :warning, + :error => :error, + :fatal => :critical, + } of ::Logger::Severity => Raven::Breadcrumb::Severity private def write(severity, datetime, progname, message) record_breadcrumb( - severity, + BREADCRUMB_LEVELS[severity]?, datetime, - self.class.deansify(progname), - self.class.deansify(message), + progname, + message, ) previous_def end diff --git a/src/raven/integrations/shared/breadcrumb_log_helper.cr b/src/raven/integrations/shared/breadcrumb_log_helper.cr new file mode 100644 index 0000000..7a1378e --- /dev/null +++ b/src/raven/integrations/shared/breadcrumb_log_helper.cr @@ -0,0 +1,22 @@ +module Raven + module BreadcrumbLogHelper + protected def deansify(message) : String? + case message + when Nil then nil + when String then message.gsub(/\x1b[^m]*m/, "") + when Exception then deansify(message.message) + else deansify(message.to_s) + end + end + + protected def record_breadcrumb(level, timestamp, category, message) : Breadcrumb? + return if Raven.configuration.ignored_logger?(category) + Raven.breadcrumbs.record do |crumb| + crumb.level = level + crumb.timestamp = timestamp + crumb.category = category.presence || "logger" + crumb.message = deansify(message).presence + end + end + end +end From db61a07525c910d6b309ff81ca3ca4c83a687567 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Fri, 19 Jun 2020 16:11:10 +0200 Subject: [PATCH 14/18] Simplify CrashHandler implementation a bit --- src/crash_handler.cr | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/crash_handler.cr b/src/crash_handler.cr index 0e91ca3..8fd80b4 100644 --- a/src/crash_handler.cr +++ b/src/crash_handler.cr @@ -24,7 +24,8 @@ module Raven # [0x10578706c] __crystal_main +2940 # [0x105798128] main +40 # ``` - CRYSTAL_CRASH_PATTERN = /(?[^\n]+)\n(?\[#{Backtrace::Line::ADDR_FORMAT}\] .*)$/m + CRYSTAL_CRASH_PATTERN = + /(?[^\n]+)\n(?\[#{Backtrace::Line::ADDR_FORMAT}\] .*)$/m # Example: # @@ -36,7 +37,8 @@ module Raven # from /usr/local/Cellar/crystal/0.26.0/src/crystal/main.cr:93:7 in 'main' # from /usr/local/Cellar/crystal/0.26.0/src/crystal/main.cr:133:3 in 'main' # ``` - CRYSTAL_EXCEPTION_PATTERN = /Unhandled exception(? in spawn(?:\(name: (?.*?)\))?)?: (?[^\n]+) \((?[A-Z]\w+)\)\n(?(?:\s+from\s+.*?){1,})$/m + CRYSTAL_EXCEPTION_PATTERN = + /Unhandled exception(? in spawn(?:\(name: (?.*?)\))?)?: (?[^\n]+) \((?[A-Z]\w+)\)\n(?(?:\s+from\s+.*?){1,})$/m # Default event options. DEFAULT_OPTS = { @@ -132,16 +134,14 @@ module Raven getter! started_at : Time getter! process_status : Process::Status - delegate :exit_code, :success?, - to: process_status - - private def run_process(error : IO = IO::Memory.new) + private def run_process + error = IO::Memory.new @process_status = Process.run command: name, args: args, shell: true, - input: Process::Redirect::Inherit, - output: Process::Redirect::Inherit, + input: :inherit, + output: :inherit, error: IO::MultiWriter.new(STDERR, error) - error.to_s.chomp + error.to_s.chomp.presence end def run : Nil @@ -153,6 +153,9 @@ module Raven error = run_process running_for = Time.monotonic - start + exit_code = process_status.exit_code + success = process_status.success? + context.tags.merge!({ exit_code: exit_code, }) @@ -162,7 +165,7 @@ module Raven }) captured = false - error.scan CRYSTAL_EXCEPTION_PATTERN do |match| + error.try &.scan CRYSTAL_EXCEPTION_PATTERN do |match| msg = match["message"] klass = match["class"] backtrace = match["backtrace"] @@ -175,7 +178,7 @@ module Raven }) captured = true end - unless success? + unless success if error =~ CRYSTAL_CRASH_PATTERN msg = $~["message"] backtrace = $~["backtrace"] @@ -194,11 +197,10 @@ module Raven end if ARGV.empty? - puts "Usage: #{PROGRAM_NAME} [OPTION]..." - exit(1) + abort "Usage: #{PROGRAM_NAME} [OPTION]..." end -name, args = ARGV[0], ARGV.size > 1 ? ARGV[1..-1] : nil +name, args = ARGV[0], ARGV.size > 1 ? ARGV[1..] : nil handler = Raven::CrashHandler.new(name, args) handler.raven.tap do |raven| raven.configuration.src_path = Dir.current From 7f52447964b5f43beea5a27d010b87effc172760 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Fri, 19 Jun 2020 16:28:41 +0200 Subject: [PATCH 15/18] Remove remaining references to (now obsolete) `Configuration#logger` --- src/raven.cr | 2 +- src/raven/transport.cr | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/raven.cr b/src/raven.cr index 58392b8..f6a6f23 100644 --- a/src/raven.cr +++ b/src/raven.cr @@ -7,7 +7,7 @@ require "./raven/*" module Raven # `Raven.instance` delegators. module Delegators - delegate :context, :logger, :configuration, :client, + delegate :context, :configuration, :client, :report_status, :configure, :send_feedback, :send_event, :capture, :last_event_id, :annotate_exception, :user_context, :tags_context, :extra_context, :breadcrumbs, diff --git a/src/raven/transport.cr b/src/raven/transport.cr index f3eabb1..5380df1 100644 --- a/src/raven/transport.cr +++ b/src/raven/transport.cr @@ -1,7 +1,6 @@ module Raven abstract class Transport property configuration : Configuration - delegate logger, to: configuration def initialize(@configuration) end From 43cf8edf738b52f43ab23d9cabfd836f0bb157c6 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Sat, 20 Jun 2020 01:50:55 +0200 Subject: [PATCH 16/18] Bump ameba dependency --- shard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shard.yml b/shard.yml index baf1223..c462743 100644 --- a/shard.yml +++ b/shard.yml @@ -15,7 +15,7 @@ development_dependencies: version: ~> 0.4.0 ameba: github: crystal-ameba/ameba - version: ~> 0.12.0 + version: ~> 0.13.0 targets: crash_handler: From 70ee7f57bde375d5aa58418f5349d23d3812fe57 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Sat, 20 Jun 2020 06:04:23 +0200 Subject: [PATCH 17/18] Use `Log::Entry#{context,data}` to fill `Breadcrumb#data` --- src/raven/integrations/kernel/log.cr | 12 ++++++++++-- src/raven/integrations/kernel/logger.cr | 6 ++++-- .../integrations/shared/breadcrumb_log_helper.cr | 11 ++++++----- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/raven/integrations/kernel/log.cr b/src/raven/integrations/kernel/log.cr index 08229ea..2095292 100644 --- a/src/raven/integrations/kernel/log.cr +++ b/src/raven/integrations/kernel/log.cr @@ -1,4 +1,5 @@ require "log" +require "log/json" require "../shared/breadcrumb_log_helper" module Raven @@ -33,11 +34,18 @@ module Raven if ex = entry.exception message += " -- (#{ex.class}): #{ex.message || "n/a"}" end + + level = BREADCRUMB_LEVELS[entry.severity]? + + data = entry.context.extend(entry.data.to_h) + data = data.empty? ? nil : JSON.parse(data.to_json).as_h + record_breadcrumb( - BREADCRUMB_LEVELS[entry.severity]?, + message, + level, entry.timestamp, entry.source, - message, + data, ) end end diff --git a/src/raven/integrations/kernel/logger.cr b/src/raven/integrations/kernel/logger.cr index 0769699..dc1ef5a 100644 --- a/src/raven/integrations/kernel/logger.cr +++ b/src/raven/integrations/kernel/logger.cr @@ -13,11 +13,13 @@ class Logger } of ::Logger::Severity => Raven::Breadcrumb::Severity private def write(severity, datetime, progname, message) + level = BREADCRUMB_LEVELS[severity]? + record_breadcrumb( - BREADCRUMB_LEVELS[severity]?, + message, + level, datetime, progname, - message, ) previous_def end diff --git a/src/raven/integrations/shared/breadcrumb_log_helper.cr b/src/raven/integrations/shared/breadcrumb_log_helper.cr index 7a1378e..137f21c 100644 --- a/src/raven/integrations/shared/breadcrumb_log_helper.cr +++ b/src/raven/integrations/shared/breadcrumb_log_helper.cr @@ -9,13 +9,14 @@ module Raven end end - protected def record_breadcrumb(level, timestamp, category, message) : Breadcrumb? - return if Raven.configuration.ignored_logger?(category) + protected def record_breadcrumb(message, level, timestamp, source, data = nil) + return if Raven.configuration.ignored_logger?(source) Raven.breadcrumbs.record do |crumb| - crumb.level = level - crumb.timestamp = timestamp - crumb.category = category.presence || "logger" crumb.message = deansify(message).presence + crumb.level = level if level + crumb.timestamp = timestamp if timestamp + crumb.category = source.presence || "logger" + crumb.data = data if data end end end From 11d5ff964481c1f76bcc68df4b685874ad74b475 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Sat, 20 Jun 2020 06:56:00 +0200 Subject: [PATCH 18/18] Bump to v1.7.0 --- shard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shard.yml b/shard.yml index c462743..94866a3 100644 --- a/shard.yml +++ b/shard.yml @@ -1,5 +1,5 @@ name: raven -version: 1.7.0-dev +version: 1.7.0 authors: - Sijawusz Pur Rahnama