DEV Community

Cover image for Easy logging in your small ruby scripts/apps
Oinak
Oinak

Posted on

Easy logging in your small ruby scripts/apps

I have recently shared A configuration system for ruby CLIs.

If you are designing a new ruby application or script, it is very possible that you wnt to write some logs to now what things ar heppening (or did happen) during the execution.

If you are using a large framework like Ruby on Rails thin might be solved for you, see Rails.logger.

But if you are building a small script or app you might be missing the conveninence of being able to call logger.info from anywhewre.

To this effect, I have a small module that cover the mos basic needs:

module Loggable def self.included(base) base.extend ClassMethods end def logger = self.class.logger module ClassMethods def log_to(logger) = @logger = logger def logger = @logger ||= ::Logger.new($stdout) end end 
Enter fullscreen mode Exit fullscreen mode

You can include thi in any of your classes, and it gives you the essential interface.

class MyClass include Loggable def foo logger.info "This is an informative message" end end 
Enter fullscreen mode Exit fullscreen mode

and then if you run

MyClass.new.foo 
Enter fullscreen mode Exit fullscreen mode

You will see:

I, [2025-07-14T15:20:25.814143 #6137] INFO -- : This is an informative message 
Enter fullscreen mode Exit fullscreen mode

In the standard output.

You can check Ruby Logger docs to see the underlying options.

Additionally, you have a class-level log_to method that you can call like this:

log_to custom_logger 
Enter fullscreen mode Exit fullscreen mode

To set up any specialised behavior. One such example is suppresing logging in tests:

 # example using minitest/spec dsl let(:logger) do # ignore logger output except when testing it Object.new.tap do |o| def o.info(*); end def o.error(*); end end end before do MyClass.log_to(logger) end 
Enter fullscreen mode Exit fullscreen mode

This allows to inject a fake logger (or a double, or a mock or a spy...) without having Dependency Injection set up on every Logabble class initialize method.

If you know me you know I am very fond of tests, so of course here you have the test that goes with this module:

# minitest/spec DSL describe Loggable do let(:dummy_class) { Class.new { include Loggable } } describe '.included' do it 'extends ClassMethods' do expect(dummy_class.singleton_class.included_modules).must_include Loggable::ClassMethods end end describe '#logger' do it 'returns the class logger' do expect(dummy_class.new.logger).must_equal dummy_class.logger end end describe Loggable::ClassMethods do describe '.log_to' do it 'sets the logger device' do logger = Object.new dummy_class.log_to(logger) expect(dummy_class.logger).must_equal logger end end describe '.logger' do it 'defaults to a logger instance' do expect(dummy_class.logger).must_be_instance_of Logger end end end end 
Enter fullscreen mode Exit fullscreen mode

I hope this is useful to you at some point, if it is, or you have a much better way, please let me know in the comments.

Cover image by Robert Larsson

Top comments (0)