Repository: ruby/debug (Ruby)

Issue:
Exception thrown when log level is set by environment variable
```bash
export RUBY_DEBUG_LOG_LEVEL=INFO
./bin/rails console
```

results in:

```bash
11: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug.rb:3:in `<top (required)>'
10: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug.rb:3:in `require_relative'
 9: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug/session.rb:6:in `<top (required)>'
 8: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug/session.rb:6:in `require_relative'
 7: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug/config.rb:3:in `<top (required)>'
 6: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug/config.rb:335:in `<module:DEBUGGER__>'
 5: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug/config.rb:335:in `new'
 4: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug/config.rb:48:in `initialize'
 3: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug/config.rb:196:in `parse_argv'
 2: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug/config.rb:196:in `each'
 1: from /Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug/config.rb:198:in `block in parse_argv'
/Users/dhh/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/debug-1.0.0/lib/debug/config.rb:174:in `parse_config_value': uninitialized constant DEBUGGER__::LOG_LEVELS (NameError)
```

Because debug.rb requires session.rb which requires config.rb at the top, before it's defined itself, which means that `DEBUGGER__::LOG_LEVELS` is not yet declared by the time config.rb wants to use it in `#parse_config_value`.


Discussion:

Patch:
diff --git a/lib/debug/config.rb b/lib/debug/config.rb
index 25dcd63b5..c4e71a1b9 100644
--- a/lib/debug/config.rb
+++ b/lib/debug/config.rb
@@ -1,6 +1,14 @@
 # frozen_string_literal: true
 
 module DEBUGGER__
+  LOG_LEVELS = {
+    UNKNOWN: 0,
+    FATAL:   1,
+    ERROR:   2,
+    WARN:    3,
+    INFO:    4,
+  }.freeze
+
   CONFIG_SET = {
     # UI setting
     log_level:      ['RUBY_DEBUG_LOG_LEVEL',      "UI: Log level same as Logger (default: WARN)",                   :loglevel],
diff --git a/lib/debug/session.rb b/lib/debug/session.rb
index e85cce2c5..309d316bf 100644
--- a/lib/debug/session.rb
+++ b/lib/debug/session.rb
@@ -1599,14 +1599,6 @@ def self.short_inspect obj, use_short = true
     end
   end
 
-  LOG_LEVELS = {
-    UNKNOWN: 0,
-    FATAL:   1,
-    ERROR:   2,
-    WARN:    3,
-    INFO:    4,
-  }.freeze
-
   def self.warn msg
     log :WARN, msg
   end


Test patch:
diff --git a/test/debug/config_test.rb b/test/debug/config_test.rb
index 18b6aea73..87b30d393 100644
--- a/test/debug/config_test.rb
+++ b/test/debug/config_test.rb
@@ -303,4 +303,42 @@ def test_p_with_keep_alloc_site
       end
     end
   end
+
+  class LogLevelTest < TestCase
+    def program
+      <<~RUBY
+      1| a = 1
+      RUBY
+    end
+
+    def test_debugger_takes_log_level_config_from_env_var
+      # default WARN level doesn't report threads creation
+      debug_code(program, remote: false) do
+        type 'Thread.new {}.join'
+        assert_no_line_text(/Thread #\d+ is created/)
+        type 'c'
+      end
+
+      ENV["RUBY_DEBUG_LOG_LEVEL"] = "INFO"
+      debug_code(program, remote: false) do
+        type 'Thread.new {}.join'
+        assert_line_text(/DEBUGGER \(INFO\): Thread #\d+ is created/)
+        type 'c'
+      end
+    ensure
+      ENV["RUBY_DEBUG_LOG_LEVEL"] = nil
+    end
+
+    def test_debugger_takes_log_level_config_from_config_option
+      # default WARN level doesn't report threads creation
+      debug_code(program, remote: false) do
+        type 'Thread.new {}.join'
+        assert_no_line_text(/Thread #\d+ is created/)
+        type 'config set log_level INFO'
+        type 'Thread.new {}.join'
+        assert_line_text(/DEBUGGER \(INFO\): Thread #\d+ is created/)
+        type 'c'
+      end
+    end
+  end
 end