Short version: How can I get the full command-line process info from 'top' while retaining the ability to redirect STDERR?

Longer Tale of Woe...

I've been working on a script that does some long-term monitoring of the health of a Linux box on one of our customer sites. (So that when we get a bug report that says "the system was really slow for a while last Tuesday after lunch", we'll have some data to look at).

The following 'top' command generates everything that I want to know about the "health" of the Linux box overall as well as the individual processes that we care to monitor:

top -bcS -n 1 -b batch mode (non-interactive) -n <num> iteration count -S cumulative CPU for dead children -c display full command line

Given,

lll.pl: sub longestLineLength { my $longestLen = undef; for my $l ( @_ ) { if ( length($l) > $longestLen ) { $longestLen = length($l); } } return $longestLen; } test-01.pl: #!/usr/bin/perl require "lll.pl"; open (TOP, "/usr/bin/top -bcS -n 1 |") || die "open pipe from top failed $!"; print longestLineLength( <TOP> ) . "\n"; $ ./test-01.pl 80
...Hmm, it looks like `top` is trying to outsmart me because it knows that my terminal is only 80 characters wide (truncating the full command line that I requested with (-c)).

Alright, I can fool it:

Externally:

$ COLUMNS=1000 ./test-01.pl 552

OR Internally test-02.pl:

open (TOP, "COLUMNS=1000 /usr/bin/top -bcS -n 1 |") OR open (TOP, "/usr/bin/env -i COLUMNS=1000 /usr/bin/top -bcS -n 1 |" +)

And all is well:

$ ./test-02.pl 552

BUT as soon as I redirect STDERR, it fails....

$ ./test-02.pl 2>err 81
...once again 'top' is truncating all my command lines!

How can redirecting STDERR possibly relate to terminal width? I don't know, but it behaves the same whether the STDERR re-direct is externally (in the shell as above), or internally (in the perl script below):

test-03.pl: open (TOP, "/usr/bin/env -i COLUMNS=1000 /usr/bin/top -bcS -n 1 2> +err.txt |") $ ./test-03.pl 81
...It doesn't seem to matter whether the destination of STDERR is a real file or /dev/null, the behavior is the same: truncated lines

so next I tried some funky stuff that I learned from 'perlopentut'...

test-04.pl:

#!/usr/bin/perl require "lll.pl"; my $outFileName = shift @ARGV; my $errFileName = $outFileName . ".err"; open( STDOUT, ">> $outFileName" ) || die "failed to redirect STDOUT to '$outFileName': $!"; open( STDERR, ">> $errFileName" ) || die "failed to redirect STDERR to '$errFileName': $!"; open (TOP, "/usr/bin/env -i COLUMNS=1000 /usr/bin/top -bcS -n 1 |" +) || die "open pipe from top failed $!"; print longestLineLength( <TOP> ) . "\n"; $ ./test-04.pl output $ cat output 81
...same result: any attempt at capturing STDERR results in trimmed lines! It doesn't seem to matter whether I use open() or IO::File, the result is exactly the same.

By definition this script is a long-running process, I NEED to capture STDERR somehow, so that I can watch for the error conditions, 'warn's, etc.

I'm at the end of my rope, my next step is to re-write it and replace all occurances of 'warn', 'die', etc. with my own versions that write to a private file-handle (not STDERR). But in addition to being nasty, that's a problem because I'll be losing any STDERR output that is emitted by child processes ('top', etc)).


Relevant Details

$ perl -v This is perl, v5.6.1 built for i386-linux $ type -a top top is /usr/bin/top $ rpm -qf /usr/bin/top procps-2.0.7-11 $ ls -l /bin/sh ... /bin/sh -> bash $ rpm -qf /bin/bash /bin/sh bash-2.05-8 bash-2.05-8 $ uname -a Linux ahost 2.4.9-e.40enterprise #1 SMP Thu Apr 8 16:43:01 EDT 2004 i6 +86 unknown (actually it's RedHat Enterprise Linux 2.1, w/ recent patches)

Apology

Pardon me for asking what might be a Linux question, but I'm hoping that the perl gurus will know of a away that I can work-around it with perl!


In reply to top and STDERR hell... by DouglasDD

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.