Skip to content

Commit

Permalink
Subclasses initialize must call super
Browse files Browse the repository at this point in the history
Warn wrong code, #100:
> Some Ruby apps subclass Logger without running the superclass
> constructor, which means that `@level_override` isn't initialized
> properly.
  • Loading branch information
nobu committed Feb 14, 2025
1 parent 30e4359 commit 1efdf6b
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 0 deletions.
9 changes: 9 additions & 0 deletions lib/logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,15 @@ def format_severity(severity)

# Guarantee the existence of this ivar even when subclasses don't call the superclass constructor.
def level_override
unless defined?(@level_override)
bad = self.class.instance_method(:initialize)
file, line = bad.source_location
Kernel.warn <<~";;;", uplevel: 2
Logger not initialized properly
#{file}:#{line}: info: #{bad.owner}\##{bad.name}: \
does not call super probably
;;;
end
@level_override ||= {}
end

Expand Down
15 changes: 15 additions & 0 deletions test/logger/test_logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -399,4 +399,19 @@ def test_does_not_instantiate_log_device_for_File_NULL
l = Logger.new(File::NULL)
assert_nil(l.instance_variable_get(:@logdev))
end

def test_subclass_initialize
bad_logger = Class.new(Logger) {def initialize(*); end}.new(IO::NULL)
line = __LINE__ - 1
file = Regexp.quote(__FILE__)
assert_warning(/not initialized properly.*\n#{file}:#{line}:/) do
bad_logger.level
end

good_logger = Class.new(Logger) {def initialize(*); super; end}.new(IO::NULL)
file = Regexp.quote(__FILE__)
assert_warning('') do
good_logger.level
end
end
end

0 comments on commit 1efdf6b

Please sign in to comment.