Standart output written in ~/.xsession-errors

Hi all.

If I launch an application using ruby/gtk via the console, the standart
output is written on the console. If the same application is launch via
gui, the standart output is written on ~/.xsession-errors when the
application exists.
I need to prevent that. Is there a way ? Is it not a bug ?

Vincent

PS: application tests on Ubuntu.

#!/usr/bin/env ruby

encoding: UTF-8

require ‘gtk2’

b=Gtk::Button.new(‘Foo’)
b.signal_connect(‘clicked’){puts ‘FOO’}
w=Gtk::Window.new
w.add(b)
w.show_all
w.signal_connect(“delete_event”){Gtk.main_quit}

Gtk.main

puts() writes to stdout. So the output will be sent to wherever stdout
is
redirected. When you say “console”, I guess you mean from something
like gnome-terminal. If you run an application from gnome-terminal,
stdout is redirected there. It seems that gdm redirects it to
.xession-errors.
gnome-panel is a child process of gdm and doesn’t bother to
redirect stdout (and it’s not clear to me that it should, since I don’t
know
where it would go…) so if you start an app from the menu, or the
panel the output goes to wherever gdm set it.

Again, I’m not quite sure where you are expecting the output to go.
Remember that there isn’t one “console” in un*x. Each process
has a stdout file handle (and stderr). As a user you can redirect
that anywhere you want. For example, if you don’t like stdout
being redirected to .xsession-errors you can set up gdm to
send it somewhere else (even to an application that will display
it on the screen).

I hope that helps

      MikeC

Thanks for you reply.

You have confirm my doubts that “gnome” redirect the standard output.
Users of my application complain about ~/.xsession-errors being filled
with my application outputs.
Other applications do not seem to write on ~/.xsession-errors.

The behaviour I would implement is:

  • if launched “graphically”, set $stdout and $stderr to /dev/null,
  • if launched by terminal app, keep $stdout and $stderr.

Can I do that ?

Vincent

On Sat, Feb 27, 2010 at 4:27 PM, Vincent C. <
[email protected]> wrote:

Thanks for you reply.

You have confirm my doubts that “gnome” redirect the standard output.
Users of my application complain about ~/.xsession-errors being filled
with my application outputs.
Other applications do not seem to write on ~/.xsession-errors.

