Skip to content

Commit 64cafc3

Browse files
committed
preserve existing prosopite custom loggers
1 parent a50ac13 commit 64cafc3

File tree

6 files changed

+245
-1
lines changed

6 files changed

+245
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## [Unreleased]
22

3+
- Preserve existing prosopite custom loggers
4+
35
## [0.5.1] - 2025-09-27
46

57
- Don't clean up stale storage data in railtie

lib/dial/prosopite.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,35 @@
22

33
require "active_support/core_ext/string/filters"
44

5+
require_relative "prosopite_composite_logger"
6+
57
module Dial
68
module Prosopite
9+
def custom_logger= logger
10+
return super logger if @setting_dial_logger
11+
12+
@original_logger = logger
13+
14+
if @dial_logger && @original_logger
15+
super ProsopiteCompositeLogger.new @dial_logger, @original_logger
16+
else
17+
super logger
18+
end
19+
end
20+
21+
def dial_logger= logger
22+
@dial_logger = logger
23+
24+
@setting_dial_logger = true
25+
if @original_logger
26+
self.custom_logger = ProsopiteCompositeLogger.new @dial_logger, @original_logger
27+
else
28+
self.custom_logger = @dial_logger
29+
end
30+
ensure
31+
@setting_dial_logger = false
32+
end
33+
734
def send_notifications
835
tc[:prosopite_notifications] = tc[:prosopite_notifications].to_h do |queries, kaller|
936
[queries.map { |query| query.squish }, kaller]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# frozen_string_literal: true
2+
3+
require "logger"
4+
5+
module Dial
6+
class ProsopiteCompositeLogger
7+
def initialize dial_logger, existing_logger = nil
8+
@dial_logger = dial_logger
9+
@existing_logger = existing_logger
10+
end
11+
12+
def level
13+
@dial_logger.level
14+
end
15+
16+
def level= value
17+
@dial_logger.level = value
18+
@existing_logger.level = value if @existing_logger&.respond_to? :level=
19+
end
20+
21+
def method_missing method, *args, &block
22+
result = nil
23+
result = @dial_logger.send method, *args, &block if @dial_logger.respond_to? method
24+
@existing_logger.send method, *args, &block if @existing_logger&.respond_to? method
25+
result
26+
end
27+
28+
def respond_to_missing? method, include_private = false
29+
@dial_logger.respond_to?(method, include_private) ||
30+
@existing_logger&.respond_to?(method, include_private) ||
31+
false
32+
end
33+
end
34+
end

lib/dial/railtie.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Railtie < ::Rails::Railtie
1515
if ::ActiveRecord::Base.configurations.configurations.any? { |config| config.adapter == "postgresql" }
1616
require "pg_query"
1717
end
18-
::Prosopite.custom_logger = ProsopiteLogger.new
18+
::Prosopite.dial_logger = ProsopiteLogger.new
1919

