Re: Route emails in a perl script (461 Views)
Reply
Frequent Advisor
allanm77
Posts: 88
Registered: ‎06-27-2011
Message 1 of 11 (541 Views)

Route emails in a perl script

[ Edited ]

HI All,

 

Have a perl script which parses a file (FILE1 has a list of alerts) and sends an email in certain format.

Only thing I need is that for VIPS/hosts having the word test in it should send the email to test@foobar.com
and VIP/host having the word dev (eg. dev.corp.foobar.com) in it  to dev@foobar.com
and VIPs having the name prod in it to prod@foobar.com. The subject needs to be different for each one.

FILE1:

***** Alert *****

Notification Type: PROBLEM

Service: Appsname_2333_env1_region
Host: vip-scv.corp.foobar.com
Address: x.x.x.x
State: CRITICAL

Date/Time: Mon Aug 8 15:50:02 EDT 2011

Additional Info:

CRITICAL - Socket timeout after 3 seconds

Console http://foobar.com/nagios/index.php
 ***** Alert *****

Notification Type: PROBLEM

Service: DiffAppsname_8552_env2_region2
Host: vip2-scv.corp.foobar.com
Address: x.x.x.x
State: CRITICAL

Date/Time: Mon Aug 8 15:50:02 EDT 2011

Additional Info:

CRITICAL - Socket timeout after 3 seconds

Console http://foobar.com/nagios/index.php

 




PERL SCRIPT:


#!/usr/bin/perl -w

use strict;

my ($apps,$email,$host);
open(HM,"<","/var/tmp/email") or die "Fail- $!\n";
open(WM,">","/var/tmp/email_text") or die "Fail- $!\n";

while(<HM>) {
        chomp;
        $apps = $1 if /Service:(.*)/;
        $host = $1 if /^Host:(.*)/;
        if (/Date\/Time:(.*)/) {
                printf WM "%s:%s:%s\n",$apps,$host,$1;  
        }
}
seek HM,0,0;
print WM <HM>;

$email='mail -s "alerts from past 4 mins" user@foobar.com < /var/tmp/email_text 2>/var/tmp/email_err';
system($email);

if ( $? ne 0 ) {
         die "Failure - while sending email. Please check file /tmp/email_err \n";
}

close(WM);
close(HM);

unlink "/tmp/email" or warn "Could not unlink email: $!";;
unlink "/tmp/email_text" or warn "Could not unlink email_text: $!";;

 

Thanks,

Allan.

Please use plain text.
Honored Contributor
Hein van den Heuvel
Posts: 6,581
Registered: ‎05-19-2003
Message 2 of 11 (535 Views)

Re: Route emails in a perl script

I would add an associative array to the perl script to map hosts to email addresses.

As you process a host, start with a generic Email address.

Replace by a specific one,  if it matches a key in the array. 

Glue the selected email address in the email command.

 

Untested example below.

Hope it works...

Hein

 

#!/usr/bin/perl -w
use strict;
my %email_map = (dev => 'dev@foobar.com', test => 'test@foobar.com', prod=> 'prod@foobar.com');

my ($apps,$email,$host, $email_address);

open(HM,"<","/var/tmp/email") or die "Fail- $!\n";

open(WM,">","/var/tmp/email_text") or die "Fail- $!\n";

 

while(<HM>) {        

chomp;

       $apps = $1 if /Service:(.*)/;

        $host = $1 if /^Host:(.*)/; 

       if (/Date\/Time:(.*)/) {

                printf WM "%s:%s:%s\n",$apps,$host,$1;

         }

}

seek HM,0,0;print WM <HM>;
$email_address = 'user@foobar.com';

