Отправка логов с OpenWRT/LEDE в syslog и обработка событий

Зайчатки разума

Записная книжка айтишника

Отправка логов с OpenWRT/LEDE в syslog и обработка событий

2019-01-13 02:31:22 — Evgeniy Shumilov

  Вдогонку к статье о syslog-ng решил сделать дополнение о том, как завернуть логи с OpenWRT и настроить реакцию на соответствие какому-нибудь фильтру. Дома у меня есть два Xiaomi MiWifi 3G (оказалось крайне доступным и достойным по характеристикам устройством), три штуки Netgear WNR3500L, которые в текущий момент работают в качестве гигабитных свичей в разных частях квартиры и Nexx 3020 для экспериментов. Одним словом, правило для сохранения логов должно быть общее для всех этих устройств, чтобы не писать шесть отдельных конфигурационных файлов. Начать я решил со своего основного Xiaomi роутера с хостнеймом gw01, на котором стоит OpenWRT 18.06.


Настройка роутера

  Есть два пути настройки - через веб интерфейс и через консоль. Первый прост как угол дома. Авторизуемся на роутере, переходим в раздел System -> System и прописываем путь к нашему syslog серверу во вкладке Logging. В принципе, этого достаточно, но тут возникает одна проблема - нам необходимо некое ключевое слово, по которому мы будем фильтровать логи, приходящие именно с OpenWRT таким же образом, как было сделано ранее для докер контейнеров с опцией логирования tag, но в веб интерфейсе такой опции нет, поэтому придётся настраивать через консоль, благо, это не намного сложнее.   Заходим на роутер по ssh и редактируем конфигурационный файл system:

vim /etc/config/system

  В раздел system нам нужно добавить следующие параметры:

        option log_proto 'udp'
        option log_ip '10.11.11.4'
        option log_prefix 'OpenWRT-Routers'                                          
        option conloglevel '7' 
        option cronloglevel '7'

  Если вы не сильны в vi/vim (выход c записью через Esc, затем ввод :wq), есть и другой способ:

uci set system.@system[0].log_proto='udp'
uci set system.@system[0].log_ip='10.11.11.4'
uci set system.@system[0].log_prefix='OpenWRT-Routers'
uci set system.@system[0].conloglevel='7'
uci set system.@system[0].cronloglevel='7'

  После изменения настроек, чтобы они вступили в силу, нужно выполнить

/etc/init.d/log restart

  В официальной документации так же было написано о необходимости затем выплонить

/etc/init.d/system restart

  Но у меня прекрасно заработало и без этого. Для сохранения настроек во флешпамять, выполняем

uci commit

  В описанных выше настройках log_prefix как раз отвечает за то, что будет приходить на наш syslog в поле PROGRAM, что очень удобно для фильтрации. 10.11.11.4 - это адрес моего syslog-ng сервера, у вас он скорее всего будет другим. conloglevel и cronloglevel - это уровни фильтрации для ядра и тех процессов, которые запускаются из cron. Самый низкий - нулевой, самый высокий - восьмой.

Настройка syslog-ng

  Теперь можно заглянуть в логи контейнера syslog-ng. Мы должны увидеть примерно такую запись:

[2019-01-05T10:04:20.894114] Incoming log entry; line='Jan 5 15:04:20 gw01 OpenWRT-Routers: logread[32051]: Logread connected to 10.11.11.4:514' 
[2019-01-05T10:04:20.894234] Setting value; msg='0x55e2eb847c00', name='HOST_FROM', value='gw01.lan' 
[2019-01-05T10:04:20.894270] Setting value; msg='0x55e2eb847c00', name='SOURCE', value='src_net'

  Как мы видим, logd на роутере успешно подключился к нашему syslog-ng. Теперь напишем конфигурационный файл. Для удобства Будем складывать логи в директорию logs/network/%hostname%.

filter f_openwrt { 
    match("OpenWRT-Routers" value("PROGRAM")); 
}; 

destination dst_openwrt { 
    file( "/logs/network/${HOST}/$YEAR-$MONTH-$DAY.log" template("$ISODATE $LEVEL $MSG\n") ); 
}; 

log { 
    source(src_net);
    filter(f_openwrt);
    destination(dst_openwrt); 
};

  И перезагрузим специально предназначенным для этого скриптом

scripts/reload

  В консоли роутера можем проверить отправку логов при помощи команды

logger test123

  Можем убедиться, что всё работает.

$ tail -n 1 logs/network/gw01/2019-01-05.log 
2019-01-05T20:56:52+00:00 notice root: test123

Реакция на события

  А теперь сделаем кое-что поинтереснее - заставим syslog-ng реагировать на какой-нибудь скрипт. Скрипт в свою очередь должен постоянно слушать stdin, иначе вас завалит сообщениями вида

syslog-ng[2673]: POLLERR occurred while idle; fd='12'

  В качестве примера будем дёргать http запросы в момент, когда в логах приходит нужная запись. К url будем добавлять последнее слово из входящей записи. Содержимое scripts/testscripts:

#!/bin/sh 
while read line; do 
    echo "$line" | sed 's#^.* #wget -q -O - http://10.11.11.224:8000/#' | sh 
done < /dev/stdin

  На хосте 10.11.11.224:8000 я подниму тестовый веб сервер. И пусть он отдаёт 404-ю ошибку, но в логах мы будем видеть обращения - это именно то, что нам нужно.

$ python -m SimpleHTTPServer 
Serving HTTP on 0.0.0.0 port 8000 ...

  Далее нам нужен конфигурационный файл для syslog-ng:

filter f_openwrttest { 
    match("test123" value("MESSAGE")) and match("OpenWRT-Routers" value("PROGRAM")); 
};

destination dst_openwrttest { 
    program("/scripts/testscript"); 
}; 

log { 
    source(src_net); 
    filter(f_openwrttest); 
    destination(dst_openwrttest); 
};

  Теперь возвращаемся к консоли любого из роутеров и выполняем:

$ logger test12345 
$ logger test123456

  И в логах веб сервера видим следующее:

[06/Jan/2019 00:48:04] code 404, message File not found 10.11.11.4 - - 
[06/Jan/2019 00:48:04] "GET /test12345 HTTP/1.1" 404 - 10.11.11.4 - - 
[06/Jan/2019 00:48:06] code 404, message File not found 10.11.11.4 - - 
[06/Jan/2019 00:48:06] "GET /test123456 HTTP/1.1" 404 -

  Таким образом мы можем вызывать внешние апи. Например, я могу по наступлению какого-нибудь события, (скажем, разрыва VPN соединения) отправить на ближайшую свою управляемую розетку мелодию главной темы из "Семейства Аддамс" в формате RTTTL, или отправить событие в систему мониторинга, но об этом я напишу как-нибудь в другой раз.


  Ещё я только что добавил к образу две полезных фичи - сжатие и очистку старых логов. Так как ротацией syslog-ng замечательно занимается сам, то очистка и компрессия никакой сложности для реализации не представляют. Я сделал следующим образом - entrypoint при старте запускает в фоновом режиме скрипт scripts/cleaner, который в свою очередь ищет в директории с логами файлы с именем .clean со следующим содержимым:

archive=7
clean=60

  Для данного примера все файлы (кроме самого файла .clean конечно) старше 60-ти дней будут удалены в той же директории и всех поддиректориях. Оставшиеся файлы (кроме того же .clean и файлов с расширением bz2 будут сжаты с помощью bzip2. Скрипт по умолчанию запускается каждые 2 часа.

  Репозиторий лежит всё там же: https://github.com/alive-corpse/es-syslog-ng

Теги: админское, docker, logging

comments powered by Disqus