2020
# finalize configuration
2121
Dial._configuration.freeze
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
5+
module Dial
6+
class TestProsopiteCompositeLogger < ActiveSupport::TestCase
7+
def setup
8+
@dial_logger = ProsopiteLogger.new
9+
@existing_logger = Logger.new StringIO.new
10+
@composite_logger = ProsopiteCompositeLogger.new @dial_logger, @existing_logger
11+
end
12+
13+
def test_composite_logger_delegates_to_both_loggers
14+
message = "Test N+1 query detected"
15+
16+
@composite_logger.warn message
17+
18+
assert_includes ProsopiteLogger.log_io.string, message
19+
assert @existing_logger.respond_to? :warn
20+
end
21+
22+
def test_composite_logger_handles_nil_existing_logger
23+
composite_logger = ProsopiteCompositeLogger.new @dial_logger, nil
24+
25+
assert_nothing_raised do
26+
composite_logger.warn "Test message"
27+
end
28+
29+
assert_includes ProsopiteLogger.log_io.string, "Test message"
30+
end
31+
32+
def test_composite_logger_forwards_all_methods
33+
assert_nothing_raised do
34+
@composite_logger.info "test info"
35+
@composite_logger.add Logger::WARN, "test add"
36+
end
37+
38+
log_content = ProsopiteLogger.log_io.string
39+
assert_includes log_content, "test info"
40+
assert_includes log_content, "test add"
41+
end
42+
43+
def test_composite_logger_level_getter_and_setter
44+
@dial_logger.level = Logger::ERROR
45+
assert_equal Logger::ERROR, @composite_logger.level
46+
47+
@composite_logger.level = Logger::WARN
48+
assert_equal Logger::WARN, @dial_logger.level
49+
assert_equal Logger::WARN, @existing_logger.level
50+
end
51+
52+
def test_method_missing_delegation
53+
assert @composite_logger.respond_to? :progname
54+
55+
assert_nothing_raised do
56+
@composite_logger.progname
57+
end
58+
end
59+
60+
def test_respond_to_missing_works_correctly
61+
assert @composite_logger.respond_to? :warn
62+
assert @composite_logger.respond_to? :progname
63+
refute @composite_logger.respond_to? :nonexistent_method
64+
end
65+
end
66+
end
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
5+
module Dial
6+
class TestProsopiteIntegration < ActiveSupport::TestCase
7+
def setup
8+
::Prosopite.instance_variable_set :@custom_logger, false
9+
::Prosopite.instance_variable_set :@dial_logger, nil
10+
::Prosopite.instance_variable_set :@original_logger, nil
11+
end
12+
13+
def teardown
14+
::Prosopite.instance_variable_set :@custom_logger, false
15+
::Prosopite.instance_variable_set :@dial_logger, nil
16+
::Prosopite.instance_variable_set :@original_logger, nil
17+
end
18+
19+
def test_dial_logger_sets_custom_logger_when_none_exists
20+
test_logger = ProsopiteLogger.new
21+
22+
::Prosopite.dial_logger = test_logger
23+
24+
assert_equal test_logger, ::Prosopite.instance_variable_get(:@custom_logger)
25+
end
26+
27+
def test_dial_logger_preserves_existing_custom_logger
28+
existing_logger = Logger.new StringIO.new
29+
::Prosopite.custom_logger = existing_logger
30+
31+
dial_logger = ProsopiteLogger.new
32+
::Prosopite.dial_logger = dial_logger
33+
34+
assert_instance_of ProsopiteCompositeLogger, ::Prosopite.instance_variable_get(:@custom_logger)
35+
end
36+
37+
def test_setting_custom_logger_after_dial_logger_creates_composite
38+
dial_logger = ProsopiteLogger.new
39+
::Prosopite.dial_logger = dial_logger
40+
41+
existing_logger = Logger.new StringIO.new
42+
::Prosopite.custom_logger = existing_logger
43+
44+
assert_instance_of ProsopiteCompositeLogger, ::Prosopite.instance_variable_get(:@custom_logger)
45+
end
46+
47+
def test_setting_dial_logger_twice_updates_composite
48+
existing_logger = Logger.new StringIO.new
49+
::Prosopite.custom_logger = existing_logger
50+
51+
dial_logger1 = ProsopiteLogger.new
52+
::Prosopite.dial_logger = dial_logger1
53+
54+
first_composite = ::Prosopite.instance_variable_get(:@custom_logger)
55+
assert_instance_of ProsopiteCompositeLogger, first_composite
56+
57+
dial_logger2 = ProsopiteLogger.new
58+
::Prosopite.dial_logger = dial_logger2
59+
60+
second_composite = ::Prosopite.instance_variable_get(:@custom_logger)
61+
assert_instance_of ProsopiteCompositeLogger, second_composite
62+
63+
refute_same first_composite, second_composite
64+
end
65+
66+
def test_composite_logger_receives_notifications
67+
existing_io = StringIO.new
68+
existing_logger = Logger.new existing_io
69+
::Prosopite.custom_logger = existing_logger
70+
71+
dial_logger = ProsopiteLogger.new
72+
::Prosopite.dial_logger = dial_logger
73+
74+
Thread.current[:prosopite_notifications] = {
75+
["SELECT * FROM users"] => ["app/controllers/users_controller.rb:10"]
76+
}
77+
78+
::Prosopite.send :send_notifications
79+
80+
assert_includes existing_io.string, "N+1 queries detected"
81+
assert_includes ProsopiteLogger.log_io.string, "N+1 queries detected"
82+
end
83+
84+
def test_setting_same_logger_twice_does_not_create_nested_composite
85+
existing_logger = Logger.new StringIO.new
86+
::Prosopite.custom_logger = existing_logger
87+
88+
dial_logger = ProsopiteLogger.new
89+
::Prosopite.dial_logger = dial_logger
90+
91+
::Prosopite.custom_logger = existing_logger
92+
93+
custom_logger = ::Prosopite.instance_variable_get(:@custom_logger)
94+
assert_instance_of ProsopiteCompositeLogger, custom_logger
95+
96+
dial_internal = custom_logger.instance_variable_get(:@dial_logger)
97+
existing_internal = custom_logger.instance_variable_get(:@existing_logger)
98+
99+
assert_equal dial_logger, dial_internal
100+
assert_equal existing_logger, existing_internal
101+
end
102+
103+
def test_setting_custom_logger_to_nil_removes_existing_logger
104+
existing_logger = Logger.new StringIO.new
105+
::Prosopite.custom_logger = existing_logger
106+
107+
dial_logger = ProsopiteLogger.new
108+
::Prosopite.dial_logger = dial_logger
109+
110+
::Prosopite.custom_logger = nil
111+
112+
assert_nil ::Prosopite.instance_variable_get(:@custom_logger)
113+
end
114+
end
115+
end

0 commit comments

Comments
 (0)