Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save xdenb43/b6c5044baccd8c8136d40b40adf7d3a0 to your computer and use it in GitHub Desktop.

Select an option

Save xdenb43/b6c5044baccd8c8136d40b40adf7d3a0 to your computer and use it in GitHub Desktop.
Mikrotik forward selected log events to Telegram bot

logEventTGInformer | by xdenb43
Sends log events filtered by condition(s) to specific topic of telegram super-group

UPDATE HISTORY:
15.05.2026 version 2:
---- switch from unstable markdown to html format
---- improve logic
---- tested on RoS 7.22.3

Specs

  • Created to post messages to dedicated topic of the specified supergroup telegram instance
  • Default filtering conditions: topics~"(error|critical|netwatch)" || message~"([fF]ailure|router rebooted|checkOSUpdate)"
  • NO time-format related troubles, mikrotik internal function totime used
  • Executes every 60 seconds
  • Uses limit to 4096 message symbols

Logic

  • Adds scheduler automatically with the first manual execution
  • Selects all log events then filter by specified conditions starting from last successfull execution time
  • Saves last successfull execution time to COMMENT of the scheduled task

How to use

  • Create telegram bot and connect to your channel/group/supergorup before usage
  • Insert your own values instead of $TOKEN, $CHATID and $GROUPTOPICID variables

Warning

Known issue: log text parser failes for keyword "HTTP"

An example of notifications

Screenshot 2025-10-09 205733

Script

# logEventTGInformer | by xdenb43
# 15.05.2026 version 2:
#   - switch from unstable markdown to html format
#   - improve logic
# tested on
#   - RoS 7.22.3

# BEGIN SETUP
:local tgBotToken "$TOKEN";
:local tgChatId "$CHATID";
:local tgTopicId "$GROUPTOPICID";

:local tgUrl ("https://api.telegram.org/bot" . $tgBotToken . "/sendMessage")
:local mikrotId ("&#10071; <code>" . [/system identity get name] . " " . [/system resource get board-name] . "</code> &#10071;")
:local messageHeader ($mikrotId . "\n\n");
:local scheduleName "logEventTGInformer";
:local logsBuffer [:toarray [/log find \
    topics~"(error|critical|netwatch)" || \
    message~"([fF]ailure|router rebooted|checkOSUpdate)"]]
:local ignoreInLog {
    "static dns entry changed"; 
    "changed script settings"; 
    "HTTP"; 
    "changed scheduled script setting"
    }
# Telegram messages can currently hold up to 4KB of text (4096 latin characters).
:local symbolsLimit 4096
:local defaultTime "1970-01-01 00:00:00"
# END SETUP

# SCHEDULER
# warn if schedule does not exist and create it
:if ([:len [/system scheduler find name="$scheduleName"]] = 0) do={
    /log warning "[logEventTGInformer] Alert : Schedule does not exist. Creating schedule ...."
    :delay 1
    /system scheduler add name=$scheduleName interval=60s start-time=startup on-event=logEventTGInformer policy=read,write,test
    /log warning "[logEventTGInformer] Alert : Schedule created!"
}

# CURSOR (time-based)
:local lastCursor [/system scheduler get [find name="$scheduleName"] comment]
:if ([:len $lastCursor] = 0) do={
    :set lastCursor ($defaultTime)
}

# MAIN PART
:local messageText $messageHeader
:local eventCursor
:if ([:len $logsBuffer] > 0) do={
    :foreach line in=$logsBuffer do={
        :local eventTime [/log get $line time]
        :if ([:len $eventTime] != 0) do={
            :local message [:tostr [/log get $line message]]
            :local keepLog true
            
            # ignore filter,
            :foreach j in=$ignoreInLog do={
                :if ($message ~ $j) do={
                    :set keepLog false
                }
            }
            
            :if ($keepLog && ([:totime $eventTime] > [:totime $lastCursor])) do={
                :local tempResult ($eventTime . "\n" . $message . "\n\n")
                
                # lenght limit check
                :if (([:len $messageText] + [:len $tempResult]) < $symbolsLimit) do={
                    :set messageText ($messageText . $tempResult)
                    :set eventCursor $eventTime
                }
            }
        }
    }
}

# send to telegram
:if ([:len $messageText] > [:len $messageHeader]) do={

    /tool fetch \
        url=$tgUrl \
        http-method=post \
        http-header-field="Content-Type: application/json" \
        http-data=("{\"chat_id\":\"" . $tgChatId . "\",\"message_thread_id\":\"" . $tgTopicId . "\",\"text\":\"" . $messageText . "\",\"parse_mode\":\"HTML\"}") \
        keep-result=no
    /system scheduler set [find name=$scheduleName] comment=$eventCursor
}

UI окно System - Scripts

Screenshot 2025-10-09 210029
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment