Logging in Ruby

Here’s the translation of the Go logging example to Ruby, formatted in Markdown suitable for Hugo:

Ruby provides several ways to handle logging, including the built-in Logger class and third-party gems for more advanced logging features. In this example, we’ll demonstrate logging using Ruby’s standard library.

require 'logger'
require 'json'
require 'stringio'

# Simply using the Logger class with default settings
logger = Logger.new(STDOUT)
logger.info("standard logger")

# Customizing the logger format
logger.formatter = proc do |severity, datetime, progname, msg|
  "#{datetime.strftime('%Y-%m-%d %H:%M:%S.%L')} [#{severity}] #{msg}\n"
end
logger.info("with microseconds")

# Adding the filename and line number to the log output
logger.formatter = proc do |severity, datetime, progname, msg|
  file, line = caller[4].split(':')
  "#{datetime.strftime('%Y-%m-%d %H:%M:%S')} #{File.basename(file)}:#{line}: [#{severity}] #{msg}\n"
end
logger.info("with file/line")

# Creating a custom logger with a prefix
my_logger = Logger.new(STDOUT)
my_logger.progname = "my"
my_logger.info("from my_logger")

# Changing the prefix of an existing logger
my_logger.progname = "ohmy"
my_logger.info("from my_logger")

# Using a custom output target (StringIO in this case)
buffer = StringIO.new
buf_logger = Logger.new(buffer)
buf_logger.progname = "buf"
buf_logger.info("hello")

# Print the contents of the buffer
puts "from buf_logger: #{buffer.string}"

# Structured logging using JSON
class JSONFormatter < Logger::Formatter
  def call(severity, time, progname, msg)
    JSON.generate({
      time: time.iso8601(6),
      level: severity,
      msg: msg
    }) + "\n"
  end
end

json_logger = Logger.new(STDOUT)
json_logger.formatter = JSONFormatter.new
json_logger.info("hi there")

# Adding key-value pairs to structured logs
json_logger.info("hello again") { {key: "val", age: 25} }

This Ruby code demonstrates various logging techniques:

  1. Using the standard Logger class with default settings.
  2. Customizing the log format to include microseconds.
  3. Including file name and line number in log messages.
  4. Creating custom loggers with prefixes.
  5. Using custom output targets (StringIO in this case).
  6. Implementing structured logging with JSON output.

When you run this script, you’ll see output similar to the following:

2023-08-22 10:45:16 INFO: standard logger
2023-08-22 10:45:16.904 [INFO] with microseconds
2023-08-22 10:45:16 example.rb:22: [INFO] with file/line
my: from my_logger
ohmy: from my_logger
from buf_logger: buf: hello

{"time":"2023-08-22T10:45:16.904166Z","level":"INFO","msg":"hi there"}
{"time":"2023-08-22T10:45:16.904178Z","level":"INFO","msg":"hello again","key":"val","age":25}

Note that the exact timestamp will depend on when you run the script.

Ruby’s Logger class provides a flexible way to handle logging in your applications. For more advanced logging features or specific formatting requirements, you might want to consider using third-party logging gems available in the Ruby ecosystem.