A logger injection gem
This gem can be used to inject several loggers in different parts of your Ruby project.
It will try to support as many methods and levels as the underlying object supports, and fall back to a supported level in case some levels are not available
How to use it
You have to declare the log levels that your code will be using, and InjectedLogger will make sure that the underlying object supports them.
The user of your code will just pass the logger and refer to either a module of yours or a symbolic name or string.
Suppose we have two projects, one of which has the other as dependency, and has a logger available. The other project wants to log whatever it does using a logger injected (provided) by the first project.
On the code injecting the logger:
Inject our logger on Dependency::Logger, which is the module used by Dependency
for logging:
InjectedLogger.inject mylogger, on: Dependency::LoggerInject our logger on whatever is identified by 'dependency-logger':
InjectedLogger.inject mylogger, on: 'dependency-logger'Inject our logger on 'dependency-logger', and have it provide :debug, :info
and :invented log levels, with whatever of those being actually unsupported by
mylogger emulated with :info:
InjectedLogger.inject mylogger, levels: [:debug, :info, :invented], fallback: :info, on: 'dependency-logger'Inject our logger on Dependency::Logger and prefix the messages with '[logger-for-dep]':
InjectedLogger.inject mylogger, prefix: '[logger-for-dep]', on: Dependency::LoggerYou can also avoid depending on InjectedLogger if you call the inject method
directly on the class/module where your dependency declares the logger:
Dependency::Logger.inject mylogger, prefix: '[logger-for-dep]'On the code where you want a logger injected:
This sets up a module with a logger method identified as 'dependency-logger'
and declaring requirements of :debug, :info, and :invented log levels. In
case no logger gets injected by the time logger is needed, the standard Ruby
logger with output on STDERR will be used. After a logger is finally available,
this also makes sure the prefix for each message is '[dependency]' (overriding
what the injector set up):
module Dependency
module Logger
InjectedLogger.use :debug, :info, :invented, as: 'dependency-logger' do
# this gets executed if no logger has been injected at use time
require 'logger'
{ logger: Logger.new(STDERR) } # optionally add parameters for `inject`
end
InjectedLogger.after_injection on: 'dependency-logger' do |logger|
logger.prefix = '[dependency]'
end
end
endNow you can use your module elsewhere in your project:
class WantsLogging
include Dependency::Logger
def some_method_needing_logging
logger.info 'some info'
# logger blocks are also supported
logger.invented do
find_answer_to_ultimate_question_of life, universe and ObjectSpace.each_object
'using the invented log level is computationally expensive so ' \
'I pass this computation as a block to avoid computing it in ' \
'case the logger filters this level'
end
end
endIf you write this inside Dependency::Logger, you will get a mylogger method in
Dependency::Logger requiring the :debug and :info levels and falling back
to the Ruby logger, identified for injection with Dependency::Logger:
InjectedLogger.use :debug, :info, method_name: :mylogger do
require 'logger'
{ logger: Logger.new(STDERR)
endYou can also force the definition of the method elsewhere:
InjectedLogger.use :debug, :info, method_name: :mylogger, on: Dependency::OtherLogger do
[...]
endIf you omit the block, InjectedLogger will provide a default logger (note that
we are forced to use the :on parameter if we have no block).
InjectedLogger.use :debug, :info, on: selfNote that you do not need to specify the :on parameter for InjectedLogger.use
nor InjectedLogger.after_injection IFF you provide a block to those methods
and want to imply on: self.
You can also get the logger invoking it directly on your module:
SomeOtherGem.logger = Dependency::Logger.loggeror... :)
OtherDependency.inject Dependency::Logger.logger, prefix: '[other-dependency]'Generating the gem
Both bundler and rspec are required to build the gem:
$ gem install bundler rspec
Run rake -T to see available tasks. The gem can be built with:
$ rake build
Or, if you want to make sure everything works correctly:
$ bundle exec rake build
Installation
After generating the gem, install it using:
$ gem install pkg/injectedlogger-*.gem