Skip to content

Log errors to a file, warnings to stderr #19

@rtanglao

Description

@rtanglao

The following is from a google search for how to log errors in ruby without rails to a file and log warnings to stderr?

Explanation

  • Logger.new(STDERR): This sets the default output destination for $logger to the standard error stream.
  • $logger.level = Logger::WARN: This ensures only messages with a severity level of WARN or higher (i.e., WARN, ERROR, FATAL) are processed by $logger.
  • $error_logger = Logger.new(error_log_file): A separate Logger instance is created specifically for ERROR and FATAL messages, sending them to the errors.log file.
  • Helper Method log(level, message): This method directs the log message to the appropriate logger based on the severity level.

After running the script, the errors.log file will contain the error and fatal messages, while the warning message will appear in your terminal's stderr output.

  • gem install multi_io
ruby code
require 'logger'
require 'multi_io'

# 1. Open the file for error logs
error_log_file = File.open('errors.log', File::WRONLY | File::APPEND | File::CREAT)

# 2. Create the primary logger instance
# By default, this logger sends everything to STDOUT (or whichever IO object you provide initially).
# We will adjust its output for errors later.
$logger = Logger.new(STDOUT)

# 3. Configure a custom formatter if needed
$logger.formatter = proc do |severity, datetime, progname, msg|
  "#{datetime.strftime('%Y-%m-%d %H:%M:%S')} [#{severity}] #{msg}\n"
end

# 4. Define the outputs using multi_io
# Errors will go to both stderr and the file for simplicity, but only the file will save them persistently.
# We use a custom method or condition to manage this behavior.

# A simple approach without multi_io:

# Configure the main logger to output all warnings to STDERR
$logger.level = Logger::WARN
$logger.instance_variable_set(:@logdev, Logger::LogDevice.new(STDERR))

# Create a separate, dedicated logger for ERROR level and higher that writes to the file
$error_logger = Logger.new(error_log_file)
$error_logger.level = Logger::ERROR
$error_logger.formatter = $logger.formatter # Use the same formatter

# Define a helper method to handle different levels
def log(level, message)
  case level
  when :error, :fatal
    $error_logger.add(Logger.const_get(level.to_s.upcase), message)
  when :warn, :info, :debug
    $logger.add(Logger.const_get(level.to_s.upcase), message)
  else
    $logger.info(message)
  end
end

puts "Logger configured. Running tests..."

log(:info, "This is an informational message (goes to STDOUT - but our level is WARN+ so it is suppressed)")
log(:warn, "This is a warning (goes to STDERR)")
log(:error, "This is an error (goes to errors.log)")
log(:fatal, "This is a fatal error (goes to errors.log)")

# 5. Ensure the file is closed when the script exits
at_exit { error_log_file.close }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions