CrackedRuby logo

CrackedRuby

Debug Gem Configuration

Overview

The debug gem provides interactive debugging capabilities for Ruby applications through configurable breakpoints, remote debugging, and session management. Ruby integrates debug gem configuration through environment variables, configuration files, and runtime settings that control debugging behavior, output formatting, and connection parameters.

The primary configuration interface centers around the RUBY_DEBUG_* environment variables and the .rdbgrc configuration file. The debug gem reads these settings during initialization to establish debugging sessions, configure output streams, and set up remote debugging connections.

# Basic debug gem initialization with configuration
require 'debug'

# Configuration is read automatically on require
# Environment variables take precedence over config files
binding.b  # Creates breakpoint with current configuration

Debug configuration affects several core components: the debugger protocol handler, output formatters, breakpoint managers, and remote connection handlers. Each component reads specific configuration parameters during startup and runtime.

# Configuration impacts multiple debugging aspects
ENV['RUBY_DEBUG_PORT'] = '12345'
ENV['RUBY_DEBUG_HOST'] = '0.0.0.0'
ENV['RUBY_DEBUG_OPEN'] = 'true'

require 'debug/open'  # Respects configuration settings

The debug gem configuration system supports both global settings that affect all debugging sessions and per-session settings that can be modified during debugging. Configuration validation occurs during gem initialization, with invalid settings generating warnings rather than errors.

# Configuration validation example
ENV['RUBY_DEBUG_LOG_LEVEL'] = 'invalid_level'
require 'debug'
# Warning: invalid log level, using 'warn' instead

Basic Usage

Debug gem configuration begins with environment variables that control fundamental debugging behavior. The RUBY_DEBUG environment variable serves as the primary activation switch, accepting boolean values or specific debugging modes.

# Enable debugging globally
ENV['RUBY_DEBUG'] = '1'
require 'debug'

# Program execution pauses at first binding.b
puts "Application starting"
binding.b  # Debugger activates here
puts "Application continuing"

The .rdbgrc configuration file provides persistent settings across debugging sessions. Ruby searches for this file in the current directory, home directory, and system-wide locations, applying settings in order of precedence.

# .rdbgrc configuration file example
# Set default log level
set log-level info

# Configure output formatting
set show-src-lines 10
set show-frames 5

# Set up remote debugging
set port 12345
set host localhost

Port and host configuration enables remote debugging scenarios where the debugger runs on a different machine or container. The debug gem validates network settings and establishes connections based on these parameters.

# Remote debugging configuration
ENV['RUBY_DEBUG_PORT'] = '9001'
ENV['RUBY_DEBUG_HOST'] = '192.168.1.100'
ENV['RUBY_DEBUG_SOCK_PATH'] = '/tmp/ruby-debug.sock'

require 'debug/open_nonstop'  # Opens remote session immediately

Log level configuration controls debugging output verbosity, affecting both console output and log file generation. Valid levels include fatal, error, warn, info, and debug, with each level including messages from higher severity levels.

# Configure logging output
ENV['RUBY_DEBUG_LOG_LEVEL'] = 'debug'
ENV['RUBY_DEBUG_LOG_FILE'] = '/var/log/ruby-debug.log'

require 'debug'
# All debugging operations generate detailed logs

Advanced Usage

Complex debugging scenarios require sophisticated configuration patterns that combine multiple settings and conditional activation. Environment-based configuration allows different debugging behavior across development, testing, and staging environments.

# Environment-specific debug configuration
class DebugConfig
  def self.setup
    case ENV['RAILS_ENV']
    when 'development'
      ENV['RUBY_DEBUG'] = '1'
      ENV['RUBY_DEBUG_LOG_LEVEL'] = 'debug'
      ENV['RUBY_DEBUG_SHOW_SRC_LINES'] = '15'
    when 'test'
      ENV['RUBY_DEBUG'] = '0'  # Disable interactive debugging
      ENV['RUBY_DEBUG_LOG_LEVEL'] = 'error'
    when 'staging'
      ENV['RUBY_DEBUG_PORT'] = '9229'
      ENV['RUBY_DEBUG_HOST'] = '0.0.0.0'
      ENV['RUBY_DEBUG_OPEN'] = 'true'
    end
  end
end

DebugConfig.setup
require 'debug'

Configuration inheritance and override patterns enable modular debugging setups where base configurations are extended for specific scenarios. The debug gem respects configuration layering with environment variables taking precedence over configuration files.

