Professional Web Applications Themes

capture stderr - Ruby

I want to temporarily capture stderr output. Im on a freebsd box, so pipe should work. What am I doing wrong? -- Simon Strandgaard server> ruby x.rb Loaded suite TestCapture Started F Finished in 0.023457 seconds. 1) Failure: test_capture_stderr(TestCapture) [x.rb:31]: <"hello world"> expected but was <"">. 1 tests, 1 assertions, 1 failures, 0 errors server> cat x.rb require 'test/unit' class TestCapture < Test::Unit::TestCase def capture_stderr(&block) reader, writer = IO.pipe result = "" thread = Thread.new do loop do res = select([reader], nil, nil, nil)[0] if res.include?(reader) unless reader.eof result += reader.read end end end end old_stderr = $stderr.dup $stderr.reopen(writer) block.call ...

  1. #1

    Default capture stderr

    I want to temporarily capture stderr output.
    Im on a freebsd box, so pipe should work.

    What am I doing wrong?

    --
    Simon Strandgaard


    server> ruby x.rb
    Loaded suite TestCapture
    Started
    F
    Finished in 0.023457 seconds.

    1) Failure:
    test_capture_stderr(TestCapture) [x.rb:31]:
    <"hello world"> expected but was
    <"">.

    1 tests, 1 assertions, 1 failures, 0 errors
    server> cat x.rb
    require 'test/unit'

    class TestCapture < Test::Unit::TestCase
    def capture_stderr(&block)
    reader, writer = IO.pipe
    result = ""
    thread = Thread.new do
    loop do
    res = select([reader], nil, nil, nil)[0]
    if res.include?(reader)
    unless reader.eof
    result += reader.read
    end
    end
    end
    end
    old_stderr = $stderr.dup
    $stderr.reopen(writer)
    block.call
    $stderr.flush
    $stderr.reopen(old_stderr)
    thread.kill
    writer.close
    reader.close
    return result
    end
    def test_capture_stderr
    str = capture_stderr {
    $stderr.puts("hello world")
    }
    assert_equal("hello world", str)
    end
    end

    if $0 == __FILE__
    require 'test/unit/ui/console/testrunner'
    Test::Unit::UI::Console::TestRunner.run(TestCaptur e)
    end
    server>
    Simon Guest

  2. #2

    Default Re: capture stderr

    On Tue, 10 Feb 2004 12:14:39 +0100, Simon Strandgaard wrote:
     

    Forgot to do thread.join ... Now it works.

    BTW: Is there a platform independent way to capture
    $stderr output ?

    --
    Simon Strandgaard


    server> ruby x.rb
    Loaded suite TestCapture
    Started
    ..
    Finished in 0.004465 seconds.

    1 tests, 1 assertions, 0 failures, 0 errors
    server> cat x.rb
    require 'test/unit'

    class TestCapture < Test::Unit::TestCase
    def capture_stderr(&block)
    reader, writer = IO.pipe
    result = ""
    thread = Thread.new do
    fds = [reader]
    loop do
    res = select(fds, nil, nil, nil)[0]
    if res.include?(reader)
    if reader.eof
    thread.kill
    else
    result += reader.read
    end
    end
    end
    end
    old_stderr = $stderr.dup
    $stderr.reopen(writer)
    block.call
    $stderr.flush
    writer.close
    $stderr.reopen(old_stderr)
    thread.join
    reader.close
    return result
    end
    def test_capture_stderr
    str = capture_stderr {
    $stderr.puts("hello world")
    }
    assert_equal("hello world\n", str)
    end
    end

    if $0 == __FILE__
    require 'test/unit/ui/console/testrunner'
    Test::Unit::UI::Console::TestRunner.run(TestCaptur e)
    end
    server>
    Simon Guest

  3. #3

    Default Re: capture stderr


    On Tue, 10 Feb 2004 20:20:03 +0900
    In article <dk>
    [capture stderr]
    Simon Strandgaard <dk> wrote:
     

    No need to reopen. Just assign StringIO.


    require 'stringio'

    e = StringIO.new
    $stderr = e
    warn "hello"
    $stderr = STDERR

    p e.string # => "hello\n"


    --[ Tietew ]-------------------------------------------------------
    Mail: net / net
    Web : http://www.tietew.net/ (Tietew Windows Lab.)
    PGP fingerprint: 26CB 71BB B595 09C4 0153 81C4 773C 963A D51B 8CAA



    Tietew Guest

  4. #4

    Default Re: capture stderr

    On Tue, 10 Feb 2004 20:35:59 +0900, Tietew wrote: 
    >
    > No need to reopen. Just assign StringIO.
    >
    >
    > require 'stringio'
    >
    > e = StringIO.new
    > $stderr = e
    > warn "hello"
    > $stderr = STDERR
    >
    > p e.string # => "hello\n"
    >[/ref]

    Nice.. this indeed does the same job. Thanks.

    --
    Simon Strandgaard
    Simon Guest

  5. #5

    Default Re: capture stderr

    On Tue, 10 Feb 2004, Simon Strandgaard wrote:
     

    a pipe should work - but it's pretty tricky...
     

    * IO#read blocks until eof is read - your loop will only happen once and tries
    to read all data at once. if you really wanted to do something like that
    you'd need to do something like

    require 'io/nonblock' # i love this module

    buf = ''
    loop do
    select [r], nil, nil
    buf << r.nonblock{ r.read }
    end

    your 'read' blocks:

    ~/eg/ruby > cat a.rb
    r, w = IO.pipe
    t = Thread.new do
    puts 'selecting...'
    select [r], nil, nil
    p r.read
    end
    w.puts 42
    t.join
    puts 'never reached'

    ~/eg/ruby > ruby a.rb
    selecting...
    (hangs forever)


    in the end, i think you can accomplish this much more easily and portably:

    ~/eg/ruby > cat x.rb
    require 'test/unit'
    require 'stringio'

    class TestCapture < Test::Unit::TestCase
    def capture_stderr
    begin
    $stderr = StringIO.new
    yield
    $stderr.rewind && $stderr.read
    ensure
    $stderr = STDERR
    end
    end
    def test_capture_stderr
    str = capture_stderr { $stderr.puts("hello world") }
    assert_equal("hello world\n", str)
    $stderr.puts 'and $stderr still works...'
    end
    end

    ~/eg/ruby > ruby x.rb
    Loaded suite x
    Started
    and $stderr still works...
    Ara.T.Howard Guest

  6. #6

    Default Re: capture stderr

    On Tue, 10 Feb 2004 08:17:06 -0700, Ara.T.Howard wrote: 
    >
    > a pipe should work - but it's pretty tricky...[/ref]

    Yes I got the pipe working.. didn't you see my second mail? ;-)

     
    >
    > * IO#read blocks until eof is read - your loop will only happen once and tries
    > to read all data at once. if you really wanted to do something like that
    > you'd need to do something like
    >
    > require 'io/nonblock' # i love this module[/ref]

    I have not yet tried using this module module.. though I have experience
    with non-blocking io.


    [snip] 

    Thanks.. I had forgotten the 'ensure' statement!

    My code is now looking like:

    def capture_stderr(&block)
    e = StringIO.new
    $stderr = e
    block.call
    return e.string
    ensure
    $stderr = STDERR
    end


    --
    Simon Strandgaard

    Simon Guest

Similar Threads

  1. pseudo tty stderr capture problem.
    By Min Shei in forum UNIX Programming
    Replies: 0
    Last Post: July 15th, 11:07 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139