closing stderr

M

Michael Garriss

I would like to prevent some output that is going to stderr during a
call to a third party lib just during that call. My first guess was:

STDERR.close_write
ThirdPartyLib::call_some_annoying_function
STDERR.????

I guess you can see my problem. Can anyone give me a lead on this?

TIA,
Michael
 
R

Robert Klemme

Michael Garriss said:
I would like to prevent some output that is going to stderr during a
call to a third party lib just during that call. My first guess was:

STDERR.close_write
ThirdPartyLib::call_some_annoying_function
STDERR.????

I guess you can see my problem. Can anyone give me a lead on this?

TIA,
Michael

require 'StringIO'

oldStdErr = $stderr
oldSTDERR = STDERR

$stderr = StringIO.new
STDERR = $stderr

begin
# lib call
ensure
$stderr = oldStdErr
STDERR = oldSTDERR
end

robert
 
A

Alan Davies

Robert said:
require 'StringIO'

oldStdErr = $stderr
oldSTDERR = STDERR

$stderr = StringIO.new
STDERR = $stderr

begin
# lib call
ensure
$stderr = oldStdErr
STDERR = oldSTDERR
end

robert

I did it like this on windows recently:

oldStderr = $stderr.dup
$stderr.reopen("NUL", 'w')

<do stuff>

$stderr.reopen(oldStderr)

Not sure if NUL works on linix/unix
 
M

Michael Garriss

Mark said:
Note that you have to assign something open to $stderr before assigning
to STDERR, or else the assignment to STDERR throws an exception trying to
print the "already initialized constant" warning and the assignment
doesn't complete. There is probably a cleaner way of doing this.

Thanks to all who responded!

Assign something open? I don't understand. I get a syntax error on
that assignment:

bin/ruglyctl:132:in `require':
/usr/www/apache/rugly/lib/rdb_rugly.rb:40: dynamic constant assignment
(SyntaxError)
STDERR = $stderr
^ from bin/ruglyctl:132:in `handle_db_cmdtype'
from bin/ruglyctl:146

Regards,
Michael
 
M

Michael Garriss

Mark said:
What I mean is that this assignment:

STDERR = blah

Generates a warning:

warning: already initialized constant STDERR

And that warning message is sent to - where else - $stderr.
Which means if $stderr is still pointing to a closed File object
at the time you try to assign to STDERR, Ruby tries to send the
warning about the assignment, fails to do so because $stderr is
closed, and aborts the assignment.

(It seems odd that failure to emit a warning would itself be fatal
to the surrounding operation, but that's the behavior I'm seeing
on final 1.8.0)




Hm, I'm not sure what that means. Is this running in mod_ruby?

No, not running this code in mod_ruby. It seems that the problem is
that it's run from within a method. I guess I'm going to have to figure
out a way around that.

Michael
 
R

Robert Klemme

Newsbeitrag
Scripsit illa aut ille »Robert Klemme« said:
I would like to prevent some output that is going to stderr during a
call to a third party lib just during that call. My first guess was:

STDERR.close_write
ThirdPartyLib::call_some_annoying_function
STDERR.????

I guess you can see my problem. Can anyone give me a lead on this?
[...]
$stderr = StringIO.new
STDERR = $stderr

Are you sure it occupies file descriptor 2 (which external libraries
normally use)?

def without_stderr(&block)
save = $stderr.dup()
$stderr.close() # this will affect STDERR, too.
begin
yield
ensure
$stderr = save.dup()
# SIDE EFFECT: the file descriptor STDERR points to will be valid again
end
end

However, this routine assumes that all file descriptors before
$stderr are used. This is the case unless $stdin or $stdout have
been closed. Is there something like dup2() in Ruby?

This routine has a totally different problem: closing $stderr make the lib
function abort because it will get an exception on writing to $stderr.
$stderr has to be something that is open.

Regards

robert
 
R

Robert Klemme

Mark J. Reed said:
If the third-party library is a Ruby library and is well-behaved,
then you don't have to mess with STDERR; just change $stderr to
point to someplace else.

Remember: the global variable $stderr is where Ruby actually sends
standard error output. The constant STDERR is just a saved
copy of the value $stderr got when Ruby started up.

Ah, thanks for reminding me!
So something like this should do the trick:

begin
$stderr = File.open('/dev/null', 'w')
ThirdPartyLib::call_some_annoying_function
ensure
$stderr = STDERR
end

I typically prefer

$stderr = File.open('/dev/null', 'w')
begin
ThirdPartyLib::call_some_annoying_function
ensure
$stderr = STDERR
end

because if the resource assignment (File.open) fails with an exception, no
assignment takes place and thus $stderr = STDERR is superfluous. In this
simple example there is no functional and not much performance difference
but if the init and cleanup actions are more complex then it might indeed
be crucial to follow the pattern to do the init before the block.

Just as an additional note, this complete scheme might break in
multithreaded applications. You migh lose messages from other threads or
other strange things. That's the price of $globals...
If, on the other hand, the third-party library is not so well-behavied
and messes with STDERR directly, then you can close it. But you need to save
a copy of it first and restore it later.

begin
errCopy = ($stderr = STDERR).dup
STDERR.close
ThirdPartyLib::call_some_annoying_function
ensure
$stderr = errCopy
STDERR = $stderr
end

Note that you have to assign something open to $stderr before assigning
to STDERR, or else the assignment to STDERR throws an exception trying to
print the "already initialized constant" warning and the assignment
doesn't complete. There is probably a cleaner way of doing this.

(see above)
Question on the subject of well-behaved libraries: if you invoke
native code from Ruby, is that run with file descriptor 2 initially
matching $stderr?

Dunno.

Kind regards

robert
 
R

Robert Klemme

Newsbeitrag
Then use the StringIO trick from the other posting.

I thought about an external library which is an interface to an
existing C library which writes to stderr (file descriptor 2).

Even then one shouldt ensure that fd 2 is opened to something unless you
know that the external lib simply doesn't write to stderr if that is
closed.

Regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,129
Messages
2,570,770
Members
47,329
Latest member
FidelRauch

Latest Threads

Top