Class: Smplkit::Logging::Adapters::StdlibLoggerAdapter

Inherits:
Base
  • Object
show all
Defined in:
lib/smplkit/logging/adapters/stdlib_logger_adapter.rb

Overview

Adapter for Ruby stdlib Logger (which ActiveSupport::Logger subclasses, so Rails is covered automatically).

Ruby has no global logger registry like Python’s logging.Logger.manager.loggerDict. Instead this adapter:

1. Always reports +"root"+ at the framework default level.
2. Reports +"rails"+ if +Rails.logger+ is defined.
3. Reports any logger explicitly registered via +track+.
4. Uses +Module#prepend+ on +::Logger+ to catch new logger
   creation. The hook fires on every +Logger.new+ call.

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeStdlibLoggerAdapter

Returns a new instance of StdlibLoggerAdapter.



28
29
30
31
32
33
34
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 28

def initialize
  super
  @loggers = Concurrent::Hash.new
  track_root!
  @on_new = nil
  @uninstalled = false
end

Class Attribute Details

.hook_moduleObject (readonly)

Returns the value of attribute hook_module.



25
26
27
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 25

def hook_module
  @hook_module
end

Class Method Details

.adaptersObject



103
104
105
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 103

def adapters
  @adapters ||= Concurrent::Array.new
end

.build_hookObject



115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 115

def build_hook
  Module.new do
    def initialize(*args, **kwargs)
      super
      StdlibLoggerAdapter.adapters.each do |adapter|
        adapter.on_new_logger_created(self, "logger.#{object_id}")
      rescue StandardError
        # Swallow to keep Logger.new robust under the hook.
      end
    end
  end
end

.global_lockObject



107
108
109
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 107

def global_lock
  @global_lock ||= Mutex.new
end

.hook_installed?Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 111

def hook_installed?
  !@hook_module.nil?
end

.reset_hook!Object



128
129
130
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 128

def reset_hook!
  @hook_module = nil
end

Instance Method Details

#apply_level(logger_name, level) ⇒ Object



64
65
66
67
68
69
70
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 64

def apply_level(logger_name, level)
  logger = @loggers[logger_name]
  return unless logger

  native = Levels.smpl_level_to_stdlib(level)
  logger.level = native
end

#discoverObject



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 46

def discover
  rows = []
  @loggers.each_pair do |logger_name, logger|
    level = logger.level
    smpl_level = Levels.stdlib_level_to_smpl(level)
    rows << [logger_name, smpl_level, smpl_level]
  end

  if defined?(::Rails) && ::Rails.respond_to?(:logger) && ::Rails.logger
    track("rails", ::Rails.logger) unless @loggers.key?("rails")
    level = ::Rails.logger.level
    smpl_level = Levels.stdlib_level_to_smpl(level)
    rows << ["rails", smpl_level, smpl_level]
  end

  rows.uniq { |row| row[0] }
end

#install_hook(&on_new_logger) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 72

def install_hook(&on_new_logger)
  @on_new = on_new_logger
  @uninstalled = false

  self.class.global_lock.synchronize do
    unless self.class.hook_installed?
      hook = self.class.build_hook
      ::Logger.prepend(hook)
      self.class.instance_variable_set(:@hook_module, hook)
    end
    self.class.adapters << self
  end
end

#nameObject



36
37
38
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 36

def name
  "stdlib-logger"
end

#on_new_logger_created(logger, name) ⇒ Object

Called by the prepended hook when a new Logger is created.



94
95
96
97
98
99
100
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 94

def on_new_logger_created(logger, name)
  return if @uninstalled

  track(name, logger)
  smpl_level = Levels.stdlib_level_to_smpl(logger.level)
  @on_new&.call(name, smpl_level, smpl_level)
end

#track(logger_name, logger) ⇒ Object

Register an additional logger with the adapter so its level can be discovered and applied.



42
43
44
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 42

def track(logger_name, logger)
  @loggers[logger_name] = logger
end

#uninstall_hookObject



86
87
88
89
90
91
# File 'lib/smplkit/logging/adapters/stdlib_logger_adapter.rb', line 86

def uninstall_hook
  @uninstalled = true
  self.class.global_lock.synchronize do
    self.class.adapters.delete(self)
  end
end