# Hierarchical configuration setup
module DebugSetup
  BASE_CONFIG = {
    'RUBY_DEBUG_LOG_LEVEL' => 'info',
    'RUBY_DEBUG_SHOW_FRAMES' => '10',
    'RUBY_DEBUG_SHOW_SRC_LINES' => '5'
  }

  REMOTE_CONFIG = BASE_CONFIG.merge({
    'RUBY_DEBUG_PORT' => '12345',
    'RUBY_DEBUG_HOST' => 'localhost',
    'RUBY_DEBUG_OPEN' => 'true'
  })

  def self.apply_config(config_hash)
    config_hash.each { |key, value| ENV[key] = value }
    require 'debug/start'
  end
end

# Apply remote debugging configuration
DebugSetup.apply_config(DebugSetup::REMOTE_CONFIG)

Dynamic configuration modification during runtime allows debugging behavior adjustment without restarting applications. The debug gem provides configuration commands that modify settings within active debugging sessions.

# Runtime configuration modification
require 'debug'

def configure_debug_session
  binding.b
  # Within debug session:
  # config set show-src-lines 20
  # config set log-level debug  
  # config list  # Show current configuration
end

# Configuration persists for session duration
configure_debug_session

Multi-process debugging configuration requires coordination between parent and child processes to avoid port conflicts and ensure proper debugging session management.

# Multi-process debug configuration
class MultiProcessDebug
  def self.configure_fork_debugging
    parent_port = ENV['RUBY_DEBUG_PORT']&.to_i || 12345
    
    # Configure parent process
    ENV['RUBY_DEBUG_PORT'] = parent_port.to_s
    ENV['RUBY_DEBUG_OPEN'] = 'true'
    
    require 'debug'
    
    # Fork with different debug port
    pid = fork do
      ENV['RUBY_DEBUG_PORT'] = (parent_port + 1).to_s
      require 'debug/start'
      
      # Child process debugging code
      binding.b
      puts "Child process: #{Process.pid}"
    end
    
    # Parent continues with original configuration
    binding.b
    puts "Parent process: #{Process.pid}"
    Process.wait(pid)
  end
end

Error Handling & Debugging

Debug gem configuration errors manifest in various forms, from invalid parameter values to network connection failures. The debug gem implements defensive configuration parsing that continues operation with fallback values when encountering invalid settings.

# Configuration error handling patterns
module DebugErrorHandling
  def self.validate_and_configure
    begin
      # Invalid port configuration
      ENV['RUBY_DEBUG_PORT'] = 'invalid_port'
      require 'debug/open'
    rescue ArgumentError => e
      warn "Debug configuration error: #{e.message}"
      # Falls back to default port 12345
      ENV['RUBY_DEBUG_PORT'] = '12345'
      require 'debug/open'
    end
  end
  
  def self.handle_connection_failures
    ENV['RUBY_DEBUG_HOST'] = '192.168.999.999'  # Invalid IP
    ENV['RUBY_DEBUG_PORT'] = '9001'
    
    begin
      require 'debug/open'
    rescue Errno::ECONNREFUSED, SocketError => e
      puts "Remote debugging unavailable: #{e.message}"
      # Switch to local debugging
      ENV.delete('RUBY_DEBUG_HOST')
      ENV.delete('RUBY_DEBUG_PORT')
      require 'debug'
    end
  end
end

Configuration file parsing errors require special handling since the debug gem reads .rdbgrc files during initialization. Syntax errors or invalid commands in configuration files generate warnings but do not prevent debugging session startup.

# Configuration file error detection
class RdbgrcValidator
  def self.validate_config_file(path)
    return unless File.exist?(path)
    
    invalid_lines = []
    File.readlines(path).each_with_index do |line, index|
      line = line.strip
      next if line.empty? || line.start_with?('#')
      
      unless valid_config_line?(line)
        invalid_lines << "Line #{index + 1}: #{line}"
      end
    end
    
    unless invalid_lines.empty?
      warn "Invalid .rdbgrc configuration:"
      invalid_lines.each { |line| warn "  #{line}" }
    end
  end
  
  private
  
  def self.valid_config_line?(line)
    # Basic validation for common configuration commands
    line.match?(/^set\s+\w+/) || line.match?(/^source\s+/)
  end
end

# Validate before loading debug gem
RdbgrcValidator.validate_config_file('.rdbgrc')
require 'debug'

Network debugging configuration failures often occur in containerized or networked environments where specified hosts or ports become unavailable. Implementing fallback mechanisms ensures debugging capabilities remain functional despite network issues.

