Uh oh!
There was an error while loading. Please reload this page.
Add thread-local log level - #85
Conversation
| # 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)dolog.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.
ioquatix
commented
Feb 7, 2023
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.
Uh oh!
There was an error while loading. Please reload this page.
| # 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. |
mperham
commented
Feb 9, 2023
Ok, refactored based on feedback. |
jeremyevans
left a comment
There was a problem hiding this comment.
Looks pretty good. One more implementation change requested.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Samuel Williams <samuel.williams@oriontransfer.co.nz>
ioquatix
commented
Feb 10, 2023
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.
Uh oh!
There was an error while loading. Please reload this page.
| 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.
mperham
commented
Feb 10, 2023
Really? irb 3.2 works fine without it: |
jeremyevans
commented
Feb 10, 2023
According to CI, |
mperham
commented
Feb 10, 2023
Right, looks like 3.1+ doesn't require "fiber" anymore. |
(ruby/logger#85) * Update lib/logger/severity.rb ruby/logger@7aabb0b4aa
ioquatix
commented
Feb 10, 2023
Thanks @mperham - I want to make one more PR and then we will try to cut a release. |
yahonda
commented
Feb 14, 2023
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?
jaynetics
commented
Jul 9, 2023
Generally speaking, this breaks any logger subclass that does not call super in its initializer. |
mperham
commented
Jul 9, 2023
I don't believe adding additional complexity to work around 3rd party bugs is a good idea. Not calling super is a bug, no? |
skipkayhil
commented
Sep 25, 2023
Hey @ioquatix, did that other PR ever land? I'd love to see this released so we could potentially use it to replace the |
ghiculescu
commented
Jun 10, 2024
@skipkayhil FYI this has been released now. |
skipkayhil
commented
Nov 6, 2024
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