Actually, any application launched that is parented by your window
manager
that prints to stdout/stderr would typically write to
~/.xsession-errors.
It’s quite common. This happens in many setups, not just GNOME (for
instance, I use openbox as my window manager, and I get plenty of stuff
in
my ~/.xsession-errors.

The behaviour I would implement is:

  • if launched “graphically”, set $stdout and $stderr to /dev/null,
  • if launched by terminal app, keep $stdout and $stderr.

Can I do that ?

Yes that is possible. In Ruby, there is IO::reopen, and can be used on
$stdout and $stderr. You could open a log file, then call
$stdout.reopen(your_log_file_io). I’m not sure how to detect if you
were
launched from a terminal though. I’m thinking of a complicated process
involving checking parent pids, but there’s probably an easier way.

dave

Dave F. wrote:

Actually, any application launched that is parented by your window
manager
that prints to stdout/stderr would typically write to
~/.xsession-errors.
It’s quite common. This happens in many setups, not just GNOME (for
instance, I use openbox as my window manager, and I get plenty of stuff
in
my ~/.xsession-errors.

There is only debug and error infos in mine!

The behaviour I would implement is:

  • if launched “graphically”, set $stdout and $stderr to /dev/null,
  • if launched by terminal app, keep $stdout and $stderr.

Can I do that ?

Yes that is possible. In Ruby, there is IO::reopen, and can be used on
$stdout and $stderr. You could open a log file, then call
$stdout.reopen(your_log_file_io). I’m not sure how to detect if you
were
launched from a terminal though. I’m thinking of a complicated process
involving checking parent pids, but there’s probably an easier way.

dave

I know the IO::reopen method but thanks for pointing it. It is
detection part that I was wondering about. Maybe someboby knows an easy
way !

Vincent

Wahoo. That is a big explanation. Thanks very much for your efforts.

I currently have a --quiet option (it uses IO::reopen). I was thinking
of implementing a --debug option to increase the number of infos
displayed.

First, I will try to had the quiet option on .desktop file.
Then, I will think about implemented quiet as default and two verbose
option (verbose end very verbose).

It seems that you think the second option better.
In that case, can I use IO::reopen by default? (It is easyer than
looking for all the puts in the code. The verbose option will “inhebit”
IO::reopen.)
Or should I modify all lines where puts is used ?

Vincs

On 28 February 2010 01:27, Vincent C.
[email protected] wrote:

Other applications do not seem to write on ~/.xsession-errors.

The point is that the other applications aren’t writing to STDOUT.
That’s why you don’t see output. I’ve written a lot about why
you don’t want to do what you think you want to do. But
it’s possible you would rather not read that. If so, I’ve written
a solution that should work and not break other people’s
expectation of your app. You can skip down to see it.
Otherwise…

I’m not sure that you’re understanding how it works. Every application
has a default file handle for STDOUT and STDERR. Where these
are sent is not (and should not) be determined by the application.
It is up to the user to determine where those should go. Redirecting
STDOUT or STDERR breaks your application. The one exception
is when you definitely don’t want to write to one of the file handles
(for example a daemon) in which case you should close the file
handle (this allows the shell to detach more easily).

When you run an application, STDOUT and STDERR are attached
to your TTY (or PTS in the case of an xterm, etc) by default, but
you can redirect the output anywhere you want (in bash you use
the > or 2> redirectors). This is important in case the user wants
to parse output that you have. You can not know how the user
will launch the application or what they want to do with the output.
Deciding for them reduces their ability to use your application
integrated with their own solution. That’s why I said it’s broken.

The problem you are running into is that the X server is (by default)
running on TTY7. So output from the X server will go to TTY7.
But you can’t really see TTY7 because you have an X display there.
GDM (the Gnome Display Manager) will redirect the output to a file
so you can see it. Now because I haven’t looked at it I don’t know
who exactly is redirecting STDOUT to .xsession-errors – but it’s
probably GDM. GDM then starts the X server and a whole host
of other stuff including your window manager, gnome-session,
gnome-panel, etc, etc. But each of these processes inherits its
STDOUT from it’s parent (for the sake of argument, we’ll call it
GDM, but I haven’t looked at the exact startup mechanism of
GNOME). Since STDOUT is redirected to .xsession-errors in
the parent process, it is in each of the child processes too.

So when you run an application “from the GUI” STDOUT is
set up as .xsession-errors – for all applications.
When you run gnome-terminal (or xterm or whatever) it creates
a new PTS (sort of like a pseudo TTY) and sets STDOUT to
that PTS. That’s why applications run from a terminal window
have their output printed there. You definitely do not what to
change that behaviour from your application. It breaks what
normal people think your app should be doing.

SKIP TO HERE FOR THE SOLUTION

It is quite possible that you have debug information
or whatever that you don’t want to output when the application
is normally launched. The most common way to do this is
simply to have a flag (say, “-debug”) that turns on printing
of the information. That way when someone types
“theAPP -debug” they get the information and when the type
“theAPP” they get nothing.

Sometimes you don’t want to (or can’t) do that for some reason.
In this case you can simply redirect STDIO or STERR when the
application is invoked from the GUI. In GNOME the menus, etc,
are populated by .desktop files.

If you look in /usr/share/applications and
/usr/share/app-install/desktop
you can see these files. Make one for your application and in
the Exec line redirect the output to /dev/null. Honestly I don’t know
much about these things. But this would be the best place to redirect
the output.

Hope that helps,
MikeC

Mathieu B. wrote:

I guess you’re mostly interested in the Linux case

Indeed but thanks for the windows tip.

VIncs

I guess you’re mostly interested in the Linux case but in Windows, you
can check whether the program was started from the command prompt or
not like this.

begin
open(“CONIN$”) {}
open(“CONOUT$”, “w”) {}
HAVE_CONSOLE = true
rescue SystemCallError
HAVE_CONSOLE = false
end

I needed that for my app because printing to stdout when running a
program with rubyw raises an exception.

Mathieu

PS: Very instructive post, Mike!