# Network fallback configuration
module NetworkDebugFallback
  FALLBACK_PORTS = [12345, 12346, 12347, 12348, 12349]
  
  def self.configure_with_fallback
    FALLBACK_PORTS.each do |port|
      ENV['RUBY_DEBUG_PORT'] = port.to_s
      
      begin
        require 'debug/open'
        puts "Debug server started on port #{port}"
        return true
      rescue Errno::EADDRINUSE
        puts "Port #{port} in use, trying next port"
        next
      rescue => e
        puts "Failed to start debug server on port #{port}: #{e.message}"
        next
      end
    end
    
    warn "All fallback ports failed, switching to local debugging"
    ENV.delete('RUBY_DEBUG_PORT')
    ENV.delete('RUBY_DEBUG_HOST')
    require 'debug'
    false
  end
end

Production Patterns

Production debugging configuration requires careful balance between debugging capabilities and security concerns. Debug gem settings in production environments should minimize performance impact while providing necessary troubleshooting functionality.

# Production-safe debug configuration
class ProductionDebugConfig
  def self.setup
    return unless production_debugging_enabled?
    
    # Restrict debugging to specific conditions
    ENV['RUBY_DEBUG'] = '1' if emergency_debugging?
    ENV['RUBY_DEBUG_LOG_LEVEL'] = 'error'
    ENV['RUBY_DEBUG_LOG_FILE'] = '/var/log/app/debug.log'
    
    # Secure remote debugging configuration
    if remote_debugging_required?
      ENV['RUBY_DEBUG_HOST'] = '127.0.0.1'  # Localhost only
      ENV['RUBY_DEBUG_PORT'] = secure_port.to_s
      ENV['RUBY_DEBUG_SOCK_PATH'] = '/tmp/ruby-debug-prod.sock'
    end
    
    require 'debug'
  end
  
  private
  
  def self.production_debugging_enabled?
    ENV['ENABLE_PRODUCTION_DEBUG'] == 'true'
  end
  
  def self.emergency_debugging?
    File.exist?('/tmp/emergency_debug')
  end
  
  def self.remote_debugging_required?
    ENV['REMOTE_DEBUG_SESSION'] == 'active'
  end
  
  def self.secure_port
    # Use application-specific port range
    base_port = 20000
    base_port + (Process.pid % 1000)
  end
end

Docker and container debugging configuration requires special consideration for network interfaces and volume mounting to ensure debugging sessions remain accessible from host systems.

# Container debugging configuration
class ContainerDebugSetup
  def self.configure_for_docker
    # Configure for container networking
    ENV['RUBY_DEBUG_HOST'] = '0.0.0.0'  # Accept external connections
    ENV['RUBY_DEBUG_PORT'] = ENV['DEBUG_PORT'] || '9229'
    
    # Use volume-mounted socket for IPC debugging
    socket_path = ENV['DEBUG_SOCKET_PATH'] || '/debug/ruby-debug.sock'
    ENV['RUBY_DEBUG_SOCK_PATH'] = socket_path
    
    # Ensure socket directory exists
    FileUtils.mkdir_p(File.dirname(socket_path))
    
    # Configure logging for container output
    ENV['RUBY_DEBUG_LOG_LEVEL'] = ENV['DEBUG_LOG_LEVEL'] || 'info'
    ENV['RUBY_DEBUG_LOG_FILE'] = '/proc/1/fd/1'  # Container stdout
    
    require 'debug/open_nonstop'
  end
  
  def self.health_check
    # Verify debugging endpoint accessibility
    host = ENV['RUBY_DEBUG_HOST']
    port = ENV['RUBY_DEBUG_PORT']
    
    return false unless host && port
    
    begin
      socket = TCPSocket.new(host, port.to_i)
      socket.close
      true
    rescue
      false
    end
  end
end

Load balancer and proxy configuration for debug sessions requires coordination with infrastructure components to ensure debugging traffic reaches the correct application instances.

# Load balancer debug configuration
module LoadBalancerDebugConfig
  def self.setup_with_instance_routing
    instance_id = ENV['INSTANCE_ID'] || Socket.gethostname
    base_port = ENV['BASE_DEBUG_PORT']&.to_i || 9200
    
    # Calculate instance-specific debug port
    instance_hash = instance_id.hash.abs
    debug_port = base_port + (instance_hash % 100)
    
    ENV['RUBY_DEBUG_PORT'] = debug_port.to_s
    ENV['RUBY_DEBUG_HOST'] = '0.0.0.0'
    
    # Register debug endpoint with service discovery
    register_debug_endpoint(instance_id, debug_port)
    
    require 'debug/open'
  end
  
  def self.register_debug_endpoint(instance_id, port)
    # Register with load balancer or service mesh
    registration_data = {
      service: 'ruby-debug',
      instance: instance_id,
      port: port,
      health_check: "/debug/health"
    }
    
    # Implementation depends on service discovery system
    puts "Debug endpoint: #{instance_id}:#{port}"
  end
