По умолчанию, логи MikroTik передаются в LibreNMS не совсем корректно:
Поэтому я решил заморочиться и научить syslog-ng правильно разбирать эти сообщения.
При отсутствии желания, или при отсутствии LibreNMS, или в каком еще случае, логи MikroTik можно собирать и просматривать гораздо проще, используя только syslog-ng и LogAnalyzer:
Ну, а для гурманов, вэлком ниже!
Главное на MikroTik'е в «System» → «Logging»:
Все остальное вопросов вызывать не должно.
/system logging action add name=Syslog remote=192.168.0.5 target=remote /system logging add action=Syslog prefix=mk_log topics=info add action=Syslog prefix=mk_log topics=critical add action=Syslog prefix=mk_log topics=error add action=Syslog prefix=mk_log topics=warning
Для начала, нужно открыть пустой файл конфигурации
sudo nano /etc/syslog-ng/conf.d/librenms.conf
и добавить следующую конфигурацию3), сохранить и закрыть
# Written by Nikolay Soloshin (nikolay@soloshin.su) for syslog-ng 3.28.1 on Raspberry Pi OS 11 (bullseye) @ 2023.03 #Options options { create-dirs( yes ); }; #Sources source s_my_udp { network( transport( udp ) flags( no-parse ) ); }; #Filters filter f_my_mikrotik { message( "mk_log" ) and match( '(\w*)\,([\w,]+)\s([\w:.-]*)\s(.*)' type( pcre ) flags( store-matches ) value( "MESSAGE" ) ); }; #Rewriters rewrite r_my_mikrotik { set( "6", value( "t_severity" ) condition( match( "info", value( "2" ) ) ) ); set( "4", value( "t_severity" ) condition( match( "warning", value( "2" ) ) ) ); set( "3", value( "t_severity" ) condition( match( "error", value( "2" ) ) ) ); set( "2", value( "t_severity" ) condition( match( "critical", value( "2" ) ) ) ); set-severity( "${t_severity}" ); set( "${1}", value( "PROGRAM" ) ); set( "${4}", value( "MESSAGE" ) ); }; #Templates template t_my_librenms { template( "$HOST||$FACILITY||$PRIORITY||$LEVEL||$TAG||$R_YEAR-$R_MONTH-$R_DAY $R_HOUR:$R_MIN:$R_SEC||$MSG||$PROGRAM\n" ); template-escape( yes ); }; #Destanations destination d_my_librenms { program( "/opt/librenms/syslog.php" template( t_my_librenms ) ); # file( "/var/log/syslog-ng/debug.log" # template( t_my_librenms ) # ); }; destination d_my_general { file( "/var/log/syslog-ng/remote.log" ); }; #Log paths log { source( s_my_udp ); junction { channel { filter( f_my_mikrotik ); rewrite{ set-facility( "22" ); }; rewrite( r_my_mikrotik ); destination( d_my_librenms ); flags( final ); }; channel { parser { syslog-parser(); }; destination( d_my_general ); flags( final ); }; }; }; # With love from Vladivostok.
В конце нужно перечитать конфигурацию
syslog-ng-ctl reload
Если появились какие-то ошибки, то тут описаны методы их обнаружения.
И так, краткие комментарии к конфигурации выше.
В этом блоке, в принципе, и так все понятно.
В блоке источников он только один на порту 514/UDP и поднят флаг «no-parse», запрещающий автоматический анализ поступающих сообщений.
В этом блоке мы отлавливаем сообщения, в которых содержится метка «mk_log» и заодно разбираем входящее сообщение по группам, используя выражение ReEx. Т.к. поднят флаг «store-matches» все захваченные группы сохраняются и далее доступны по ${0} и ${1}…${255}, как и любой другой макрос. Протестировать использованное выражение можно здесь.
Собственно, самое сердце этой затеи. Здесь мы ищем переданный MikroTik'ом, в виде топика, уровень («Level», «Severity») – «Info», «Warning», «Error» или «Critical» – и, заменяя его на цифровое значение, сохраняем во временной переменной «t_severity», а потом уже переносим в системный макрос, используя функцию «set-severity()».
Но тут у меня возник некий диссонанс – вообще, «Priority» = «Facility» * 8 + «Severity», но почему-то syslog-ng отдает ${LEVEL}4) и ${PRIORITY}, как одно и то же! А в LibreNMS фильтрация возможна только по столбцу «Priority», поэтому выводить реальный «Priority» в виде цифр, к примеру, «172» (21*8+4), идиотизму подобно… Поэтому в интерфейсе LibreNMS всегда «Level» == «Priority».
Далее, исправляем значения макросов «${PROGRAM}» и «${MESSAGE}», на захваченные ранее.
Шаблон стандартный, рекомендованный авторами LibreNMS.
Направлений два – одно, для тех сообщений, которые содержат метку «mk_log», через специальный скрипт в LibreNMS, а второе, для всех остальных сообщений, в файл.
Ну, и на последок, собираем все вышеописанное вместе.
Тут два канала в «junction»5). По одному каналу, обрабатываются сообщения от MikroTik'а, а по второму – все остальные.
В первом канале:
Во втором канале:
Вообще, «junction» в данном контексте использовать бессмысленно, т.к. не используется его функционал, позволяющий временно разделить поток сообщений, по разному их обработать и свести опять в один. Можно было ограничиться просто двумя «channel» – кажется, так то же бы работало. Но сделал так, на будущее.
Обсуждение