Conversation
lib/logger.rb
Outdated
| # logger.with_level(:debug) do | ||
| # logger.debug { "Hello" } | ||
| # end | ||
| def with_level(severity, &block) |
There was a problem hiding this comment.
Alternative name: at?
log.at(:debug) do
log.debug("You'll see this")
endThere was a problem hiding this comment.
I think with_level is much more clear what is going on.
There was a problem hiding this comment.
&block is not needed, since you are only yielding and not capturing.
|
Sorry, I did not see this. Please mention me or add me as a reviewer in the future, otherwise I don't know about it :) |
jeremyevans
left a comment
There was a problem hiding this comment.
I'm OK with the idea, but I'm against pollute Thread.current with this. Instead, add a instance variable storing a hash inside the logger keyed by Thread.current. This approach also makes it simple to change from a thread-local implementation to a fiber-local or global implementation by changing the key.
lib/logger.rb
Outdated
| # logger.with_level(:debug) do | ||
| # logger.debug { "Hello" } | ||
| # end | ||
| def with_level(severity, &block) |
There was a problem hiding this comment.
&block is not needed, since you are only yielding and not capturing.
|
Thanks @jeremyevans, great review. What do you think about using It might make sense just to leave this as implementation dependent so that other loggers (e.g. the ones I maintain) can be fiber-specific or use fiber-storage instead. |
|
Ok, refactored based on feedback. |
jeremyevans
left a comment
There was a problem hiding this comment.
Looks pretty good. One more implementation change requested.
Co-authored-by: Samuel Williams <samuel.williams@oriontransfer.co.nz>
|
Sorry, one more change is required, we will need to add |
jeremyevans
left a comment
There was a problem hiding this comment.
Couple of small things that could be fixed, but I don't think need to block merging.
| logger.with_level(DEBUG) do # verify reentrancy | ||
| assert_equal(logger.level, DEBUG) | ||
|
|
||
| Thread.new do |
There was a problem hiding this comment.
This tests for Thread-local, not explicitly for Fiber-local, but works since a new Thread is also a new Fiber. Not sure if we want to explicitly test for Fiber-localness. Could be done later.
Really? irb 3.2 works fine without it: |
|
According to CI, |
Right, looks like 3.1+ doesn't require "fiber" anymore. |
(ruby/logger#85) * Update lib/logger/severity.rb ruby/logger@7aabb0b4aa
|
Thanks @mperham - I want to make one more PR and then we will try to cut a release. |
|
This commit introduces |
ruby/logger#85 added this to the `Logger` initializer. Since we don't call `super` in `initialize`, we need to do it ourselves. Not doing this leads to an error in `Logger#level`: # undefined method `[]' for nil:NilClass (NoMethodError): def level @level_override[Fiber.current] || @Level # ^^^^^^^^^^^^^^^ end
ruby/logger#85 added this to the `Logger` initializer. Since we don't call `super` in `initialize`, we need to do it ourselves. Not doing this leads to an error in `Logger#level`: ```ruby def level @level_override[Fiber.current] || @Level # ^^^^^^^^^^^^^^^ end ```
ruby/logger#85 added `@level_override` to the `Logger` initializer. Since we didn't call `super` in `initialize`, the variable was uninitialized, and we would run into a `NoMethodError` in `Logger#level` on Ruby HEAD: def level @level_override[Fiber.current] || @Level # ^^^^^^^^^^^^^^^ NoMethodError: undefined method `[]' for nil:NilClass end
logger 1.4.3 will have ruby/logger#85. It initializes a new instance variable in `Logger#initialize`. `Jekyll::Stevenson < ::Logger` doesn't use `super`. So the new instance variable isn't initialized in `Jekyll::Stevenson`. And it causes an exception: ```text /tmp/local/lib/ruby/3.3.0+0/logger.rb:385:in `level': undefined method `[]' for nil (NoMethodError) @level_override[Fiber.current] || @Level ^^^^^^^^^^^^^^^ from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/log_adapter.rb:45:in `adjust_verbosity' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/configuration.rb:143:in `config_files' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll.rb:118:in `configuration' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/command.rb:44:in `configuration_from_options' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/commands/serve.rb:83:in `block (2 levels) in init_with_program' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `block in execute' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `each' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `execute' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/program.rb:44:in `go' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary.rb:21:in `program' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/exe/jekyll:15:in `<top (required)>' from /tmp/local/bin/jekyll:25:in `load' from /tmp/local/bin/jekyll:25:in `<top (required)>' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli/exec.rb:58:in `load' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli/exec.rb:58:in `kernel_load' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli/exec.rb:23:in `run' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli.rb:492:in `exec' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor/command.rb:27:in `run' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor.rb:392:in `dispatch' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli.rb:34:in `dispatch' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor/base.rb:485:in `start' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli.rb:28:in `start' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/bundler-2.5.0.dev/libexec/bundle:37:in `block in <top (required)>' from /tmp/local/lib/ruby/3.3.0+0/bundler/friendly_errors.rb:117:in `with_friendly_errors' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/bundler-2.5.0.dev/libexec/bundle:29:in `<top (required)>' from /tmp/local/bin/bundle:25:in `load' from /tmp/local/bin/bundle:25:in `<main>' ``` How about using `super` instead of implementing our `Jekyll::Stevenson#initialize` to reduce maintenance cost?
logger 1.4.3 will have ruby/logger#85. It initializes a new instance variable in `Logger#initialize`. `Jekyll::Stevenson < ::Logger` doesn't use `super`. So the new instance variable isn't initialized in `Jekyll::Stevenson`. And it causes an exception: ```text /tmp/local/lib/ruby/3.3.0+0/logger.rb:385:in `level': undefined method `[]' for nil (NoMethodError) @level_override[Fiber.current] || @Level ^^^^^^^^^^^^^^^ from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/log_adapter.rb:45:in `adjust_verbosity' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/configuration.rb:143:in `config_files' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll.rb:118:in `configuration' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/command.rb:44:in `configuration_from_options' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/commands/serve.rb:83:in `block (2 levels) in init_with_program' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `block in execute' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `each' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `execute' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/program.rb:44:in `go' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary.rb:21:in `program' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/exe/jekyll:15:in `<top (required)>' from /tmp/local/bin/jekyll:25:in `load' from /tmp/local/bin/jekyll:25:in `<top (required)>' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli/exec.rb:58:in `load' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli/exec.rb:58:in `kernel_load' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli/exec.rb:23:in `run' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli.rb:492:in `exec' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor/command.rb:27:in `run' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor.rb:392:in `dispatch' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli.rb:34:in `dispatch' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor/base.rb:485:in `start' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli.rb:28:in `start' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/bundler-2.5.0.dev/libexec/bundle:37:in `block in <top (required)>' from /tmp/local/lib/ruby/3.3.0+0/bundler/friendly_errors.rb:117:in `with_friendly_errors' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/bundler-2.5.0.dev/libexec/bundle:29:in `<top (required)>' from /tmp/local/bin/bundle:25:in `load' from /tmp/local/bin/bundle:25:in `<main>' ``` How about using `super` instead of implementing our `Jekyll::Stevenson#initialize` to reduce maintenance cost?
logger 1.4.3 will have ruby/logger#85. It initializes a new instance variable in `Logger#initialize`. `Jekyll::Stevenson < ::Logger` doesn't use `super`. So the new instance variable isn't initialized in `Jekyll::Stevenson`. And it causes an exception: ```text /tmp/local/lib/ruby/3.3.0+0/logger.rb:385:in `level': undefined method `[]' for nil (NoMethodError) @level_override[Fiber.current] || @Level ^^^^^^^^^^^^^^^ from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/log_adapter.rb:45:in `adjust_verbosity' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/configuration.rb:143:in `config_files' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll.rb:118:in `configuration' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/command.rb:44:in `configuration_from_options' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/lib/jekyll/commands/serve.rb:83:in `block (2 levels) in init_with_program' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `block in execute' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `each' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `execute' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary/program.rb:44:in `go' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/mercenary-0.4.0/lib/mercenary.rb:21:in `program' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/jekyll-4.3.2/exe/jekyll:15:in `<top (required)>' from /tmp/local/bin/jekyll:25:in `load' from /tmp/local/bin/jekyll:25:in `<top (required)>' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli/exec.rb:58:in `load' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli/exec.rb:58:in `kernel_load' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli/exec.rb:23:in `run' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli.rb:492:in `exec' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor/command.rb:27:in `run' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor.rb:392:in `dispatch' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli.rb:34:in `dispatch' from /tmp/local/lib/ruby/3.3.0+0/bundler/vendor/thor/lib/thor/base.rb:485:in `start' from /tmp/local/lib/ruby/3.3.0+0/bundler/cli.rb:28:in `start' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/bundler-2.5.0.dev/libexec/bundle:37:in `block in <top (required)>' from /tmp/local/lib/ruby/3.3.0+0/bundler/friendly_errors.rb:117:in `with_friendly_errors' from /tmp/local/lib/ruby/gems/3.3.0+0/gems/bundler-2.5.0.dev/libexec/bundle:29:in `<top (required)>' from /tmp/local/bin/bundle:25:in `load' from /tmp/local/bin/bundle:25:in `<main>' ``` How about using `super` instead of implementing our `Jekyll::Stevenson#initialize` to reduce maintenance cost?
Generally speaking, this breaks any logger subclass that does not call super in its initializer. |
|
I don't believe adding additional complexity to work around 3rd party bugs is a good idea. Not calling super is a bug, no? |
Hey @ioquatix, did that other PR ever land? I'd love to see this released so we could potentially use it to replace the |
|
@skipkayhil FYI this has been released now. |
|
I believe we need something like this to replace |
This adds Logger#with_level which provides a thread-local log level so Threads can temporarily enable logging for a given block.
Fixes #84