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.
So something like this should do the trick:
begin
$stderr = File.open(‘/dev/null’, ‘w’)
ThirdPartyLib::call_some_annoying_function
ensure
$stderr = STDERR
end
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.
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?
-Mark
···
On Fri, Sep 19, 2003 at 12:49:43AM +0900, Michael Garriss wrote:
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:
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?
···
–
The only thing that Babelfish is good at is proving that Vogons are
great poets.
Josef ‘Jupp’ Schugt in japan.anime.evangelion
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
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
···
On Fri, Sep 19, 2003 at 12:49:43AM +0900, Michael Garriss wrote:
Definitely not. It will just create a file in the current directory
named “NUL”.
There are no magic filenames on *N?X. There are, however, special
files which refer to hardware devices rather than disk storage. These
can be named anything, since it’s not the name that matters but
the file attributes, but there is a standard set of such files
in /dev on all systems. One of these is /dev/null, which points
to the “null device”, which is not a real piece of hardware but a
virtual device that just discards everything written to it.
Another popular virtual device is /dev/zero, which will happily output
zero bytes as long as you care to continue reading from it.
In any case, we came up with much the same solution, differing only
in the filenames for the null device. The StringIO solution
seems like a better choice for cross-platform compatibility, however.
-Mark
···
On Thu, Sep 18, 2003 at 05:28:31PM +0100, Alan Davies wrote:
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.
Assign something open? I don’t understand. I get a syntax error on
that assignment:
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)
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.
On Fri, Sep 19, 2003 at 02:18:35AM +0900, Michael Garriss wrote:
Mark J. Reed wrote:
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.
Assign something open? I don’t understand. I get a syntax error on
that assignment:
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.
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.
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).
···
–
The only thing that Babelfish is good at is proving that Vogons are
great poets.
Josef ‘Jupp’ Schugt in japan.anime.evangelion
“Rudolf Polzer” denshimeiru-sapmctacher@durchnull.de schrieb im
Newsbeitrag
news:slrnbmloi3.bll.denshimeiru-sapmctacher@message-id.durchnull.ath.cx…
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.
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.
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.
write() to a closed FD fails, but most libs ignore the error. If
they don’t, however, it needs to be reopened to something like
/dev/null which isn’t possible in a platform-independent manner.
···
–
The only thing that Babelfish is good at is proving that Vogons are
great poets.
Josef ‘Jupp’ Schugt in japan.anime.evangelion