end

Common Pitfalls

Debug gem configuration creates several categories of common mistakes that can compromise debugging effectiveness or application security. Port conflicts represent one of the most frequent configuration issues, particularly in development environments running multiple applications.

# Port conflict resolution
class DebugPortManager
  @used_ports = Set.new
  
  def self.allocate_port(preferred_port = nil)
    preferred_port ||= 12345
    
    # Check if preferred port is available
    if preferred_port && !port_in_use?(preferred_port)
      @used_ports.add(preferred_port)
      return preferred_port
    end
    
    # Find next available port
    (12345..12355).each do |port|
      unless port_in_use?(port)
        @used_ports.add(port)
        return port
      end
    end
    
    raise "No available debug ports in range"
  end
  
  def self.port_in_use?(port)
    begin
      server = TCPServer.new('localhost', port)
      server.close
      false
    rescue Errno::EADDRINUSE
      true
    end
  end
end

# Safe port allocation
debug_port = DebugPortManager.allocate_port
ENV['RUBY_DEBUG_PORT'] = debug_port.to_s
require 'debug/open'

Configuration file precedence confusion occurs when developers expect certain settings to take effect but environment variables override configuration file values. Understanding precedence order prevents debugging session misconfigurations.

# Configuration precedence demonstration
class ConfigPrecedenceIssue
  def self.demonstrate_problem
    # Create .rdbgrc with specific settings
    File.write('.rdbgrc', <<~CONFIG)
      set log-level debug
      set port 9001
      set show-src-lines 20
    CONFIG
    
    # Environment variables override file settings
    ENV['RUBY_DEBUG_LOG_LEVEL'] = 'error'  # Overrides 'debug' from file
    ENV['RUBY_DEBUG_PORT'] = '9002'        # Overrides '9001' from file
    # show-src-lines uses file setting (no env var override)
    
    require 'debug'
    
    # Result: log-level=error, port=9002, show-src-lines=20
    puts "Effective configuration may differ from .rdbgrc"
  end
  
  def self.show_effective_config
    # Display actual configuration being used
    config_sources = {
      log_level: ENV['RUBY_DEBUG_LOG_LEVEL'] || 'from .rdbgrc',
      port: ENV['RUBY_DEBUG_PORT'] || 'from .rdbgrc',
      src_lines: ENV['RUBY_DEBUG_SHOW_SRC_LINES'] || 'from .rdbgrc'
    }
    
    puts "Effective debug configuration:"
    config_sources.each { |key, value| puts "  #{key}: #{value}" }
  end
end

Security vulnerabilities in production debug configuration often stem from overly permissive network settings or inadequate access controls. Debug interfaces exposed to public networks create significant security risks.

# Security anti-patterns and corrections
module DebugSecurityPitfalls
  # DANGEROUS: Exposes debug interface to all networks
  def self.insecure_configuration
    ENV['RUBY_DEBUG_HOST'] = '0.0.0.0'
    ENV['RUBY_DEBUG_PORT'] = '12345'
    ENV['RUBY_DEBUG_OPEN'] = 'true'
    # This allows anyone to connect and debug the application
  end
  
  # SECURE: Restricts debug interface appropriately
  def self.secure_configuration
    # Only bind to localhost in production
    if ENV['RAILS_ENV'] == 'production'
      ENV['RUBY_DEBUG_HOST'] = '127.0.0.1'
      
      # Use Unix socket instead of network port
      ENV['RUBY_DEBUG_SOCK_PATH'] = '/tmp/ruby-debug-secure.sock'
      File.chmod(0600, '/tmp/ruby-debug-secure.sock') if File.exist?('/tmp/ruby-debug-secure.sock')
      
      # Require authentication token
      ENV['RUBY_DEBUG_AUTH_TOKEN'] = SecureRandom.hex(32)
    end
  end
  
  def self.validate_production_safety
    if ENV['RAILS_ENV'] == 'production'
      dangerous_settings = []
      
      dangerous_settings << "Host set to 0.0.0.0" if ENV['RUBY_DEBUG_HOST'] == '0.0.0.0'
      dangerous_settings << "No authentication configured" unless ENV['RUBY_DEBUG_AUTH_TOKEN']
      dangerous_settings << "Using network port in production" if ENV['RUBY_DEBUG_PORT'] && !ENV['RUBY_DEBUG_SOCK_PATH']
      
      unless dangerous_settings.empty?
        warn "SECURITY WARNING: Dangerous debug configuration detected:"
        dangerous_settings.each { |warning| warn "  - #{warning}" }
      end
    end
  end
