2

I've built a Thor CLI app that uses a number of external gems. When I run it I get warning messages from those gems cluttering my output- how can I suppress this?

Clarification: I want to suppress the warning messages only, but still receive the standard output for my app, including errors and puts results.

For example, when I use these same gems in my Sinatra app, I don't get all the warning messages emanating from the gem code like I do with Thor.

EXAMPLE (Derived from http://willschenk.com/making-a-command-line-utility-with-gems-and-thor/)

require 'thor'
require 'safe_yaml'

module Socialinvestigator
  class HammerOfTheGods < Thor
    desc "hello NAME", "This will greet you"
    long_desc <<-HELLO_WORLD

    `hello NAME` will print out a message to the person of your choosing.

    HELLO_WORLD
    option :upcase
    def hello( name )
      greeting = "Hello, #{name}"
      greeting.upcase! if options[:upcase]
      puts greeting
    end
  end
end

In this case, because we're requiring the safe_yaml gem, every time we run a command we'll get the following warnings in our output:

/usr/local/lib/ruby/gems/2.3.0/gems/safe_yaml-1.0.4/lib/safe_yaml.rb:28: warning: method redefined; discarding old safe_load /usr/local/Cellar/ruby/2.3.0/lib/ruby/2.3.0/psych.rb:290: warning: previous definition of safe_load was here /usr/local/lib/ruby/gems/2.3.0/gems/safe_yaml-1.0.4/lib/safe_yaml.rb:52: warning: method redefined; discarding old load_file /usr/local/Cellar/ruby/2.3.0/lib/ruby/2.3.0/psych.rb:470: warning: previous definition of load_file was here

We're using a number of different gems and getting a whole array of warnings that are cluttering our output...

Yarin
  • 173,523
  • 149
  • 402
  • 512

3 Answers3

1

Firstly, you could potentially submit a Pull request and suppress the message in the dependency or raise an issue asking the gem developers to sort it out for you

Otherwise, this is something I have used before - It's probably from somewhere on SO (or the internet in general) but I can't remember where...

So you basically wrap the noisy method from the dependency with a silence method which simply pushes the STDOUT to a StringIO object and then back again to STDOUT...

require 'stringio'
def silence
  $stdout = temp_out = StringIO.new 
  yield
  temp_out.string
ensure
  $stdout = STDOUT
end

out = silence { run_dependency_method }
puts out # if in dev mode etc...
Ismail Moghul
  • 2,864
  • 2
  • 22
  • 28
  • Also see http://stackoverflow.com/questions/1496019/suppresing-output-to-console-with-ruby – Ismail Moghul Oct 13 '16 at 19:05
  • my bad I wasn't clear. I still need the standard output, I just don't want the warning messages coming out of the gems. See my edits above... – Yarin Oct 14 '16 at 16:18
1

Ruby has a global variable to define the verboseness of the output. nil means no warnings, false is the "normal" mode and true is extra verbose (adds some additional runtime information, equivalent to running ruby --verbose):

def without_warnings
  verboseness_level = $VERBOSE
  $VERBOSE = nil

  yield
ensure
  $VERBOSE = verboseness_level
end

# Doesn't show warnings about overwriting the constant
without_warnings do
  Foo = 42
  Foo = 'bar'
end

# Still shows normal output
without_warnings { puts 42 }

# Still shows and throws errors
without_warnings { raise 'wtf' }

If you have control over how the program is ran, you can instead use ruby's -W flag with respective values 0, 1 or 2 (in this case ruby -W 0).

ndnenkov
  • 35,425
  • 9
  • 72
  • 104
0

@Yarin,

Following up on @Ismail's answer, you could extend this solution by overloading the new "temporary" StringIO inside the silence method to filter out messages that contain the word "warning".

Here's an example:

require 'stringio'

class FooIO < StringIO
        def puts s
                super unless s.start_with? "WARN"
        end
end

def silence
  $stdout = temp_out = FooIO.new
  yield
  temp_out.string
ensure
  $stdout = STDOUT
end

def foo
        puts "INFO : Hello World!"
        puts "WARN : Oops.. This is a warning..."
        puts "ALRT : EVERYONE IS GOING TO DIE!!!"
end

out = silence { foo }

puts out
Eresse
  • 108
  • 1
  • 6