logger
Small, easy-to-use, and extensible Dart/Flutter logging package inspired by Android logger that prints beautiful logs. Supports trace, debug, info, warning, error, and fatal levels. Shows logs at or above configured level in debug mode, omits all logs in release mode.
Library
Logger (Standard Library)
Overview
Logger (Standard Library) is Ruby's built-in logging functionality that provides simple and reliable logging solutions without external dependencies. It supports log level control, file rotation, and custom formatters, catering to basic logging requirements for small-scale Ruby applications and scripts. The library offers detailed output control through five log levels (DEBUG, INFO, WARN, ERROR, FATAL) and identification functionality through program name specification, making it an accessible starting point for Ruby logging needs.
Details
Ruby's standard Logger maintains practical value for small-scale projects and learning purposes in 2025. Available immediately without external gem dependencies, it includes built-in log rotation functionality for both size-based and time-based rotation. Custom formatter definition enables flexible output format customization, covering basic log management features like date/time format specification, program name settings, and multiple output destinations. While sufficient for simple requirements, migration to more feature-rich libraries is recommended for serious web applications and Rails projects.
Key Features
- Standard Library: Immediately available without external dependencies
- Five Log Levels: Detailed control through DEBUG, INFO, WARN, ERROR, FATAL
- Log Rotation: Support for both size-based and time-based rotation
- Custom Formatters: Flexible output format customization via Proc
- Multiple Outputs: Support for files, STDOUT, and IO streams
- Program Name Setting: Log entry identification functionality
Pros and Cons
Pros
- Zero-setup environment with immediate availability without external dependencies
- Long-term support and stability guaranteed as Ruby standard library
- Built-in log rotation functionality for both size-based and time-based rotation
- Flexible output control through Proc-based custom formatters
- Simultaneous output to multiple destinations (files, STDOUT, streams)
- Low learning curve requiring only basic Ruby concepts for understanding
Cons
- Insufficient support for modern log formats like structured logging and JSON output
- Functional limitations in high-performance requirements and multi-process environments
- Feature insufficiency for serious web applications
- Lack of log level-specific output destination distribution and advanced filtering
- No integration features with third-party services
- Insufficient support for enterprise-level audit and security requirements
Reference Pages
Usage Examples
Installation and Setup
# Logger is part of standard library, available with require only
require 'logger'
# Basic logger creation (STDOUT output)
logger = Logger.new(STDOUT)
# File output logger
logger = Logger.new('application.log')
# IO stream specification
logger = Logger.new($stdout)
# Logger with program name
logger = Logger.new(STDOUT, progname: 'MyApp')
# Version check
puts "Ruby Version: #{RUBY_VERSION}"
puts "Logger available: #{defined?(Logger) ? 'Yes' : 'No'}"
Basic Logging with Different Levels
require 'logger'
# Basic logger setup
logger = Logger.new(STDOUT)
logger.level = Logger::DEBUG
# Message output with five log levels
logger.debug("Debug info: detailed execution trace")
logger.info("Info: application started")
logger.warn("Warning: deprecated method usage")
logger.error("Error: problem occurred during processing")
logger.fatal("Fatal: system-stopping level problem")
# Output control through log level setting
logger.level = Logger::WARN
logger.debug("This message will not be output")
logger.info("This message will also not be output")
logger.warn("This message will be output")
# Logging with program name
logger.progname = 'UserService'
logger.info("User authentication process started")
# Block-style logging (lazy evaluation)
logger.debug { "Heavy processing result: #{expensive_calculation}" }
# Log level checking
logger.debug? && logger.debug("Debug level is enabled")
Log Level Control and Filtering
require 'logger'
# Basic log level setting
logger = Logger.new('application.log')
# Various log level setting methods
logger.level = Logger::INFO
logger.level = Logger::DEBUG
logger.level = Logger::WARN
logger.level = Logger::ERROR
logger.level = Logger::FATAL
# Numeric setting also possible
logger.level = 2 # Equivalent to Logger::WARN
# Log level setting from environment variables
log_level = ENV['RUBY_LOG_LEVEL'] || 'INFO'
logger.level = Logger.const_get(log_level)
# Log level checking methods
def log_with_level_check(logger)
logger.debug? && logger.debug("Debug level enabled")
logger.info? && logger.info("Info level enabled")
logger.warn? && logger.warn("Warning level enabled")
logger.error? && logger.error("Error level enabled")
logger.fatal? && logger.fatal("Fatal level enabled")
end
# Environment-specific log level settings
case ENV['RAILS_ENV']
when 'development'
logger.level = Logger::DEBUG
when 'test'
logger.level = Logger::WARN
when 'production'
logger.level = Logger::ERROR
else
logger.level = Logger::INFO
end
# Display current log level
puts "Current log level: #{logger.level}"
puts "Log level name: #{%w[DEBUG INFO WARN ERROR FATAL UNKNOWN][logger.level]}"
Log Rotation and Output Destination Management
require 'logger'
# Size-based rotation (3 files, 10MB limit)
logger = Logger.new('application.log', 3, 10485760)
# Time-based rotation (daily rotation)
logger = Logger.new('daily.log', 'daily')
logger = Logger.new('weekly.log', 'weekly')
logger = Logger.new('monthly.log', 'monthly')
# Multiple output destination management class
class MultiLogger
def initialize(*loggers)
@loggers = loggers
end
def info(message)
@loggers.each { |logger| logger.info(message) }
end
def error(message)
@loggers.each { |logger| logger.error(message) }
end
def warn(message)
@loggers.each { |logger| logger.warn(message) }
end
end
# Multiple logger usage example
file_logger = Logger.new('application.log')
console_logger = Logger.new(STDOUT)
error_logger = Logger.new('error.log')
multi_logger = MultiLogger.new(file_logger, console_logger)
multi_logger.info("Message output to all loggers")
# Conditional log rotation
class ConditionalRotationLogger
def initialize(filename, max_size = 1048576) # 1MB
@filename = filename
@max_size = max_size
@logger = create_logger
end
def rotate_if_needed
if File.exist?(@filename) && File.size(@filename) > @max_size
backup_name = "#{@filename}.#{Time.now.strftime('%Y%m%d_%H%M%S')}"
File.rename(@filename, backup_name)
@logger = create_logger
end
end
def info(message)
rotate_if_needed
@logger.info(message)
end
private
def create_logger
Logger.new(@filename)
end
end
# Usage example
rotating_logger = ConditionalRotationLogger.new('app.log')
rotating_logger.info("Rotation-aware log message")
Custom Formatters and Layout Configuration
require 'logger'
# Create custom formatter
logger = Logger.new(STDOUT)
# Simple custom formatter
logger.formatter = proc do |severity, datetime, progname, msg|
"#{datetime}: #{severity} - #{msg}\n"
end
# Detailed custom formatter
logger.formatter = proc do |severity, datetime, progname, msg|
date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
"[#{date_format}] #{severity.ljust(5)} #{progname}: #{msg}\n"
end
# JSON-style formatter
logger.formatter = proc do |severity, datetime, progname, msg|
{
timestamp: datetime.iso8601,
level: severity,
program: progname,
message: msg
}.to_json + "\n"
end
# Colored formatter (for terminal)
class ColorFormatter
COLORS = {
'DEBUG' => "\033[36m", # Cyan
'INFO' => "\033[32m", # Green
'WARN' => "\033[33m", # Yellow
'ERROR' => "\033[31m", # Red
'FATAL' => "\033[35m" # Magenta
}.freeze
RESET = "\033[0m".freeze
def call(severity, datetime, progname, msg)
color = COLORS[severity] || ''
"#{color}[#{datetime.strftime('%H:%M:%S')}] #{severity}: #{msg}#{RESET}\n"
end
end
logger.formatter = ColorFormatter.new
# Custom datetime format
logger.datetime_format = '%Y-%m-%d %H:%M:%S'
# Formatter with program name
logger.progname = 'MyApp'
logger.formatter = proc do |severity, datetime, progname, msg|
"[#{progname}] #{datetime.strftime('%H:%M:%S')} #{severity}: #{msg}\n"
end
# Log testing
logger.debug("Debug message")
logger.info("Info message")
logger.warn("Warning message")
logger.error("Error message")
Error Handling and Log Management
require 'logger'
# Safe logger creation function
def create_safe_logger(filename, level = Logger::INFO)
begin
logger = Logger.new(filename)
logger.level = level
logger.info("Log file initialization completed: #{filename}")
logger
rescue StandardError => e
fallback_logger = Logger.new(STDERR)
fallback_logger.error("Log file creation failed (#{filename}): #{e.message}")
fallback_logger
end
end
# Standard pattern for exception log output
def log_exception(logger, exception, context = '')
logger.error "#{context}Exception occurred: #{exception.class}: #{exception.message}"
logger.error "Backtrace:"
exception.backtrace.each { |line| logger.error " #{line}" }
end
# Exception handling by log level
class ApplicationLogger
def initialize(filename = 'application.log')
@logger = create_safe_logger(filename)
end
def log_with_exception_handling(level, message)
begin
@logger.send(level, message)
rescue StandardError => e
STDERR.puts "Log output error: #{e.message}"
end
end
def safe_info(message)
log_with_exception_handling(:info, message)
end
def safe_error(message)
log_with_exception_handling(:error, message)
end
def log_method_execution(method_name)
start_time = Time.now
@logger.debug("Method started: #{method_name}")
begin
result = yield
duration = Time.now - start_time
@logger.info("Method completed: #{method_name} (#{duration.round(3)} seconds)")
result
rescue StandardError => e
duration = Time.now - start_time
@logger.error("Method failed: #{method_name} (#{duration.round(3)} seconds)")
log_exception(@logger, e, "In #{method_name}: ")
raise
end
end
end
# Usage example
app_logger = ApplicationLogger.new
begin
app_logger.log_method_execution('data_processing') do
# Some processing
raise "Test exception" if rand(2) == 0
"Processing completed"
end
rescue StandardError => e
app_logger.safe_error("Application-level exception catch: #{e.message}")
end
# Log file permission check
def check_log_permissions(filename)
logger = Logger.new(STDERR)
begin
test_logger = Logger.new(filename)
test_logger.info("Permission test")
test_logger.close
logger.info("Log file permissions OK: #{filename}")
true
rescue StandardError => e
logger.error("Log file permission error (#{filename}): #{e.message}")
false
end
end
# System information logging
def log_system_info(logger)
logger.info("Ruby Version: #{RUBY_VERSION}")
logger.info("Platform: #{RUBY_PLATFORM}")
logger.info("Process ID: #{Process.pid}")
logger.info("Logger Level: #{logger.level}")
end
# Execution example
system_logger = create_safe_logger('system.log')
log_system_info(system_logger)
Practical Application Integration
require 'logger'
require 'fileutils'
# Application logger class
class ApplicationLogger
DEFAULT_LOG_DIR = 'log'.freeze
DEFAULT_LOG_LEVEL = Logger::INFO
def initialize(app_name, log_dir = DEFAULT_LOG_DIR)
@app_name = app_name
@log_dir = log_dir
ensure_log_directory
@logger = create_logger
setup_formatter
log_startup_info
end
def debug(message); @logger.debug(format_message(message)); end
def info(message); @logger.info(format_message(message)); end
def warn(message); @logger.warn(format_message(message)); end
def error(message); @logger.error(format_message(message)); end
def fatal(message); @logger.fatal(format_message(message)); end
def log_performance(operation_name)
start_time = Time.now
info("Started: #{operation_name}")
begin
result = yield
duration = Time.now - start_time
info("Completed: #{operation_name} (#{duration.round(3)} seconds)")
result
rescue StandardError => e
duration = Time.now - start_time
error("Failed: #{operation_name} (#{duration.round(3)} seconds): #{e.message}")
raise
end
end
def close
info("Logging system shutdown")
@logger.close if @logger.respond_to?(:close)
end
private
def ensure_log_directory
FileUtils.mkdir_p(@log_dir) unless Dir.exist?(@log_dir)
end
def create_logger
log_file = File.join(@log_dir, "#{@app_name}.log")
Logger.new(log_file, 'daily')
end
def setup_formatter
@logger.formatter = proc do |severity, datetime, progname, msg|
"[#{datetime.strftime('%Y-%m-%d %H:%M:%S')}] #{severity.ljust(5)} [#{@app_name}] #{msg}\n"
end
end
def format_message(message)
"[PID:#{Process.pid}] #{message}"
end
def log_startup_info
info("=== #{@app_name} Started ===")
info("Ruby Version: #{RUBY_VERSION}")
info("Log Level: #{@logger.level}")
info("Log File: #{@log_dir}/#{@app_name}.log")
end
end
# Configuration management class
class LogConfig
def self.setup_from_env
{
level: log_level_from_env,
app_name: ENV['APP_NAME'] || 'MyApp',
log_dir: ENV['LOG_DIR'] || 'log'
}
end
def self.log_level_from_env
level_name = ENV['LOG_LEVEL'] || 'INFO'
Logger.const_get(level_name.upcase)
rescue NameError
Logger::INFO
end
end
# Usage example
begin
config = LogConfig.setup_from_env
logger = ApplicationLogger.new(config[:app_name], config[:log_dir])
logger.info("Configuration loaded successfully")
# Actual application processing
logger.log_performance('database_initialization') do
sleep(0.1) # Instead of actual initialization process
"DB connection completed"
end
logger.log_performance('user_data_processing') do
# Some processing
100.times do |i|
logger.debug("Processing: #{i+1}/100") if (i+1) % 10 == 0
end
"Processing completed"
end
ensure
logger&.close
end
# Singleton logger pattern
class GlobalLogger
@@instance = nil
def self.instance
@@instance ||= ApplicationLogger.new('global')
end
def self.method_missing(method, *args)
instance.send(method, *args)
end
end
# Global logger usage
GlobalLogger.info("Global logger message")
GlobalLogger.warn("Global warning")