end

Memory leaks from debug session configuration occur when debugging remains enabled in long-running processes or when debug sessions accumulate without proper cleanup.

# Memory leak prevention in debug configuration
class DebugMemoryManagement
  def self.configure_with_cleanup
    # Set memory limits for debug sessions
    ENV['RUBY_DEBUG_MAX_SESSIONS'] = '3'
    ENV['RUBY_DEBUG_SESSION_TIMEOUT'] = '3600'  # 1 hour
    
    # Configure automatic cleanup
    at_exit do
      cleanup_debug_resources
    end
    
    # Trap signals to ensure cleanup
    Signal.trap('TERM') do
      cleanup_debug_resources
      exit(0)
    end
    
    require 'debug'
  end
  
  def self.cleanup_debug_resources
    # Close any open debug sessions
    ObjectSpace.each_object(TCPServer) do |server|
      server.close if server.addr[1] == ENV['RUBY_DEBUG_PORT']&.to_i
    rescue
      # Ignore cleanup errors
    end
    
    # Remove debug socket files
    socket_path = ENV['RUBY_DEBUG_SOCK_PATH']
    File.unlink(socket_path) if socket_path && File.exist?(socket_path)
  end
end

Reference

Environment Variables

Variable Type Default Description
RUBY_DEBUG Boolean/String false Enables debug gem functionality
RUBY_DEBUG_PORT Integer 12345 Network port for remote debugging
RUBY_DEBUG_HOST String localhost Host interface for remote debugging
RUBY_DEBUG_SOCK_PATH String None Unix socket path for IPC debugging
RUBY_DEBUG_LOG_LEVEL String warn Logging verbosity level
RUBY_DEBUG_LOG_FILE String None Log file path for debug output
RUBY_DEBUG_OPEN Boolean false Auto-open debug session on startup
RUBY_DEBUG_SHOW_SRC_LINES Integer 10 Source code lines to display
RUBY_DEBUG_SHOW_FRAMES Integer 2 Stack frame count to display
RUBY_DEBUG_USE_SHORT_PATH Boolean false Show shortened file paths
RUBY_DEBUG_NO_COLOR Boolean false Disable color output
RUBY_DEBUG_NO_SIGINT_HOOK Boolean false Disable SIGINT handling
RUBY_DEBUG_INIT_SCRIPT String None Initialization script path
RUBY_DEBUG_HISTORY_FILE String ~/.rdbg_history Command history file
RUBY_DEBUG_SAVE_HISTORY Boolean true Save command history

Configuration File Commands

Command Parameters Description
set log-level LEVEL fatal, error, warn, info, debug Set logging verbosity
set port NUMBER Integer (1024-65535) Set remote debugging port
set host ADDRESS IP address or hostname Set remote debugging host
set show-src-lines NUMBER Integer (1-100) Set source line display count
set show-frames NUMBER Integer (1-50) Set stack frame display count
set use-short-path BOOL true, false Enable shortened path display
set no-color BOOL true, false Disable color output
set save-history BOOL true, false Enable command history saving
source FILE File path Load additional configuration file

Require Variants

Require Statement Behavior
require 'debug' Load debug gem with standard configuration
require 'debug/start' Initialize debug gem and start session
require 'debug/open' Open remote debugging immediately
require 'debug/open_nonstop' Open remote debugging without stopping execution
require 'debug/prelude' Load debug gem early in boot process

Log Levels

Level Numeric Value Output Includes
fatal 4 Fatal errors only
error 3 Fatal and error messages
warn 2 Fatal, error, and warning messages
info 1 Fatal, error, warning, and info messages
debug 0 All messages including debug output

Configuration Precedence

  1. Environment variables (highest priority)
  2. .rdbgrc in current directory
  3. .rdbgrc in home directory
  4. System-wide configuration files
  5. Default gem settings (lowest priority)

Common Port Ranges

Range Purpose
12345-12355 Default debug gem ports
9229-9239 Node.js inspector compatible ports
20000-21000 Production debug port range
30000-31000 Container debug port range

Socket File Locations

Path Usage
/tmp/ruby-debug.sock Development debugging
/var/run/ruby-debug.sock System service debugging
/debug/ruby-debug.sock Container volume debugging
~/.ruby-debug.sock User-specific debugging