for (keys %email_map) { $email_adress = $email_map{$_} if $host =~ /^\s*$_/;

$email='mail -s "alerts from past 4 mins" ' . $email_adress . ' < /var/tmp/email_text 2>/var/tmp/email_err';system($email);

 

if ( $? ne 0 ) {

       die "Failure - while sending email. Please check file /tmp/email_err \n";

}

close(WM);

close(HM);
unlink "/tmp/email" or warn "Could not unlink email: $!";;

unlink "/tmp/email_text" or warn "Could not unlink email_text: $!";;

Please use plain text.
Honored Contributor
H.Merijn Brand (procura
Posts: 6,185
Registered: ‎10-13-1997
Message 3 of 11 (522 Views)

Re: Route emails in a perl script

OK, I'll bite ...

 

use strict;
use warnings;
use Mail::Sendmail;

my $alerts = do { local ($/, @ARGV) = (undef, "alerts.txt"); <> };
my @alerts = split m/\s*\Q***** Alert *****\E\s*/ => $alerts;

my ($from, $to) = ('reporter@my.site.com', 'user@foobar.com');

my @summ;
for (@alerts) {
    my %tag = (m/^\s*(\S+)\s*:\s*(.*?)\s*$/gm) or next;
    push @summ, "$tag{Service}:$tag{Host}:$tag{'Date/Time'}\n";
    $tag{Host} =~ m/\b test \b/ix	and $to =~ s/user/test/;
    $tag{Host} =~ m/\b dev  \b/ix	and $to =~ s/user/dev/;
    $tag{Host} =~ m/\b prod \b/ix	and $to =~ s/user/prod/;
    }

sendmail ({
    To      => $to,
    From    => $from,
    Subject => "Alerts from past 4 mins",
    Message => join "\n", @summ, $alerts,
    }) or die $Mail::Sendmail::error;

 This is about what I deduced from your code. I'll leave it up to you to make the change to the subject based on the recipient.

 

What I did was

1. Read the complete alerts file. (you parsed it twice)

2. Split the alerts into chuncks

3. create a summary line for each chunk

mail the summary and the complete body to the recipient. The recipient is default 'user' and is changed on the first host that matches any of the threee criteria you asked for. 


 

Enjoy, Have FUN! H.Merijn
Please use plain text.
Frequent Advisor
allanm77
Posts: 88
Registered: ‎06-27-2011
Message 4 of 11 (510 Views)

Re: Route emails in a perl script

[ Edited ]

Thanks Hein,

 

Can the subject append the word dev, test & prod to the subject line?

 

Its currently not sending the alerts to specific email ids but rather to the default one.

 

It would be great if it can.

 

Regards,

Allan.

Please use plain text.
Honored Contributor
Hein van den Heuvel
Posts: 6,581
Registered: ‎05-19-2003
Message 5 of 11 (499 Views)

Re: Route emails in a perl script

Sure...

 

Again untested...

 

 

my $subject = 'alerts from past 4 mins';

$email_address = 'user@foobar.com';

for (keys %email_map) {

      if ( $host =~ /^\s*$_/ ) {

            $email_adress = $email_map{$_}; 

            $subject .= " from $_";

}


$email = "mail -s  \"$subject \"  $email_adress . < /var/tmp/email_text 2>/var/tmp/email_err";

system($email);

 

fwiw,

Hein

Please use plain text.
Frequent Advisor
allanm77
Posts: 88
Registered: ‎06-27-2011
Message 6 of 11 (497 Views)

Re: Route emails in a perl script

Thanks again!

Not getting any emails now :(

Earlier I got the same email four times to the default user.

Can you test out at your end and see what the problem could be... I have given the sample file above.

Thanks,
Allan.
Please use plain text.
Acclaimed Contributor
James R. Ferguson
Posts: 21,184
Registered: ‎07-06-2000
Message 7 of 11 (485 Views)

Re: Route emails in a perl script

Hi:

 

Hein's original post(s) mis-spelled "$email_address" [ which the 'strict' pragma would have told you ] and as an untested post, lacked a closing brace.  HIS SCRIPT should (likely) be:

 

#!/usr/bin/perl
use strict;
use warnings;
my %email_map = (dev => 'dev@foobar.com', test => 'test@foobar.com', prod=> 'prod@foobar.com');

my ($apps,$email,$host, $email_address);
open(HM,"<","/var/tmp/email") or die "Fail- $!\n";
open(WM,">","/var/tmp/email_text") or die "Fail- $!\n";

while(<HM>) {
    chomp;
    $apps = $1 if /Service:(.*)/;
    $host = $1 if /^Host:(.*)/;
    if (/Date\/Time:(.*)/) {
        printf WM "%s:%s:%s\n",$apps,$host,$1;
    }
}
seek HM,0,0;print WM <HM>;
my $subject = 'alerts from past 4 mins';
$email_address = 'user@foobar.com';
for (keys %email_map) {
     if ( $host =~ /^\s*$_/ ) {
         $email_address = $email_map{$_};
         $subject .= " from $_";
     }
     $email='mail -s "alerts from past 4 mins" ' . $email_address . ' < /var/tmp/email_text 2>/var/tmp/email_err';system($email);

    if ( $? ne 0 ) {
           die "Failure - while sending email. Please check file /tmp/email_err \n";
    }
}

close(WM);
close(HM);
unlink "/tmp/email" or warn "Could not unlink email: $!";
unlink "/tmp/email_text" or warn "Could not unlink email_text: $!";

 Regards!

 

...JRF...

Please use plain text.
Frequent Advisor
allanm77
Posts: 88
Registered: ‎06-27-2011
Message 8 of 11 (465 Views)

Re: Route emails in a perl script

Thanks JRF!

Some of it I had figured, also I am a little concerned about the unlinks down below, that it deletes the files even though the program is successful or not.

Regards,
Allan.
Please use plain text.
Acclaimed Contributor
James R. Ferguson
Posts: 21,184
Registered: ‎07-06-2000
Message 9 of 11 (461 Views)

Re: Route emails in a perl script


allanm77 wrote:
I am a little concerned about the unlinks down below, that it deletes the files even though the program is successful or not.

Hi Alan:

 

First, thank Hein.  I just fixed up some of his untested syntax.  As for the unlink()'s, you don't know that the mail will ever be delivered or not, so everything is on-faith.  Because the files in question live in '/var/tmp', the inference is that they aren't critical to anything but this process.

 

If, for whatever reason, you feel that removing them isn't what you want to do, you could simply rename() them, leaving their eventual cleanup to a routine purge (with 'find') of '/var/tmp' .

 

In fact, you actually have used to different paths in your script!  You 'open()' in '/var/tmp' but 'unlink()' from '/tmp'.   A better way to avoid this is to declare variables (or constants) with the file names.  Then, by example, you could do this to rename the file or files you want to keep:

 

my $HM_name = '/var/tmp/email';
my $WM_name = '/var/tmp/email_text';

#...

my ($mon,$mday,$year) = (localtime)[4,3,5];
my $suffix = sprintf "_%02d%02d%04d", $mon+1, $mday, $year+1900;

rename $HM_name, $HM_name . $suffix;
1;

 Regards!

 

...JRF...

 

Please use plain text.
Frequent Advisor
allanm77
Posts: 88
Registered: ‎06-27-2011
Message 10 of 11 (452 Views)

Re: Route emails in a perl script

Thanks Hein & JRF!

Have another question about the original perl script (from above), I want to use that on three to four different files -

/var/tmp/email & /var/tmp/email_new & /var/tmp/email_newer

with same logic and probably send to different userids with different subjects.

I tried to keep that in the same script but struggled with die statements which used to close the program if it couldn't find the one of the file.

Thanks,
Allan.
Please use plain text.
Acclaimed Contributor
James R. Ferguson
Posts: 21,184
Registered: ‎07-06-2000
Message 11 of 11 (448 Views)

Re: Route emails in a perl script


allanm77 wrote:
Have another question about the original perl script (from above), I want to use that on three to four different files -
/var/tmp/email & /var/tmp/email_new & /var/tmp/email_newer
with same logic and probably send to different userids with different subjects.
I tried to keep that in the same script but struggled with die statements which used to close the program if it couldn't find the one of the file.

Currently you 'die' (with the reason for the death) if you can't open a file.  That's one way.  I would construct your 'open...or die...' like this, though:

 

...
my $HM_name = '/var/tmp/email';
open NM, .'<', $NM_name or die "Can't open '$NM_name': $!\n";
...

You can also test for the presence of a file and only if present, open it:

 

if ( -e $NM_name ) {
    open NM, '<', $NM_name or die "Can't open '$NM_name': $!\n";
}
else {
    ...
}

 

Notice how we defined the file name as a variable for consistent use throughout, too.  If it's wrong in one place, its the same "wrong" everywhere :-)

 

In the second example code where we test for file existence we are ignoring a race condition where a file does indeed exist and the test is satisfied, but the open fails (and you die) because when that's atttempted another process has removed the file.  I don't believe that you need to worry in a case like this, but you should be aware of the potential if only in the abstract.

 

Regards!

 

...JRF...



Please use plain text.
The opinions expressed above are the personal opinions of the authors, not of HP. By using this site, you accept the Terms of Use and Rules of Participation