Ruby, Can You Speak Louder?

Ruby has some ways to turn on debug mode, which library authors can use to print out extra information for interested users. But unfortunately, there are multiple debug modes in Ruby. When to use which one?

Consider you have this code:

def production_method
  puts "I am doing the right thing part 1"
  # @a is really intereting here
  puts "I am doing the right thing part 2"
end

We could query the global $DEBUG variable, which can be toggled when starting the Ruby interpreter:

def production_method
  puts "I am doing the right thing part 1"
  $stderr.puts "@a is now: #{@a}" if $DEBUG
  puts "I am doing the right thing part 2"
end

But is this the best way? It also could have been:

$stderr.puts "@a is now: #{@a}" if $VERBOSE

Or:

$stderr.puts "@a is now: #{@a}" if Library.debug_mode?

And what about:

warn "@a is now: #{@a}"

Ruby is a little idiosyncratic here. There is no standard way to signalize "I want to have more information". Ruby has two global debug modes: debug mode and verbosity mode and both behave differently. Within Ruby, the current debug mode state can be queried from two global variables:

Global Debug State

This table shows the different modes both of them can have:

Variable Value CLI-Variable Mirrors¹ Meaning
$DEBUG true $-d == true Debug mode active
$DEBUG false² $-d == false Debug mode inactive
$VERBOSE true $-v == true
$-w == true
$-W == 2
Verbosity mode active
$VERBOSE false² $-v == false
$-w == false
$-W == 1
Medium verbosity mode
$VERBOSE nil $-v == nil
$-w == nil
$-W == 0
Silent verbosity mode

¹ Will be set automatically
² Default

Note that the Verbosity mode is different for $VERBOSE == false and $VERBOSE == nil.

Another side note: While it is possible to change $DEBUG to an arbitrary value, this is not true for $VERBOSE - If you assign it a trueish value, it will just be set to true.

What follows is a list of command line options that have an effects on the debug modes:

Command Line Options for Debug Modes

Option Alias Effects
-W2 -W, -w Sets $VERBOSE to true
-W1   Nothing ($VERBOSE remains false)
-W0   Sets $VERBOSE to nil
--verbose   Sets $VERBOSE to true
Also quits Ruby if no arguments given
-v   Sets $VERBOSE to true
Also Prints Ruby version
Also quits Ruby if no arguments given
--debug -d Sets $DEBUG to true
Sets $VERBOSE to true

A funny thing to note is that -v is a shortcut for --version as well as it is one for --verbose.

Effect of Debug Modes on Interpreter

Verbosity

$VERBOSE Effect
true or false (but not nil) Kernel#warn will output to STDERR
true Interpreter level 1 warnings will be printed, for example, duplicated hash keys
true Interpreter level 2 warnings will be printed, for example, method redefinition

Debug Mode

$DEBUG Effect
true Extended exception reporting will be turned on. See this blog post for an example. It will also turn on Thread.abort_on_exception

Best Practice

Use neither $VERBOSE, nor $DEBUG, but use custom logging, for example standard library's logger or some other logging gem. It is easier to understand than relying on the global debug modes.

Use $VERBOSE = true if you are interested in level 2 interpreter warnings.

Use $DEBUG = true if you want to turn on extended exception reporting or enable Thread.abort_on_exception.

Further Reading

More Idiosyncratic Ruby