Logger

Ruby has built-in Logger. You can log to standard output:

require "logger"

logger = Logger.new($stdout)
logger.debug("logs level 0")
logger.info("logs level 1")
logger.warn("logs level 2")
logger.error("logs level 3")
logger.fatal("logs level 4")

# also takes block

logger.info { "INFO logs level 1" }

which will output something like this to $stdout:

D, [2022-05-28T09:16:26.957525 #44700] DEBUG -- : logs level 0
I, [2022-05-28T09:16:33.589977 #44700]  INFO -- : logs level 1
W, [2022-05-28T09:16:58.642355 #44700]  WARN -- : logs level 2
E, [2022-05-28T09:17:01.487036 #44700] ERROR -- : logs level 3
F, [2022-05-28T09:17:03.578646 #44700] FATAL -- : logs level 4

A log line has log level indicator DIWEF which stands for DEBUG, INFO, WARN, ERROR, FATAL respectively. A local timestamp (bad, you should customize to use UTC), a Process ID #44700 follows by log level and -- :, then your log message!

# log/ folder need to exist first
logger = Logger.new("log/something.log")

logger.level = Logger::ERROR

You can customize your logger using Logger::Formatter or any object responds to call (Proc, Lambda). For example, customize a logger that use UTC timestamp and prints extra thread ID:

class MyFormatter < ::Logger::Formatter
  def call(severity, time, _program, message)
    "#{time.utc.iso8601(9)} pid=#{::Process.pid} tid=#{::Thread.current.object_id} #{severity}: #{message}\n"
  end
end
logger = Logger.new($stdout)
logger.formatter = MyFormatter.new
logger.info("hello, world!")
# => 2022-05-28T00:28:41.629943000Z pid=44700 tid=8120 INFO: hello, world!

Popular logging gem is Lograge.

By sending logs to Linux’s special file /dev/null:

Logger.new("/dev/null")

Rails application defaults to DEBUG log level, you can change it to something higher than DEBUG to silent logs, take Sidekiq as an example:

Sidekiq.logger.level = Logger::ERROR

You can create a logger that sends logs to StringIO then read from the IO object:

io = StringIO.new
logger = Logger.new(io)

logger.info "1"
logger.info "2"

puts io.string

will print:

I, [2022-05-28T09:31:25.877328 #44700]  INFO -- : 1
I, [2022-05-28T09:31:27.908248 #44700]  INFO -- : 2

Don’t forget to clean up the StringIO object afterwards:

io.truncate(0)
io.rewind