Difference between revisions of "Monitor logs, send email alert / run script"

From MikroTik Wiki
Jump to: navigation, search
(Created page with "== Description == This script monitors the logs for particular words/phrases, and then excludes results based on a second set of words/phrases. If new matching logs are found, a...")
 
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
== Description ==
 
== Description ==
  
This script monitors the logs for particular words/phrases, and then excludes results based on a second set of words/phrases. If new matching logs are found, an email is sent / a script is run / whatever...
+
This script monitors the logs for particular words/phrases, and then excludes results based on a second set of words/phrases. If new matching logs are found, an email is sent (or other code could be run)
  
== Todo ==
+
== v4 Changes ==
 +
 
 +
tested on v5.26 and v6.20
  
 
<ul>
 
<ul>
<li>The startBuf array really needs to be an array for easier editing / implementation.</li>
+
<li>Script now catches all matching logs since the last detection.</li>
<li>Need to change the time stamp to be a date + time stamp, to eliminate the very slim possibility that a new log exactly 24h later would not be detected.</li>
+
<li>Date/time checking updated to look for 3 possible formats.</li>
 +
<li>Changed time stamp to now be date/time stamp</li>
 
</ul>
 
</ul>
  
 
== Instructions ==
 
== Instructions ==
  
Create a new schedule. Set the duration to how often you want to check for new logs. If the duration is too long, there may be a number of "new" matching logs but only the most recent will be "detected".
+
Create a new schedule, and paste the script into the schedule. Set the duration to how often you want to check for new logs.
 +
 
 +
 
 +
