Getting last 50 lines after finding a word

Hi All,

I have a requirement as below

I need find for a string in a log file and once i found that string i need to send a mail.Thsi can be done thru grep and mailx cmnd.

Here once i found the string i need to send last 50 lines(up) from where string found.

Actually they require to find out the user name which may be available before 50 lines.

One more thing this script will run every 15 min , i am thinking how to handle if there are multiple cases of these failures

any thoughts or code will be appreciated

Thanks
San

  1. grepping 50 lines after match.
grep -A 50 'PATTERN' file
  1. For a script to be executed every 15 minutes.

You can use cron, and the cron job should be

*/15 * * * * CMD

I think he wants the lines before the pattern - grep -B 'pattern', assuming he has GNU grep (linux)

awk 'BEGIN{tail=50}
{
  a[NR%tail]=$0
}
/pattern/{ for(i=NR+1;i<=NR+tail;i++)print a[i%tail]}
' file

A more efficient way would be to tail and follow the log with "tail -f", store the last 50 lines and email those lines when the failure word occurs. This can be done in either shell, awk or perl easily. An untested gawk version:

tail -f log-file |gawk '
BEGIN { email_cmd = "mail -s failure emails_addrs" }
{
  line[NR%50] = $0
}
/failure word/ {
  for (i = NR-49; i <= NR; i++)
    print line[i%50] | email_cmd
  close(email_cmd)
}'

I was going to suggest binlib's solution, above, although the standard "tail -f" command might not work after a log rotation. The tail from GNU's coreutils will follow the file opened, not the name of the file, unless you do:

  tail --follow=filename

But given that you want the most recent occurrence of a pattern before a second pattern occurs, try this (again, gawk or nawk or mawk):

tail --follow=log-file | awk '
    BEGIN { email_cmd = "mail -s failure emails_addrs" }
    BEGIN { last_found = "NOT AVAILABLE"; last_lineno = 0; }
    /username pattern/ {  last_found = $0; last_lineno = FNR; }
    /failure word/  { print "Found " (FNR-last_lineno) " lines ago:" last_found | email_cmd }'

You'll need to put your own stuff where you see italicized words

Hi All,

Thanks for ur suggestions.Sorry for late reply
I followed otheus suggestion and put the code, but it going to infinite loop and not getting any output. I am new to UNIX, so i may be wrong in some pattern.
Code i am using

#!/bin/sh
tail -f EssbaseLog.txt | awk '
BEGIN { email_cmd = "mail -s failure xxxxx@yyy.com" }
BEGIN { last_found = "NOT AVAILABLE"; last_lineno = 0; }
/[hyperion]/ { last_found = $0; last_lineno = FNR; }
/Error -- not connected/ { print "Found " (FNR-last_lineno) " lines ago:" last_found }'

I have questions on this, as i mentioned if i get error at 2:30 PM, my script will execute and send a report to users.It should also save a text file with that 50 lines for reference.

Then if it runs again on 2:45 it will again send the same error message and it will continue to send the error until log was corrected.

Is there any way we can send only updated errors?

Sorry for amny questions

Any suggestions will be appreciated

Thanks

tail -f EssbaseLog.txt
will run forever and will present lines as they are added to the file. Thus your script will run forever too. You run your script once and let it find errors as they occur.

You didn't use --follow=log-file but you may need it. Post the output from:
uname -a
so folks know what version of unix you have.

ReadLines=0
while [ true ]
do
TMPVAR=$(date +%s)
Totallines=$(wc -l /var/log/YOU.log )
Totallines=$((Totallines-ReadLines))
tail -n $Totallines /var/log/YOU.log | grep -A 50 'PATTERN' > /tmp/$TMPVAR.tmpfile
if grep 'username' /tmp/$TMPVAR.tmpfile ;
 then
   mail -s failure xxxxx@yyy.com < /tmp/$TMPVAR.tmpfile
fi
rm -rf /tmp/$TMPVAR.tmpfile
sleep 900
done

Some concept .. You need to just check with syntax to suit your system.

Basically what I am trying
While [ true ] ---> infinate loop
TMPVAR ... just to create tmp file...
Checking number of lines now and subtracting from what we have previously read. So that we dont want to send error which we have seen already ..
Tail -n ... read only last lines ... what we have not read from previous run .. And check patten and get lines matching above matching pattern.
Then again grep in the 50 lines from PATTERN which are in tmp file .. to see if username is available or not ..

if Available then mail .. else ... Nothing ..
Cleanup: remove all tmp file etc .. and sleep for 900 sec 15 mins ..

Better place to put this check is in cron:

Incase you decide to put in cron removing while do ... then push this number to some tmp file .. Like records read and etc ..
Also make note of more details in the same tmp where number of records are saved.. details like log file creation date etc to reset ReadLines variables incase the log gets rotated .. truncated etc ...

When you change PATTERN and username for your system .. Please add proper escape character wherever applicable

  1. Use crontab to run every fifteen minutes, key "man crontab" in shell.

  2. This script may work <script.sh <your text to grep>:

#!/usr/bin/ksh

thelog="/your/local/logpath"
user=$1
lines="50"

run () {

 num1=$\(cat -n $thelog |grep $1 |awk '\{print $1\}' |head -1\)
 num2=$\(expr $num1 - $lines\)

if [ $num1 -gt 50 ]
then
results=$(cat -n $thelog |sed -n "$num2,${num1}p")

 else
    results=$\(cat -n $thelog |sed -n '1,50p'\)
    
   fi
     echo "$results" |mailx -s "blabla" [email]yourmailbox@nospamplease.com[/email]

}

run $user;