LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-25-2015, 08:26 AM   #1
zokken
Member
 
Registered: Oct 2008
Posts: 44

Rep: Reputation: 16
Script to Conditionally Send Mail Based on Logs


Hey All,

So what I'm attempting to do is search for a particular string in a log file that appears after a certain time. Pull the usernames from the results and count the number of times each username appears.

What I'm having trouble with is coming up with a way to trigger an email if any of the usernames appear more than a certain number of times.

Here's a simplified snipped of code of what I've done so far.

Code:
#!/bin/bash


checktime () {
   while read line; do
      # code that checks if the timestamp of each line is after
      # a certain time; if it is, echo the line
   done
}

# grep logfile for search_string; pass the results to the checktime function.
# use awk to pull usernames from the results and count number of occurrences
# for each user
grep search_string logfile | checktime | awk '{print $9}' sort | uniq -c
This part works. What I'd like to do next is send an email with the usernames and their count if the count exceeds a certain amount. I can come up with ways to do it, but it doesn't seem very efficient/elegant. For example:

Code:
#!/bin/bash

results=""

checktime () {
   while read line; do
      # code that checks if the timestamp of each line is after
      # a certain time; if it is, echo the line
   done
}

# print username if it appears more than 50 times in the results
checklogs () {
   while read line; do
      if [[ $(echo $line | awk '{print $1}') -ge 50 ]]; then
         echo $line
      fi
   done
}

# grep logfile for search_string; pass the results to the checktime function.
# use awk to pull usernames from the results and count number of occurrences
# for each user. pass this to the checklogs function.
results=$(grep search_string logfile | checktime | awk '{print $9}' sort | uniq -c | checklogs

# if $results isn't empty, at least one user exceeded the count. email results.
[[ "$results" != "" ]] && echo $results | /bin/mail -s "results" addy@domain.com
This seems to work (though I'm left with the formatting problem when echo'ing $results to an email), but I'm looking for suggestions on how to better do it.
 
Old 02-25-2015, 09:02 AM   #2
unSpawn
Moderator
 
Registered: May 2001
Posts: 29,415
Blog Entries: 55

Rep: Reputation: 3600Reputation: 3600Reputation: 3600Reputation: 3600Reputation: 3600Reputation: 3600Reputation: 3600Reputation: 3600Reputation: 3600Reputation: 3600Reputation: 3600
Code:
checktime () {
   while read line; do
      # code that checks if the timestamp of each line is after
      # a certain time; if it is, echo the line
}
The problem with this is that anything passing through syslog has a human readable time stamp set. That is good but not efficient to work with so you'll better internally convert time stamps to epoch (as in date '+%s' --date=something)' for easy comparison...


Code:
# print username if it appears more than 50 times in the results
checklogs () {
   while read line; do
      if [[ $(echo $line | awk '{print $1}') -ge 50 ]]; then
         echo $line
      fi
   done
}
If the output is always a value string pair then you could use an array and use ${ARRAY[0]}.



Code:
# if $results isn't empty, at least one user exceeded the count. email results.
[[ "$results" != "" ]] && echo $results | /bin/mail -s "results" addy@domain.com
Same here: RESULTS can be an array so if '[ ${#RESULTS[@]} =! 0 ]' that's the trigger to send an email. Personally I'd start by cutting the log file at the time stamp first (use 'mktemp' to hold temporary files?). Unless you have a very fast growing log file and can't afford to miss entries while processing this ensures you only have to check time stamps once at the beginning of the script. In pseudo code:

Code:
define THRESHOLD
define LOG_FILE
define TIME_STAMP
define STRING

test -s LOG_FILE && exit 0
grep -q -m1 TIME_STAMP LOG_FILE || exit 0

mktemp TEMPDIR && { cut LOG_FILE at TIME_STAMP > TEMPDIR/TEMPFILE
awk '/STRING/ {print STRING_FIELD USERNAME_FIELD} TEMPDIR/TEMPFILE | sort -u | while read STRING_VALUE USER_VALUE; do
 [ `grep -m50 -c "STRING_VALUE.*USER_VALUE" (or something)` -ge THRESHOLD ] && echo USER_VALUE
done > TEMPDIR/REPORTFILE; test -s TEMPDIR/REPORTFILE && mail TEMPDIR/REPORTFILE
} && CLEANUP

exit 0
HTH
 
1 members found this post helpful.
Old 02-25-2015, 09:52 AM   #3
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,930

Rep: Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321
my usual comment is: do not use pipe chains like grep|awk|sort|uniq, usually it can be solved within a single perl/awk/python/whatever script. It would be more efficient, and every requirement can be implemented - not to speak about the while cycle containing a $(... | awk)!
Especially the function checklogs can be replaced by:
awk '$1>=50'
Also checkline will look quite similar:
awk ' <condition> '
(but it is a bit harder, you need to specify input line format and how/what do you want to check)
Next, grep pattern file usually can be replaced by awk '/pattern/' file
sort and uniq were also already implemented in awk - and you only need to combine all of it into one single script
 
1 members found this post helpful.
Old 02-26-2015, 09:26 AM   #4
zokken
Member
 
Registered: Oct 2008
Posts: 44

Original Poster
Rep: Reputation: 16
Thanks for the replies; they're both definitely helpful.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
How to write this SIMPLE SCRIPT based on output to send mail ? manalisharmabe Linux - Newbie 18 04-18-2014 12:35 AM
[SOLVED] Can I have a script send me an email if a person logs on incorrectly 3 times? Rupadhya Linux - Newbie 7 10-06-2012 03:13 PM
Send input from one script to another menu based script. simonedgcumbe Programming 9 03-24-2010 09:22 PM
Conditionally Setting up Different Network Connections Based on Available Networks c4onastick Linux - Networking 1 09-07-2009 02:23 PM
How do I send daily clamav scan logs to my work e-mail account rwtreke SUSE / openSUSE 3 05-20-2005 12:05 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:12 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration