Monitor Mikrotik log by Telegram

Probably mipsbe and arm have something different inside??? Just one hypothesis…

Hi, I am trying to adapt this script to be compatible with the new ISO date format of v7.10+.

Could the “LOG DATE” part of the code be made shorter?

 # LOG DATE
        # format daily 00:00:00
        :if ([:len $currentTime] = 8 ) do={
            
            # format $date 2023-05-17 (10)
            :if ([:len $date] = 10) do={
                :set currentTime ([:pick $date 8 10]."/".[:pick $date 5 7]."/".[:pick $date 0 4]." ".$currentTime)
            }
            # format $date may/17/2023 (11)
            :if ([:len $date] = 11) do={
                :set currentTime ([:pick $date 4 6]."/".[$mesnum [:pick $date 0 3]]."/".[:pick $date 7 11]." ".$currentTime)
            }
        } 

        # format jan/01/2023 00:00:00 (20)
        :if ([:len $currentTime] = 20 ) do={
            :set currentTime ([:pick $currentTime 4 6]."/".[$mesnum [:pick $currentTime 0 3]]."/".[:pick $currentTime 7 11]." ".[:pick $currentTime 12 20])
        }

        # format jan/01 00:00:00 (15)
        :if ([:len $currentTime] = 15 ) do={
            :set currentTime ([:pick $currentTime 4 6]."/".[$mesnum [:pick $currentTime 0 3]]."/".[:pick $date 7 11]." ".[:pick $currentTime 7 15])
        }
        
        # format 05-16 00:00:00 (14)
        :if ([:len $currentTime] = 14 ) do={
            :set currentTime ([:pick $currentTime 3 5]."/".[:pick $currentTime 0 2]."/".[:pick $date 7 11]." ".[:pick $currentTime 6 14])
        }

Complete script (works fine):

# BEGIN SETUP Edit Here
:local bot "XXXXXXXXXXXXXXXX:XXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXX
:local ChatID "XXXXXXXXX"
:local myserver ("\E2\84\B9"." "."MikroTik"." ".[/system identity get name]." ".[/system resource get board-name])
:local scheduleName "LogFilter"

# Separate the words you want to filter with "|" within the array: message~"(filter1|filter2|filter3|...)"
:local startBuf [:toarray [/log find where message~"(login failure|logged in|loop|down|fcs|excessive|system|rebooted|ipsec|ike2)" or topics~"(error|critical)"]]

# :local removeThese {"link";"telnet"}
:local removeThese

# 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. curly braces sample as follow {"testing";"whatever string you want"}
# END SETUP

# Convert 10/oct/2021 to numeric date: 10/10/2021 -> $mesnum
:global mesnum
:local date [/system clock get date]

# warn if schedule does not exist and create it
:if ([:len [/system scheduler find name="$scheduleName"]] = 0) do={
    /log warning "[LogFilter] Alert : Schedule does not exist. Creating schedule ...."
    /system scheduler add name=$scheduleName interval=60s start-date=dec/12/2022 start-time=12:00:00 on-event=LogFilter
    /log warning "[LogFilter] Alert : Schedule created!"
}

# get last time from scheduler's comment
: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]
        :set currentTime [ /log get $i time ]
                
        # LOG DATE
        # format daily 00:00:00
        :if ([:len $currentTime] = 8 ) do={
            
            # format $date 2023-05-17 (10)
            :if ([:len $date] = 10) do={
                :set currentTime ([:pick $date 8 10]."/".[:pick $date 5 7]."/".[:pick $date 0 4]." ".$currentTime)
            }
            # format $date may/17/2023 (11)
            :if ([:len $date] = 11) do={
                :set currentTime ([:pick $date 4 6]."/".[$mesnum [:pick $date 0 3]]."/".[:pick $date 7 11]." ".$currentTime)
            }
        } 

        # format jan/01/2023 00:00:00 (20)
        :if ([:len $currentTime] = 20 ) do={
            :set currentTime ([:pick $currentTime 4 6]."/".[$mesnum [:pick $currentTime 0 3]]."/".[:pick $currentTime 7 11]." ".[:pick $currentTime 12 20])
        }

        # format jan/01 00:00:00 (15)
        :if ([:len $currentTime] = 15 ) do={
            :set currentTime ([:pick $currentTime 4 6]."/".[$mesnum [:pick $currentTime 0 3]]."/".[:pick $date 7 11]." ".[:pick $currentTime 7 15])
        }
        
        # format 05-16 00:00:00 (14)
        :if ([:len $currentTime] = 14 ) do={
            :set currentTime ([:pick $currentTime 3 5]."/".[:pick $currentTime 0 2]."/".[:pick $date 7 11]." ".[:pick $currentTime 6 14])
        }

        # if keepOutput is true, add this log entry to output
        :if ($keepOutput = true) do={
            :set output ($output."------------------------------"."%0A".$currentTime." ".$message."%0A")
        }
        
        # 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)
            }
        }
    }

    :set counter ($counter + 1)
}

# If we have output, save new date/time, and send Telegram
if ([:len $output] > 0) do={
    /system scheduler set [find name="$scheduleName"] comment=$currentTime
    /tool fetch url="https://api.telegram.org/bot$bot/sendMessage\?chat_id=$ChatID&text=$myserver%0A$output" keep-result=no;
}

Thanks.

add $currentTime to log that repost only the date is wrong, must be 00:00:00
add the scheduler using old format value probably is unsupported, if not on 10beta5, on new versions.

The tests are done on a hAP ac^2 with v7.10beta5.
But now I want it to be valid for versions <7.10

I assume you are referring to this part of the code:


# warn if schedule does not exist and create it
:if ([:len [/system scheduler find name="$scheduleName"]] = 0) do={
    /log warning "[LogFilter] Alert : Schedule does not exist. Creating schedule ...."
    /system scheduler add name=$scheduleName interval=60s start-date=dec/12/2022 start-time=12:00:00 on-event=LogFilter
    /log warning "[LogFilter] Alert : Schedule created!"
    }

well it "swallows" it correctly:
In the future I will have to correct it when it stops working.

[admin@MikroTik] > :put [/sys sche get 5]
.id=*b;comment=19/05/2023 11:06:32;disabled=false;interval=00:01:00;name=LogFilter;next-run=11:10:00;on-event=LogFilter;owner=admin;policy=ftp;reboot;read;write;policy;test;password;sniff;sensitive;romon;run-count=2205;start-date=2022-12-12;start-time=12:00:00

Regarding your $currentTime comment, I don't understand what you mean.

Anyway the question I asked was if it is possible to "shorten" the "LOG DATE" part of the code.

old format value probably is unsupported, if not on 10beta5, on new versions.
sorry, wrong typing:
old format value is probably not supported, if not now on 10beta5, on new versions it may no longer be usable


I’m preparing the script for you to see, it takes a while because I’m at work now.


I’m referring to this:

            # format $date 2023-05-17 (10)
            :if ([:len $date] = 10) do={
                :set currentTime ([:pick $date 8 10]."/".[:pick $date 5 7]."/".[:pick $date 0 4]." ".$currentTime)
            }

if tle log is only 2023-05-17 (or may/17/2023) with not time, is wrong add $currentTime at the end, but must be added 00:00:00

Oh thanks, no problem.

Rex, the approach of the script is fine because the Log lines of less than 24h do not have the date, only the time:

:if ([:len $currentTime] = 8 )

Log e.g.
02:07:19 script,info Automated Cloud Backup Completed

The script completes that line by incorporating the “current” date of the actual day


:if ([:len $currentTime] = 8 ) do={
	
	# format $date 2023-05-17 (10)
	:if ([:len $date] = 10) do={
		:set currentTime ([:pick $date 8 10]."/".[:pick $date 5 7]."/".[:pick $date 0 4]." ".$currentTime)
	}
	# format $date may/17/2023 (11)
	:if ([:len $date] = 11) do={
		:set currentTime ([:pick $date 4 6]."/".[$mesnum [:pick $date 0 3]]."/".[:pick $date 7 11]." ".$currentTime)
	}
}

Output:
19/05/2023 02:07:19 script,info Automated Cloud Backup Completed
In this format it sends it to Telegram

..

sorry, not noticed the “[:len $currentTime] = 8” because is unexpected / not well nested
and the comment “# format $date 2023-05-17 (10)” is misleading

:global anydate2isodate do={
:local dtime [:tostr $1]
/system clock
:local cyear [get date] ; :if ($cyear ~ “…-..-..”) do={:set cyear [:pick $cyear 0 4]} else={:set cyear [:pick $cyear 7 11]}
:if (([:len $dtime] = 10) or ([:len $dtime] = 11)) do={:set dtime “$dtime 00:00:00”}
:if ([:len $dtime] = 15) do={:set dtime “$[:pick $dtime 0 6]/$cyear $[:pick $dtime 7 15]”}
:if ([:len $dtime] = 14) do={:set dtime “$cyear-$[:pick $dtime 0 5] $[:pick $dtime 6 14]”}
:if ([:len $dtime] = 8) do={:set dtime “$[get date] $dtime”}
:if ([:tostr $1] = “”) do={:set dtime (“$[get date] $[get time]”)}
:local vdoff [:toarray “0,4,5,7,8,10,11,19”]
:local MM [:pick $dtime ($vdoff->2) ($vdoff->3)]
:if ($dtime ~ “…/../…”) do={
:set vdoff [:toarray “7,11,1,3,4,6,12,20”]
:set MM ([:find “xxanebarprayunulugepctovecANEBARPRAYUNULUGEPCTOVEC” [:pick $dtime ($vdoff->2) ($vdoff->3)] -1] / 2)
:if ($MM>12) do={:set MM ($MM - 12)} ; :if ($MM<10) do={:set MM “0$MM”}
}
:return “$[:pick $dtime ($vdoff->0) ($vdoff->1)]-$MM-$[:pick $dtime ($vdoff->4) ($vdoff->5)] $[:pick $dtime ($vdoff->6) ($vdoff->7)]”
}
:put [$anydate2isodate “apr/22/2023 16:33:41”] ; # 2023-04-22 16:33:41
:put [$anydate2isodate “apr/22/2023”] ; # 2023-04-22 00:00:00
:put [$anydate2isodate “apr/22 16:33:41”] ; # 2023-04-22 16:33:41
:put [$anydate2isodate “Apr/22 16:33:41”] ; # 2023-04-22 16:33:41
:put [$anydate2isodate “2023-04-22 16:33:41”] ; # 2023-04-22 16:33:41
:put [$anydate2isodate “2023-04-22”] ; # 2023-04-22 00:00:00
:put [$anydate2isodate “04-22 16:33:41”] ; # -04-22 16:33:41
:put [$anydate2isodate “16:33:41”] ; # -04-22 16:33:41
:put [$anydate2isodate] ; #

Brillante!. Grazie.
Works great.

I’m sorry the comment confused you.

BR.

Thanks, No worry

Since is based to
http://forum.mikrotik.com/t/i-did-it-script-to-compute-unix-time/68576/24
I’ve updated the previous script with some shortcuts and removed all unused/useless parts.

Hi Rex, I think I have detected a bug? in the script:

:put [$anydate2isodate “04-22 16:33:41”]

In v.7.9 output
2023-04-22 16:33:41

In v7.10beta5 output:
-19–4–2 6:33:41

Is it normal?

EDIT post: changing the order of the date. Sorry.
..

Can be a bug, I check.

Failed tests in these cases:
(v7.10beta5)
:put [$anydate2isodate "apr/22 16:33:41"]; # -19 -04-22 6:33:41
:put [$anydate2isodate "Apr/22 16:33:41"]; # -19 -04-22 6:33:41
:put [$anydate2isodate "04-22 16:33:41"]; # -19--4--2 6:33:41

thanks.

Yes, is why apr/xx is unexpected on 7.10beta5 and 04-xx is unexpected on previous version.

I already fix the script (check if is the latest version) if the parameter is passed without to be readed from log.

ok, no problem.

BR.

You have thested the last script?

wow! now it's working!
now works on both systems, v7.9 and v7.10

thanks for everything!!!

Ok!

Can we have an updated complete script?

The instructions and comments are removed for check the code and fix some things.
:global anydate2isodate do={
:local dtime [:tostr $1]
/system clock
:local cyear [get date] ; :if ($cyear ~ “…-..-..”) do={:set cyear [:pick $cyear 0 4]} else={:set cyear [:pick $cyear 7 11]}
:if (([:len $dtime] = 10) or ([:len $dtime] = 11)) do={:set dtime “$dtime 00:00:00”}
:if ([:len $dtime] = 15) do={:set dtime “$[:pick $dtime 0 6]/$cyear $[:pick $dtime 7 15]”}
:if ([:len $dtime] = 14) do={:set dtime “$cyear-$[:pick $dtime 0 5] $[:pick $dtime 6 14]”}
:if ([:len $dtime] = 8) do={:set dtime “$[get date] $dtime”}
:if ([:tostr $1] = “”) do={:set dtime (“$[get date] $[get time]”)}
:local vdoff [:toarray “0,4,5,7,8,10,11,19”]
:local MM [:pick $dtime ($vdoff->2) ($vdoff->3)]
:if ($dtime ~ “…/../…”) do={
:set vdoff [:toarray “7,11,1,3,4,6,12,20”]
:set MM ([:find “xxanebarprayunulugepctovecANEBARPRAYUNULUGEPCTOVEC” [:pick $dtime ($vdoff->2) ($vdoff->3)] -1] / 2)
:if ($MM>12) do={:set MM ($MM - 12)} ; :if ($MM<10) do={:set MM “0$MM”}
}
:return “$[:pick $dtime ($vdoff->0) ($vdoff->1)]-$MM-$[:pick $dtime ($vdoff->4) ($vdoff->5)] $[:pick $dtime ($vdoff->6) ($vdoff->7)]”
}

:local bot “XXXXXXXXXXXXXXXX:XXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXX”
:local ChatID “XXXXXXXXX”
:local myserver “\E2\84\B9 MikroTik $[/system identity get name] $[/system resource get board-name]”
:local scheduleName “LogFilter”

:local startBuf [:toarray [/log find where message~“(login failure|logged in|loop|down|fcs|excessive|system|rebooted|ipsec|ike2)”
or topics~“(error|critical)”]]

:local removeThese [:toarray “”]

:if ([:len [/system scheduler find where name=$scheduleName]] = 0) do={
/log warning “[LogFilter] Alert : Schedule does not exist. Creating schedule …”
/system scheduler add name=$scheduleName interval=60s start-time=12:00:00 on-event=LogFilter
/log warning “[LogFilter] Alert : Schedule created!”
}

:local lastTime [/system scheduler get [find where name=$scheduleName] comment]
:local currentTime “”
:local message “”
:local output “”

:local keepOutput false
:if ([:len $lastTime] = 0) do={:set keepOutput true}

:local counter 0

:foreach i in=$startBuf do={
:local keepLog true
:foreach j in=$removeThese do={
:if ([/log get $i message] ~ “$j”) do={:set keepLog false}
}

:if ($keepLog = true) do={
    :set message     [/log get $i message]
    :set currentTime [$anydate2isodate [/log get $i time]]
    :if ($keepOutput = true) do={
        :set output "$output------------------------------%0A$currentTime $message%0A"
    }
    :if ($currentTime = $lastTime) do={
        :set keepOutput true
        :set output     ""
    }
}

:if ($counter = ([:len $startBuf] - 1)) do={
    :if ($keepOutput = false) do={
        :if ([:len $message] > 0) do={
        :set output "$output$currentTime $message"
        }
    }
}

:set counter ($counter + 1)

}

if ([:len $output] > 0) do={
/system scheduler set [find where name=$scheduleName] comment=$currentTime
/tool fetch url=“https://api.telegram.org/bot$bot/sendMessage\3Fchat_id=$ChatID&text=$myserver $output” keep-result=no
}