log_switch
https://github.com/turboladen/log_switch
Description
While developing other gems that needed a single class/singleton style logger, I got tired of repeating the code to create that logger and mix it in to my base class. I just wanted to require something, mix it in, and log:
MyThing.new.log "some message"
...and be able to switch that logging off programmatically:
MyThing.logging_enabled = false
This gem does that.
Synopsis
Basic use
include LogSwitch to give your class a class-level logger and an instance-level #log method.
Logging is off by default — turn it on explicitly:
require 'log_switch'
class MyThing
include LogSwitch
end
MyThing.logging_enabled = true
MyThing.new.log "I like you, Ruby."
# => D, [2026-07-15T12:46:30.206465 #66434] DEBUG -- : <MyThing> I like you, Ruby.
Switch it back off and calls become no-ops:
MyThing.logging_enabled = false
MyThing.new.log "You're my favorite." # => nothing is written
MyThing.logging_enabled = true # ...and back on, for the examples below
Note the class name is prepended to each message. That is on by default.
Log levels
The default level is :debug. Change it with default_log_level:
MyThing.default_log_level = :warn
MyThing.new.log "Crap!"
# => W, [2026-07-15T12:46:30.206563 #66434] WARN -- : <MyThing> Crap!
Or pass a level per call:
MyThing.new.log "Stuff!", :info
# => I, [2026-07-15T12:46:30.206499 #66434] INFO -- : <MyThing> Stuff!
The level is passed straight through to your Logger, so any method it responds to will do.
Using your own Logger
LogSwitch defaults to a Logger writing to STDOUT. Point it anywhere:
MyThing.logger = Logger.new('log.txt')
MyThing.new.log "hi!"
LogSwitch.logger sets the default for includers that have not set their own, and
LogSwitch.reset_config! puts things back to a fresh STDOUT logger.
Multi-line messages
Anything responding to #each_line is logged one line per call, so a multi-line message stays
readable:
MyThing.new.log "line one\nline two"
# => D, [...] DEBUG -- : <MyThing> line one
# => D, [...] DEBUG -- : <MyThing> line two
Objects that do not respond to #each_line (an Array, an Exception) are logged whole.
Hooks
Pass a block to #log and it runs before the message is written — handy for one-off setup:
require 'fileutils'
log_directory = File.('log')
MyThing.new.log("Thanks brah!") do
FileUtils.mkdir_p(log_directory)
end
For something that should run before every call, use before_log:
MyThing.before_log = proc { FileUtils.mkdir_p(log_directory) }
MyThing.new.log "Thanks brah!" # runs the hook, then logs
MyThing.new.log "I'm hungry..." # runs it again
Requirements
- Ruby >= 3.3. Tested on 3.3, 3.4 and 4.0 (see
.github/workflows/ci.yml). - Runtime dependency:
logger(no longer a default gem as of Ruby 4.0).
Install
gem install log_switch
Developers
After checking out the source:
bundle install
bundle exec rake # specs + RuboCop
Thanks
I need to thank the savon project for most of the code here.
Somehow I ran across how they do logging and started following suit. The code in log_switch is
almost identical to Savon's logging.