Change this to the name of your schedule (the date/time stamp is saved in the schedule's comment).
 +
<pre>:local scheduleName "mySchedule"</pre>
 +
 
 +
 
 +
Put your email address here.
 +
<pre>:local emailAddress "email@domain.com"</pre>
 +
 
 +
 
 +
This currently detects two strings. It can be changed to more or less strings if desired. Remove: '''|| message~"login failure"''' if you only want to use one string, or if you want more strings, add this same code at the end (but before the last two end brackets).
 +
<pre>:local startBuf [:toarray [/log find message~"logged in" || message~"login failure"]]</pre>
 +
 
 +
 
 +
Edit the quoted items for strings you want to be filtered out of the results. For example, if you want all "logged in" logs found, but you do not want any of the "logged in via telnet" logs included, simply include the word "telnet" in the array and these logs will be excluded. Double quote additional strings and separate them with semi-colons. If you don't want any logs filtered, simply declare the variable ''':local removeThese''' without any curly braces.
 +
<pre>:local removeThese {"telnet";"whatever string you want"}</pre>
  
 
== The Script ==
 
== The Script ==
 
Paste the script into the new schedule.
 
  
 
<pre>
 
<pre>
 +
# BEGIN SETUP
 
:local scheduleName "mySchedule"
 
:local scheduleName "mySchedule"
:local emailAddress "myEmail"
+
:local emailAddress "user@email.com"
 
:local startBuf [:toarray [/log find message~"logged in" || message~"login failure"]]
 
:local startBuf [:toarray [/log find message~"logged in" || message~"login failure"]]
:local removeThese ("telnet","whatever string you want")
+
:local removeThese {"telnet";"whatever string you want"}
+
# END SETUP
 +
 
 +
# warn if schedule does not exist
 +
:if ([:len [/system scheduler find name="$scheduleName"]] = 0) do={
 +
  /log warning "[LOGMON] ERROR: Schedule does not exist. Create schedule and edit script to match name"
 +
}
 +
 
 +
# get last time
 
:local lastTime [/system scheduler get [find name="$scheduleName"] comment]
 
:local lastTime [/system scheduler get [find name="$scheduleName"] comment]
 +
# for checking time of each log entry
 +
:local currentTime
 +
# log message
 +
:local message
 
   
 
   
:local currentBuf ""; :set currentBuf [:toarray $currentBuf]
+
# final output
 +
:local output
 +
 
 +
:local keepOutput false
 +
# if lastTime is empty, set keepOutput to true
 +
:if ([:len $lastTime] = 0) do={
 +
  :set keepOutput true
 +
}
 +
 
 +
 
 +
:local counter 0
 +
# loop through all log entries that have been found
 +
:foreach i in=$startBuf do={
 
   
 
   
:foreach i in=$startBuf do={
+
# loop through all removeThese array items
   :local toggle 1
+
   :local keepLog true
   :foreach j in=[:toarray $removeThese] do={
+
   :foreach j in=$removeThese do={
     :if ([:typeof [:find [/log get $i message] "$j"]] = "num") do={
+
#  if this log entry contains any of them, it will be ignored
       :set toggle 0
+
     :if ([/log get $i message] ~ "$j") do={
 +
       :set keepLog false
 
     }
 
     }
 
   }
 
   }
   :if ($toggle = 1) do={
+
   :if ($keepLog = true) do={
     :set currentBuf ($currentBuf , $i)
+
 
 +
  :set message [/log get $i message]
 +
 
 +
#  LOG DATE
 +
#  depending on log date/time, the format may be different. 3 known formats
 +
#  format of jan/01/2002 00:00:00 which shows up at unknown date/time. Using as default
 +
    :set currentTime [ /log get $i time ]
 +
#  format of 00:00:00 which shows up on current day's logs
 +
  :if ([:len $currentTime] = 8 ) do={
 +
    :set currentTime ([:pick [/system clock get date] 0 11]." ".$currentTime)
 +
    } else={
 +
#    format of jan/01 00:00:00 which shows up on previous day's logs
 +
    :if ([:len $currentTime] = 15 ) do={
 +
        :set currentTime ([:pick $currentTime 0 6]."/".[:pick [/system clock get date] 7 11]." ".[:pick $currentTime 7 15])
 +
      }
 +
  }
 +
   
 +
#  if keepOutput is true, add this log entry to output
 +
  :if ($keepOutput = true) do={
 +
    :set output ($output.$currentTime." ".$message."\r\n")
 +
  }
 +
#  if currentTime = lastTime, set keepOutput so any further logs found will be added to output
 +
#  reset output in the case we have multiple identical date/time entries in a row as the last matching logs
 +
#  otherwise, it would stop at the first found matching log, thus all following logs would be output
 +
    :if ($currentTime = $lastTime) do={
 +
    :set keepOutput true
 +
    :set output ""
 +
  }
 +
  }
 +
 
 +
#  if this is last log entry
 +
  :if ($counter = ([:len $startBuf]-1)) do={
 +
#  If keepOutput is still false after loop, this means lastTime has a value, but a matching currentTime was never found.
 +
#  This can happen if 1) The router was rebooted and matching logs stored in memory were wiped, or 2) An item is added
 +
#  to the removeThese array that then ignores the last log that determined the lastTime variable.
 +
#  This resets the comment to nothing. The next run will be like the first time, and you will get all matching logs
 +
  :if ($keepOutput = false) do={
 +
#     if previous log was found, this will be our new lastTime entry     
 +
    :if ([:len $message] > 0) do={
 +
        :set output ($output.$currentTime." ".$message."\r\n")
 +
      }
 +
    }
 
   }
 
   }
 +
  :set counter ($counter + 1)
 
}
 
}
+
 
:local currentLineCount [ :len $currentBuf ]
+
# If we have output, save new date/time, and send email
 
+
if ([:len $output] > 0) do={
if ($currentLineCount > 0) do={
+
  /system scheduler set [find name="$scheduleName"] comment=$currentTime
  :local currentTime "$[ /log get [ :pick $currentBuf ($currentLineCount -1) ] time ]"
+
  /tool e-mail send to="$emailAddress" subject="MikroTik alert $currentTime" body="$output"
 
+
  /log info "[LOGMON] New logs found, send email"
  :if ([:len $currentTime] = 15 ) do={
 
      :set currentTime [ :pick $currentTime 7 15 ]
 
  }
 
   
 
  :local output "$currentTime $[/log get [ :pick $currentBuf ($currentLineCount-1) ] message ]"
 
   
 
  :if (([:len $lastTime] < 1) || (([:len $lastTime] > 0) && ($lastTime != $currentTime))) do={
 
      /system scheduler set [find name="$scheduleName"] comment=$currentTime
 
      /tool e-mail send to="$emailAddress" subject="MikroTik alert $currentTime" body="$output"
 
  }
 
 
}
 
}
 
</pre>
 
</pre>
  
== Config ==
 
 
Change the first few config items.
 
 
 
<pre>:local scheduleName "mySchedule"</pre>
 
Change this to the name of your schedule.
 
 
 
<pre>:local emailAddress "myEmail"</pre>
 
Put your email address here.
 
 
 
<pre>:local startBuf [:toarray [/log find message~"logged in" || message~"login failure"]]</pre>
 
This currently detects two strings. It can be changed to more or less strings if desired. Remove: '''|| message~"login failure"''' if you only want to use one string, or if you want more strings, add this same code at the end (but before the last two end brackets).
 
 
 
<pre>:local removeThese ("telnet","whatever string you want")</pre>
 
Edit the quoted items for strings you want to be filtered out of the results. For example, if you want all "logged in" logs found, but you do not want any of the "logged in via telnet" logs included, simply include the word "telnet" in the array and these logs will be excluded. Double quote additional strings and separate them with commas. If you don't want any logs filtered, simply declare the variable :local removeThese, or leave double quotes :local removeThese ("")
 
  
 
== Other Notes ==
 
== Other Notes ==
  
If you would rather run a script or whatever (instead of sending email), simply remove the second line, and change the "/tool email" line near the bottom to do whatever you want.
+
If you would rather run a script or whatever (instead of sending email), simply remove the email config line at the top, and change the "/tool email" line near the bottom to do whatever you want.
  
  
 
Original forum thread here:
 
Original forum thread here:
 
[[http://forum.mikrotik.com/viewtopic.php?f=2&t=60616]]
 
[[http://forum.mikrotik.com/viewtopic.php?f=2&t=60616]]

Latest revision as of 20:23, 18 December 2014

Description

This script monitors the logs for particular words/phrases, and then excludes results based on a second set of words/phrases. If new matching logs are found, an email is sent (or other code could be run)

v4 Changes

tested on v5.26 and v6.20

  • Script now catches all matching logs since the last detection.
  • Date/time checking updated to look for 3 possible formats.
  • Changed time stamp to now be date/time stamp

Instructions

Create a new schedule, and paste the script into the schedule. Set the duration to how often you want to check for new logs.


Change this to the name of your schedule (the date/time stamp is saved in the schedule's comment).

:local scheduleName "mySchedule"


Put your email address here.

:local emailAddress "email@domain.com"


This currently detects two strings. It can be changed to more or less strings if desired. Remove: || message~"login failure" if you only want to use one string, or if you want more strings, add this same code at the end (but before the last two end brackets).

:local startBuf [:toarray [/log find message~"logged in" || message~"login failure"]]


Edit the quoted items for strings you want to be filtered out of the results. For example, if you want all "logged in" logs found, but you do not want any of the "logged in via telnet" logs included, simply include the word "telnet" in the array and these logs will be excluded. Double quote additional strings and separate them with semi-colons. If you don't want any logs filtered, simply declare the variable :local removeThese without any curly braces.

:local removeThese {"telnet";"whatever string you want"}

The Script

# BEGIN SETUP
:local scheduleName "mySchedule"
:local emailAddress "user@email.com"
:local startBuf [:toarray [/log find message~"logged in" || message~"login failure"]]
:local removeThese {"telnet";"whatever string you want"}
# END SETUP

# warn if schedule does not exist
:if ([:len [/system scheduler find name="$scheduleName"]] = 0) do={
  /log warning "[LOGMON] ERROR: Schedule does not exist. Create schedule and edit script to match name"
}

# get last time
:local lastTime [/system scheduler get [find name="$scheduleName"] comment]
# for checking time of each log entry
:local currentTime
# log message
:local message
 
# final output
:local output

:local keepOutput false
# if lastTime is empty, set keepOutput to true
:if ([:len $lastTime] = 0) do={
  :set keepOutput true
}


:local counter 0
# loop through all log entries that have been found
:foreach i in=$startBuf do={
 
# loop through all removeThese array items
  :local keepLog true
  :foreach j in=$removeThese do={
#   if this log entry contains any of them, it will be ignored
    :if ([/log get $i message] ~ "$j") do={
      :set keepLog false
    }
  }
  :if ($keepLog = true) do={
   
   :set message [/log get $i message]

#   LOG DATE
#   depending on log date/time, the format may be different. 3 known formats
#   format of jan/01/2002 00:00:00 which shows up at unknown date/time. Using as default
    :set currentTime [ /log get $i time ]
#   format of 00:00:00 which shows up on current day's logs
   :if ([:len $currentTime] = 8 ) do={
     :set currentTime ([:pick [/system clock get date] 0 11]." ".$currentTime)
    } else={
#     format of jan/01 00:00:00 which shows up on previous day's logs
     :if ([:len $currentTime] = 15 ) do={
        :set currentTime ([:pick $currentTime 0 6]."/".[:pick [/system clock get date] 7 11]." ".[:pick $currentTime 7 15])
      }
   }
    
#   if keepOutput is true, add this log entry to output
   :if ($keepOutput = true) do={
     :set output ($output.$currentTime." ".$message."\r\n")
   }
#   if currentTime = lastTime, set keepOutput so any further logs found will be added to output
#   reset output in the case we have multiple identical date/time entries in a row as the last matching logs
#   otherwise, it would stop at the first found matching log, thus all following logs would be output
    :if ($currentTime = $lastTime) do={
     :set keepOutput true
     :set output ""
   }
  }

#   if this is last log entry
  :if ($counter = ([:len $startBuf]-1)) do={
#   If keepOutput is still false after loop, this means lastTime has a value, but a matching currentTime was never found.
#   This can happen if 1) The router was rebooted and matching logs stored in memory were wiped, or 2) An item is added
#   to the removeThese array that then ignores the last log that determined the lastTime variable.
#   This resets the comment to nothing. The next run will be like the first time, and you will get all matching logs
   :if ($keepOutput = false) do={
#     if previous log was found, this will be our new lastTime entry      
     :if ([:len $message] > 0) do={
        :set output ($output.$currentTime." ".$message."\r\n")
      }
    }
  }
  :set counter ($counter + 1)
}

# If we have output, save new date/time, and send email
if ([:len $output] > 0) do={
  /system scheduler set [find name="$scheduleName"] comment=$currentTime
  /tool e-mail send to="$emailAddress" subject="MikroTik alert $currentTime" body="$output"
  /log info "[LOGMON] New logs found, send email"
}


Other Notes

If you would rather run a script or whatever (instead of sending email), simply remove the email config line at the top, and change the "/tool email" line near the bottom to do whatever you want.


Original forum thread here: [[1]]