Skip to content

Commit 6a63405

Browse files
committed
Add Sentry::DebugTransport for testing/debugging
1 parent 36920ac commit 6a63405

File tree

6 files changed

+131
-0
lines changed

6 files changed

+131
-0
lines changed

sentry-ruby/lib/sentry/configuration.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ def capture_exception_frame_locals=(value)
196196
# @return [Logger]
197197
attr_accessor :sdk_logger
198198

199+
# File path for DebugTransport to log events to. If not set, defaults to a temporary file.
200+
# This is useful for debugging and testing purposes.
201+
# @return [String, nil]
202+
attr_accessor :sdk_debug_transport_log_file
203+
199204
# @deprecated Use {#sdk_logger=} instead.
200205
def logger=(logger)
201206
warn "[sentry] `config.logger=` is deprecated. Please use `config.sdk_logger=` instead."

sentry-ruby/lib/sentry/test_helper.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ def setup_sentry_test(&block)
4646
def teardown_sentry_test
4747
return unless Sentry.initialized?
4848

49+
transport = Sentry.get_current_client&.transport
50+
if transport.is_a?(Sentry::DebugTransport)
51+
transport.clear_events
52+
end
53+
4954
# pop testing layer created by `setup_sentry_test`
5055
# but keep the base layer to avoid nil-pointer errors
5156
# TODO: find a way to notify users if they somehow popped the test layer before calling this method

sentry-ruby/lib/sentry/transport.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,4 @@ def reject_rate_limited_items(envelope)
223223
require "sentry/transport/dummy_transport"
224224
require "sentry/transport/http_transport"
225225
require "sentry/transport/spotlight_transport"
226+
require "sentry/transport/debug_transport"
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# frozen_string_literal: true
2+
3+
require "json"
4+
require "fileutils"
5+
6+
module Sentry
7+
# DebugTransport is a transport that logs events to a file for debugging purposes.
8+
#
9+
# It can optionally also send events to Sentry via HTTP transport if a real DSN
10+
# is provided.
11+
class DebugTransport < Transport
12+
attr_reader :log_file_path, :http_transport
13+
14+
def initialize(configuration)
15+
super
16+
17+
@log_file_path = configuration.sdk_debug_transport_log_file || default_log_file_path
18+
19+
FileUtils.mkdir_p(File.dirname(@log_file_path))
20+
21+
log_debug("DebugTransport: Initialized with log file: #{@log_file_path}")
22+
23+
if configuration.dsn && !configuration.dsn.to_s.include?("localhost")
24+
@http_transport = Sentry::HTTPTransport.new(configuration)
25+
log_debug("DebugTransport: Initialized with HTTP transport for DSN: #{configuration.dsn}")
26+
else
27+
@http_transport = nil
28+
log_debug("DebugTransport: Using local-only mode for DSN: #{configuration.dsn}")
29+
end
30+
end
31+
32+
def send_event(event)
33+
envelope = envelope_from_event(event)
34+
send_envelope(envelope)
35+
event
36+
end
37+
38+
def send_envelope(envelope)
39+
envelope_data = {
40+
timestamp: Time.now.utc.iso8601,
41+
envelope_headers: envelope.headers,
42+
items: envelope.items.map do |item|
43+
{
44+
headers: item.headers,
45+
payload: item.payload
46+
}
47+
end
48+
}
49+
50+
File.open(log_file_path, "a") do |file|
51+
file << JSON.dump(envelope_data) << "\n"
52+
end
53+
54+
if http_transport
55+
http_transport.send_envelope(envelope)
56+
end
57+
end
58+
59+
def events
60+
return [] unless File.exist?(log_file_path)
61+
62+
File.readlines(log_file_path).map do |line|
63+
JSON.load(line)
64+
end
65+
end
66+
67+
def clear
68+
File.write(log_file_path, "")
69+
log_debug("DebugTransport: Cleared events from #{log_file_path}")
70+
end
71+
72+
private
73+
74+
def default_log_file_path
75+
if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
76+
File.join(Rails.root, "log", "sentry_debug_events.log")
77+
elsif File.directory?("log")
78+
File.join("log", "sentry_debug_events.log")
79+
else
80+
"/tmp/sentry_debug_events.json"
81+
end
82+
end
83+
end
84+
end
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# frozen_string_literal: true
2+
3+
require 'contexts/with_request_mock'
4+
5+
RSpec.describe Sentry do
6+
include_context "with request mock"
7+
8+
let(:client) { Sentry.get_current_client }
9+
let(:transport) { Sentry.get_current_client.transport }
10+
11+
before do
12+
perform_basic_setup do |config|
13+
config.transport.transport_class = Sentry::DebugTransport
14+
end
15+
end
16+
17+
describe ".send_event" do
18+
let(:event) { Sentry.get_current_client.event_from_message("test message") }
19+
20+
it "sends the event and logs to a file" do
21+
sentry_stub_request(build_fake_response("200"))
22+
23+
Sentry.send_event(event)
24+
25+
expect(transport.events.count).to be(1)
26+
end
27+
end
28+
end

sentry-ruby/spec/spec_helper.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@
7979
end
8080

8181
config.after(:each) do
82+
if Sentry.initialized?
83+
transport = Sentry.get_current_client&.transport
84+
85+
if transport.is_a?(Sentry::DebugTransport)
86+
transport.clear
87+
end
88+
end
89+
8290
reset_sentry_globals!
8391
end
8492

0 commit comments

Comments
 (0)