Tuna has asked for the wisdom of the Perl Monks concerning the following question:

I wrote this little utility because I run a process on several servers that create a ton of data. I unfortunately need to share my partition with another group, who also runs process that write data to the disk. So, as part 1 of my "process management scheme", I want to be notified when disk space reaches 50%, at which point I can transfer some data off of that server. I am planning on running this as a cron job, on an hourly basis.

My question is, how can I do this without opening and closing my output file so many times?
The (cough) code:
#!/usr/local/bin/perl -w use strict; use Sys::Hostname; my ($fs, $kbytes, $used, $avail, $cap, $mount); my $line; my $host = hostname(); my $date = `date +%Y%m%d%H`; my $outfile = "/export/home/steve/disk_log.$host.$date"; my $sendmail ='/usr/lib/sendmail -t '; my $mailhdr = "To: steve\@foo.com\n". "Subject: Disk usage alarm - $host - $date\n====================== +================================\n\n"; open (OUTFILE, ">$outfile") || die "Can't open $outfile: $!\n"; print OUTFILE $mailhdr; close (OUTFILE); open (OUTFILE, ">>$outfile") || die "Can't open $outfile: $!\n"; my $cmd = `df -k /usr >> $outfile`; close (OUTFILE); open (OUTFILE, "$outfile") || die "Can't open $outfile: $!\n"; while ($line = <OUTFILE>) { chomp $line; next unless ($line =~ /^\//); ($fs, $kbytes, $used, $avail, $cap, $mount) = split(' ', $line); $cap =~ s/\%//; } close (OUTFILE); if ($cap >= 50) { system( "$sendmail < $outfile") == 0 or die "Can't Mail: $!\n"; } else { exit; }
May the laughter commence.......

Replies are listed 'Best First'.
Re (tilly) 1: Partition monitor, aka, I told you it was ugly
by tilly (Archbishop) on Mar 02, 2001 at 03:08 UTC
    Several suggestions, in approximate order of how important I think they are.

    I recommend Mail::Send for handling mail.

    Or in a cron, if the cron is propery configured, any cron which prints will generate email to an appropriate list.

    Also note that it is generally good to avoid hardcoding user names in code like this. If you can make it a group name, that would be good...

    And finally, for running a process that you need to send data to, rather than writing a file and then using system, open on a pipe and write to that pipe.

(jeffa) Re: Partition monitor, aka, I told you it was ugly
by jeffa (Bishop) on Mar 02, 2001 at 04:44 UTC
    use strict; use Mail::Send; use Sys::Hostname; my $MAX = 50; my $dir = shift || '/usr'; my $to = 'foo@bar.com'; my $body; open(DF, "df -k $dir | ") or die; $body .= $_ while <DF>; my ($perc) = $body =~ /(\d+)%/; close DF; exit if $perc < $MAX; my $msg = new Mail::Send Subject => 'df alarm', To => $to; my $fh = $msg->open; print $fh "Disk uskagage for $dir on ", hostname(), "\n"; print $fh $body; $fh->close;

    I played around with Filesys::DiskSpace, but it does not return the percentage left. I decided to open a pipe to the 'df' command instead of doing the math. Besides, this is Perl, not C. :)

    Jeff

    R-R-R--R-R-R--R-R-R--R-R-R--R-R-R--
    L-L--L-L--L-L--L-L--L-L--L-L--L-L--
    
Re: Partition monitor, aka, I told you it was ugly
by archon (Monk) on Mar 02, 2001 at 03:08 UTC
    If you are closing the OUTFILE handle each time to flush the buffer, then the answer is:
    select OUTFILE; $|=1; select STDOUT;

    Then you only have to open/close it once to read and once to write. You can print to it or read from it as many times as you want in between.

    Since you are both reading and writing to it, you might want to use IPC::Open2. This module lets you read and write to the same handle. See its manpage for caveats.

    You might also want to check into the Mail::Send module for sending mail without using system. In addition, you can avoid the system calls to `date` and `hostname` if you use the POSIX.pm strftime function and the Sys::Hostname module. These methods are more portable than your current implementation.

Re: Partition monitor, aka, I told you it was ugly
by chipmunk (Parson) on Mar 02, 2001 at 04:21 UTC
    There's no need to open $outfile for appending as you do, because you're doing the actual append in `df -k /usr >> $outfile`.

    But instead of writing to $outfile, why not just build up the message in memory, and then open a pipe to sendmail? (Or, better yet, use a module to send the mail.)

Re: Partition monitor, aka, I told you it was ugly
by BlueLines (Hermit) on Mar 02, 2001 at 04:55 UTC
    I've used Big Brother for almost 3 years to do monitoring of systems. It's a neat program, and I highly reccomend it. However, it's written in C and sh. So i've been porting it to perl. Right now i've finished the client portion, and here's the sub i use for disk space monitoring. It may or may not be helpful to you, but what the hell...
    sub DISK { my @df = `df`; my $red = '95'; my $yellow = '90'; my $color = "green"; my $message; #get rid of the header from df(1) shift @df; #strip off leading whitespace foreach my $lines (@df) { my $warning; $lines =~s/^\s+//; my ($device,$usage) =($lines =~m|(/dev/\S+)\s+\d+\s+\d+\s+\d+\s+(\ +d+)|); if ($usage >= $red) { $color = "red"; $warning = "Warning"; } elsif ($usage >= $yellow) { $color = "yellow" unless ($color eq "red"); $warning = "Caution"; } if (defined $warning) { $message .= "$warning: $device is at $usage% usage.\n"; } } unless (defined $message) { $message .= "All filesystems ok.\n"; } foreach (@df) { $message .= $_ ; } }


    BlueLines

    Disclaimer: This post may contain inaccurate information, be habit forming, cause atomic warfare between peaceful countries, speed up male pattern baldness, interfere with your cable reception, exile you from certain third world countries, ruin your marriage, and generally spoil your day. No batteries included, no strings attached, your mileage may vary.
      You should take a look at spong and netsaint; two really snazzy monitors written in perl.

      a