Application: "Bacula Director v7", "Zabbix v3.4".
Задача: наладить посредством системы мониторинга "Zabbix" отслеживание текущего состояния компонентов и задач централизованной системы резервного копирования "Bacula", хранения истории отработанных заданий и уведомления о сбоях в процессе их исполнения.
Общий принцип действия выработанного решения таков:
1. Каждый час "Zabbix" обращается за списком актуальных задач к "Zabbix Agent"-у на стороне сервера "Bacula", ожидая его в JSON-массиве.
2. Для полученного перечня объектов мониторинга сервером "Zabbix", в соответствии с заготовками в специализированном шаблоне, в соответствии со спецификацией "Low-Level Discovery (LLD)", создаются необходимые элементы и подэлементы.
3. Практически все запросы обрабатываются запускаемыми "Zabbix Agent"-ом самодельными скриптами, извлекающими данные через CLI-интерфейс "Bacula".
2. Для полученного перечня объектов мониторинга сервером "Zabbix", в соответствии с заготовками в специализированном шаблоне, в соответствии со спецификацией "Low-Level Discovery (LLD)", создаются необходимые элементы и подэлементы.
3. Практически все запросы обрабатываются запускаемыми "Zabbix Agent"-ом самодельными скриптами, извлекающими данные через CLI-интерфейс "Bacula".
Получившееся полностью автоматизированное решение отслеживает состояние системы резервного копирования по следующим позициям:
Наличие сервисов "Bacula Dir", "Bacula SD" & "Bacula DB" (item/trigger, every 30sec);
Статус задач (item, every 5min);
Длительность исполнения задач (item/graph, every 2hour);
Объём загруженных при исполнении задач данных (item/graph, every 2hour);
Количество загруженных при исполнении задач файлов (item/graph, every 2hour);
Уведомление о неудачном завершении задач (trigger);
Уведомление об активности задач в данный момент (trigger);
Уведомление о длительном отсутствии данных о статусе задач (trigger, 6hour);
Уведомление о длительном перерыве в исполнении задач (trigger, 15 day).
Статус задач (item, every 5min);
Длительность исполнения задач (item/graph, every 2hour);
Объём загруженных при исполнении задач данных (item/graph, every 2hour);
Количество загруженных при исполнении задач файлов (item/graph, every 2hour);
Уведомление о неудачном завершении задач (trigger);
Уведомление об активности задач в данный момент (trigger);
Уведомление о длительном отсутствии данных о статусе задач (trigger, 6hour);
Уведомление о длительном перерыве в исполнении задач (trigger, 15 day).
Предварительная подготовка.
На стороне сервера резервного копирования должен быть установлен "Zabbix Agent" и CLI-интерфейс для "Bacula", а также утилита проверки синтаксиса JSON:
# aptitude install zabbix-agent bconsole jq
Перед всеми дальнейшими работами потребуется применить заранее подготовленный мною специализированный шаблон для системы мониторинга:
Очень желательно сразу проверить возможность прохождения запроса от сервера мониторинга "Zabbix" к запущенному на стороне системы резервного копирования "Zabbix Agent"-у:
# sudo -u zabbix -s zabbix_get -s bacula.example.net -k "proc.num[bacula-dir]"
Настраиваем аутентификацию между компонентами.
Прежде чем приступать к выстраиванию логики сбора данных, обеспечим к таковым ограниченный доступ (только "на чтение", и не ко всем подсистемам) агенту мониторинга "Zabbix".
В конфигурации "Bacula Director" заведём отдельную точку входа со своими параметрами аутентификации для утилиты "bconsole", через которую к "Bacula" будет подключатся "Zabbix Agent":
# vi /etc/bacula/bacula-dir.conf
....
# # Блок описания подсистем управления и мониторинга:
Console {
Name = "zabbix-agent.local"
Password = "zabbixConsolePassword"
# Разрешаем исполнение только перечисленных команд
Command ACL = show,list,llist,quit
# Явно разрешаем получать данные о любых задачах и обращаться к любым каталогам хранения метаданных
Job ACL = *all*
Catalog ACL = *all*
}
....
# # Блок описания подсистем управления и мониторинга:
Console {
Name = "zabbix-agent.local"
Password = "zabbixConsolePassword"
# Разрешаем исполнение только перечисленных команд
Command ACL = show,list,llist,quit
# Явно разрешаем получать данные о любых задачах и обращаться к любым каталогам хранения метаданных
Job ACL = *all*
Catalog ACL = *all*
}
....
Проверяем корректность конфигурации средствами самого "Bacula" и применяем таковую:
# bacula-dir -c /etc/bacula/bacula-dir.conf -t
# /etc/init.d/bacula-director reload
# /etc/init.d/bacula-director reload
Мне представляется естественным, что клиентский конфигурационный файл утилиты "bconsole" должен быть расположен поближе к источнику запросов - в директории настроек "Zabbix Agent"-а:
# vi /etc/zabbix/bconsole.conf && chown zabix:zabbix /etc/zabbix/bconsole.conf && chmod o-rwx /etc/zabbix/bconsole.conf
#
# Bacula Console Configuration File, intended for Zabbix-Agent
#
# Указываем на сервис "Director Daemon", к которому нужно подключится:
Director {
Name = bacula.example.net
Address = bacula.example.net
DIRport = 9101
# (несмотря на то, что в действительности аутентификация осуществляется в контексте блока "Console", в блоке описания "Director" тоже требуется указание параметра "Password" - он не должен ничему соответствовать, просто необходимо присутствие его определения)
Password = "XXXXXXXXXXX"
}
# Параметры аутентификации клиента при подключении к "Director Daemon":
Console {
Name = zabbix-agent.local
Password = "zabbixConsolePassword"
Director = bacula.example.net
}
# Bacula Console Configuration File, intended for Zabbix-Agent
#
# Указываем на сервис "Director Daemon", к которому нужно подключится:
Director {
Name = bacula.example.net
Address = bacula.example.net
DIRport = 9101
# (несмотря на то, что в действительности аутентификация осуществляется в контексте блока "Console", в блоке описания "Director" тоже требуется указание параметра "Password" - он не должен ничему соответствовать, просто необходимо присутствие его определения)
Password = "XXXXXXXXXXX"
}
# Параметры аутентификации клиента при подключении к "Director Daemon":
Console {
Name = zabbix-agent.local
Password = "zabbixConsolePassword"
Director = bacula.example.net
}
Проверяем корректность конфигурации средствами самого CLI-агента "Bacula":
# bconsole -c /etc/zabbix/bconsole.conf -t
Есть смысл сразу удостовериться, действуют ли ограничения - уж не буду здесь о методике.
Настраиваем "Zabbix Agent".
Учитывая то, что процедуры сбора данных и отправки их на сервер мониторинга осуществляется клиентом "Zabbix", то конфигурационные файл и скрипты расположим в его директории:
# mkdir -p /etc/zabbix/scripts
# mkdir -p /etc/zabbix/zabbix_agents.conf.d
# mkdir -p /etc/zabbix/zabbix_agents.conf.d
# vi /etc/zabbix/zabbix_agentd.conf.d/bacula.conf
UserParameter=bacula.jobs.discovery, /etc/zabbix/scripts/bacula_discovery.sh
UserParameter=bacula.jobs.check[*], /etc/zabbix/scripts/bacula_check_job.sh $1 $2 $3 $4
UserParameter=bacula.jobs.check[*], /etc/zabbix/scripts/bacula_check_job.sh $1 $2 $3 $4
Подстраховываясь, закрываем к настройкам и скриптам "Zabbix" доступ посторонним:
# chown -R zabbix:zabbix /etc/zabbix
# chmod o-rwx /etc/zabbix
# chmod o-rwx /etc/zabbix
Для применения изменений в конфигурации "Zabbix Agent" необходимо перезапустить:
# /etc/init.d/zabbix-agent restart
Пишем и тестируем скрипт "Zabbix Auto Discovery (LLD)".
Подготовим простейший Bash-скрипт, по запросу подключающийся к "Bacula", запрашивающий перечень разрешённых к исполнению задач резервного копирования и формирующий соответствующий требования "Zabbix Auto Discovery" JSON-массив:
# cd /etc/zabbix/scripts
# vi ./bacula_discovery.sh && chown zabix:zabbix ./bacula_discovery.sh && chmod ug+x ./bacula_discovery.sh
# vi ./bacula_discovery.sh && chown zabix:zabbix ./bacula_discovery.sh && chmod ug+x ./bacula_discovery.sh
#!/bin/bash
# usage: ./bacula_discovery.sh
# Задаём переменные рабочего окружения
BCON="bconsole -c /etc/zabbix/bconsole.conf"
LOG="/var/log/zabbix-agent/zabbix-bacula-error.log"
DATE=$(date +"%Y-%m-%d.%H:%M:%S")
# Проверяем наличие ожидаемых утилит
[ -x "$(command -v bconsole)" ] && [ -x "$(command -v jq)" ] || { echo "${DATE}: Не обнаружены необходимые для работы утилиты. Процедура создания списка активных заданий резервного копирования прервана." >> ${LOG}; exit 1; }
# Формируем список имён активных заданий "Bacula"
JOBS=$(echo -e "show job\n.\nquit" | ${BCON} | grep -i -E "^job:.*enabled[ \t]*=[ \t]*1" | awk '{print $2}' | grep -i -E "^name[ \t]*=[ \t]*.*$" | awk -F "=" '{print $2}')
# Если список имён заданий не пуст, то формируем JSON для "Zabbix Low-Level Discovery (LLD)"
if [ ! -z "${JOBS}" ] ; then
# Задаём начало JSON
JSONZLLD="{\"data\":["
FIRST=1
# Перебираем имена заданий
for JOB in ${JOBS} ; do
# Пропускаем обработку некоторых задач (заготовку для "восстановления", например)
[ $(echo ${JOB} | grep "restore") ] && continue
# Проставляем разделитель между элементами JSON
if [ ${FIRST} == 0 ] ; then
JSONZLLD=${JSONZLLD}","
fi
FIRST=0
# Вводим имя задания в качестве элмента JSON
JSONZLLD=${JSONZLLD}"{\"{#JOB}\":\"${JOB}\"}"
done
# Завершаем JSON
JSONZLLD=${JSONZLLD}"]}"
# Проверяем синтаксическую корректность JSON
if jq -e . 1>/dev/null 2>&1 <<< "${JSONZLLD}" ; then
# Отдаём JSON на STDOUT
echo ${JSONZLLD}
fi
fi
exit ${?}
# usage: ./bacula_discovery.sh
# Задаём переменные рабочего окружения
BCON="bconsole -c /etc/zabbix/bconsole.conf"
LOG="/var/log/zabbix-agent/zabbix-bacula-error.log"
DATE=$(date +"%Y-%m-%d.%H:%M:%S")
# Проверяем наличие ожидаемых утилит
[ -x "$(command -v bconsole)" ] && [ -x "$(command -v jq)" ] || { echo "${DATE}: Не обнаружены необходимые для работы утилиты. Процедура создания списка активных заданий резервного копирования прервана." >> ${LOG}; exit 1; }
# Формируем список имён активных заданий "Bacula"
JOBS=$(echo -e "show job\n.\nquit" | ${BCON} | grep -i -E "^job:.*enabled[ \t]*=[ \t]*1" | awk '{print $2}' | grep -i -E "^name[ \t]*=[ \t]*.*$" | awk -F "=" '{print $2}')
# Если список имён заданий не пуст, то формируем JSON для "Zabbix Low-Level Discovery (LLD)"
if [ ! -z "${JOBS}" ] ; then
# Задаём начало JSON
JSONZLLD="{\"data\":["
FIRST=1
# Перебираем имена заданий
for JOB in ${JOBS} ; do
# Пропускаем обработку некоторых задач (заготовку для "восстановления", например)
[ $(echo ${JOB} | grep "restore") ] && continue
# Проставляем разделитель между элементами JSON
if [ ${FIRST} == 0 ] ; then
JSONZLLD=${JSONZLLD}","
fi
FIRST=0
# Вводим имя задания в качестве элмента JSON
JSONZLLD=${JSONZLLD}"{\"{#JOB}\":\"${JOB}\"}"
done
# Завершаем JSON
JSONZLLD=${JSONZLLD}"]}"
# Проверяем синтаксическую корректность JSON
if jq -e . 1>/dev/null 2>&1 <<< "${JSONZLLD}" ; then
# Отдаём JSON на STDOUT
echo ${JSONZLLD}
fi
fi
exit ${?}
Пример получаемого в ответ на запрос JSON-файла для "Zabbix LLD", с обнаруженными активными задачами:
{
"data":[
{"{#JOB}":"client0.example.net"},
{"{#JOB}":"clientX.example.net"}
]
}
"data":[
{"{#JOB}":"client0.example.net"},
{"{#JOB}":"clientX.example.net"}
]
}
Есть смысл сразу проверить корректность срабатывания скрипта "Auto Discovery (LLD)":
# sudo -u zabbix -s zabbix_get -s bacula.example.net -k "bacula.jobs.discovery"
Пишем и тестируем скрипт получения запрашиваемых параметров.
Создаём специализированный Bash-скрипт, принимающий от "Zabbix Agent"-а запросы на получение данных по ряду интересующих нас параметров, обращающийся к CLI-утилите "Bacula" и нормализующий их перед выдачей:
# cd /etc/zabbix/scripts
# vi ./bacula_check_job.sh && chown zabix:zabbix ./bacula_check_job.sh && chmod ug+x ./bacula_check_job.sh
# vi ./bacula_check_job.sh && chown zabix:zabbix ./bacula_check_job.sh && chmod ug+x ./bacula_check_job.sh
#!/bin/bash
# usage: ./bacula_check_job.sh "jobName" "jobParam" {jobLevel}
# Задаём переменные рабочего окружения
BCON="bconsole -c /etc/zabbix/bconsole.conf"
LOG="/var/log/zabbix-agent/zabbix-bacula-error.log"
DATE=$(date +"%Y-%m-%d.%H:%M:%S")
# Проверяем наличие ожидаемых утилит
[ -x "$(command -v bconsole)" ] || { echo "${DATE}: Не обнаружены необходимые для работы утилиты. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1; }
# Проверяем корректность вводимых данных и выводим подсказку в журнал событий при необходимости
#
JINAME="${1}"
JIPARAM="${2}"
JILEVEL="${3}"
#
[ ! "${JINAME}" ] && { echo "${DATE}: Запрос: \"$(basename $0) $@\". Не указано имя задания резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1; }
#
[ ! "${JIPARAM}" ] && { echo "${DATE}: Запрос: \"$(basename $0) $@\". Не указан запрашиваемый параметр задания резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1; }
#
[ "${JILEVEL}" ] && [[ "${JILEVEL}" != "F" && "${JILEVEL}" != "D" && "${JILEVEL}" != "I" ]] && { echo "${DATE}: Запрос: \"$(basename $0) $@\". Некорректно указан уровень задания резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1; }
# Запрашиваем упрощённую статистику задания, опираясь на его имя
JOBLINE=$(echo -e "list job=${JINAME}\n.\nquit" | ${BCON})
# Первым отрабатываем самые простые запросы о статусах текущего (последнего в списке) задания
if [ "${JIPARAM}" == "jobstatus" ] ; then
ANSWER=$(echo -e "${JOBLINE}" | grep '^|' | tail -n1 | awk -F "|" '{print $9}' | sed -e 's/[ ]*//g')
elif [ "${JIPARAM}" == "lastexecution" ] ; then
STARTTIME=$(echo -e "${JOBLINE}" | grep '^|' | tail -n1 | awk -F "|" '{print $4}' | xargs -I{} date -d "{}" +%s)
let "ANSWER = $(date +%s) - STARTTIME"
# (для дальнейшей выгрузки статистики по отработанным задачам необходимо указание их уровня)
elif [ ! -z "${JILEVEL}" ] ; then
# Для получения статистики выясняем идентификатор последнего успешно завершённого задания
JOBID=$(echo -e "list job=${JINAME}\n.\nquit" | ${BCON} | grep '^|' | grep -i -E ".*\|[ \t]*B[ \t]*\|[ \t]*${JILEVEL}[ \t]*\|.*\|[ \t]*T[ \t]*\|[ \t]*$" | tail -n1 | awk -F "|" '{print $2}' | sed -e 's/[ \t]*//g' | sed -e 's/,//g')
if [ ! -z "${JOBID}" ] ; then
# Запрашиваем расширенную статистику задания, опираясь на его идентификатор
JOBLONG=$(echo -e "llist jobid=${JOBID}\n.\nquit" | ${BCON})
# Формируем запросы и обрабатываем ответы с вычленением значений запрашиваемых параметров
if [ ! -z "${JOBLONG}" ] ; then
case "${JIPARAM}" in
"jobbytes")
ANSWER=$(echo -e "${JOBLONG}" | grep -i -E "^[ \t]*jobbytes:" | awk -F ":" '{print $2}' | sed -e 's/[ \t]*//g' | sed -e 's/,//g')
;;
"jobfiles")
ANSWER=$(echo -e "${JOBLONG}" | grep -i -E "^[ \t]*jobfiles:" | awk -F ":" '{print $2}' | sed -e 's/[ \t]*//g' | sed -e 's/,//g')
;;
"duration")
STARTTIME=$(echo -e "${JOBLONG}" | grep -i -E "^[ \t]*starttime:" | awk -F "starttime:" '{print $2}' | xargs -I{} date -d "{}" +%s)
ENDTIME=$(echo -e "${JOBLONG}" | grep -i -E "^[ \t]*endtime:" | awk -F "endtime:" '{print $2}' | xargs -I{} date -d "{}" +%s)
let "ANSWER = ENDTIME - STARTTIME"
;;
*) echo "${DATE}: Запрос: \"$(basename $0) $@\". Некорректно указан запрашиваемый параметр задания резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1; ;;
esac
else
echo "${DATE}: Запрос: \"$(basename $0) $@\". Не получен ответ на запрос идентификатора и расширенного описания задания от подсистемы резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1;
fi
fi
else
echo "${DATE}: Запрос: \"$(basename $0) $@\". Не указан уровень задания резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1;
fi
# Отдаём значение запрашиваемого параметра (или ничего не делаем если запрашиваемый параметр отсутствует)
[ ! -z "${ANSWER}" ] && echo ${ANSWER}
exit ${?}
# usage: ./bacula_check_job.sh "jobName" "jobParam" {jobLevel}
# Задаём переменные рабочего окружения
BCON="bconsole -c /etc/zabbix/bconsole.conf"
LOG="/var/log/zabbix-agent/zabbix-bacula-error.log"
DATE=$(date +"%Y-%m-%d.%H:%M:%S")
# Проверяем наличие ожидаемых утилит
[ -x "$(command -v bconsole)" ] || { echo "${DATE}: Не обнаружены необходимые для работы утилиты. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1; }
# Проверяем корректность вводимых данных и выводим подсказку в журнал событий при необходимости
#
JINAME="${1}"
JIPARAM="${2}"
JILEVEL="${3}"
#
[ ! "${JINAME}" ] && { echo "${DATE}: Запрос: \"$(basename $0) $@\". Не указано имя задания резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1; }
#
[ ! "${JIPARAM}" ] && { echo "${DATE}: Запрос: \"$(basename $0) $@\". Не указан запрашиваемый параметр задания резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1; }
#
[ "${JILEVEL}" ] && [[ "${JILEVEL}" != "F" && "${JILEVEL}" != "D" && "${JILEVEL}" != "I" ]] && { echo "${DATE}: Запрос: \"$(basename $0) $@\". Некорректно указан уровень задания резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1; }
# Запрашиваем упрощённую статистику задания, опираясь на его имя
JOBLINE=$(echo -e "list job=${JINAME}\n.\nquit" | ${BCON})
# Первым отрабатываем самые простые запросы о статусах текущего (последнего в списке) задания
if [ "${JIPARAM}" == "jobstatus" ] ; then
ANSWER=$(echo -e "${JOBLINE}" | grep '^|' | tail -n1 | awk -F "|" '{print $9}' | sed -e 's/[ ]*//g')
elif [ "${JIPARAM}" == "lastexecution" ] ; then
STARTTIME=$(echo -e "${JOBLINE}" | grep '^|' | tail -n1 | awk -F "|" '{print $4}' | xargs -I{} date -d "{}" +%s)
let "ANSWER = $(date +%s) - STARTTIME"
# (для дальнейшей выгрузки статистики по отработанным задачам необходимо указание их уровня)
elif [ ! -z "${JILEVEL}" ] ; then
# Для получения статистики выясняем идентификатор последнего успешно завершённого задания
JOBID=$(echo -e "list job=${JINAME}\n.\nquit" | ${BCON} | grep '^|' | grep -i -E ".*\|[ \t]*B[ \t]*\|[ \t]*${JILEVEL}[ \t]*\|.*\|[ \t]*T[ \t]*\|[ \t]*$" | tail -n1 | awk -F "|" '{print $2}' | sed -e 's/[ \t]*//g' | sed -e 's/,//g')
if [ ! -z "${JOBID}" ] ; then
# Запрашиваем расширенную статистику задания, опираясь на его идентификатор
JOBLONG=$(echo -e "llist jobid=${JOBID}\n.\nquit" | ${BCON})
# Формируем запросы и обрабатываем ответы с вычленением значений запрашиваемых параметров
if [ ! -z "${JOBLONG}" ] ; then
case "${JIPARAM}" in
"jobbytes")
ANSWER=$(echo -e "${JOBLONG}" | grep -i -E "^[ \t]*jobbytes:" | awk -F ":" '{print $2}' | sed -e 's/[ \t]*//g' | sed -e 's/,//g')
;;
"jobfiles")
ANSWER=$(echo -e "${JOBLONG}" | grep -i -E "^[ \t]*jobfiles:" | awk -F ":" '{print $2}' | sed -e 's/[ \t]*//g' | sed -e 's/,//g')
;;
"duration")
STARTTIME=$(echo -e "${JOBLONG}" | grep -i -E "^[ \t]*starttime:" | awk -F "starttime:" '{print $2}' | xargs -I{} date -d "{}" +%s)
ENDTIME=$(echo -e "${JOBLONG}" | grep -i -E "^[ \t]*endtime:" | awk -F "endtime:" '{print $2}' | xargs -I{} date -d "{}" +%s)
let "ANSWER = ENDTIME - STARTTIME"
;;
*) echo "${DATE}: Запрос: \"$(basename $0) $@\". Некорректно указан запрашиваемый параметр задания резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1; ;;
esac
else
echo "${DATE}: Запрос: \"$(basename $0) $@\". Не получен ответ на запрос идентификатора и расширенного описания задания от подсистемы резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1;
fi
fi
else
echo "${DATE}: Запрос: \"$(basename $0) $@\". Не указан уровень задания резервного копирования. Процедура запроса статуса задания резервного копирования прервана." >> ${LOG}; exit 1;
fi
# Отдаём значение запрашиваемого параметра (или ничего не делаем если запрашиваемый параметр отсутствует)
[ ! -z "${ANSWER}" ] && echo ${ANSWER}
exit ${?}
Аналогично предыдущим этапам проверяем корректность прохождения запросов к "Bacula" от сервера мониторинга "Zabbix":
# sudo -u zabbix -s zabbix_get -s bacula.example.net -k "bacula.jobs.check[client0.example.net,jobbytes,F]"
Оптимизация оборота файлов журналов событий.
Наши самодельные скрипты пишут в свой файл журнала событий, а кроме того конфигурационный файл "Logrotate" для "Zabbix Agent" несовременный - заменяем его на свой, всеобъемлющий:
# vi /etc/logrotate.d/zabbix-agent
/var/log/zabbix-agent/*.log {
weekly
rotate 7
compress
delaycompress
missingok
notifempty
copytruncate
su zabbix zabbix
}
weekly
rotate 7
compress
delaycompress
missingok
notifempty
copytruncate
su zabbix zabbix
}
Проверяем корректность конфигурации "Logrotate":
# logrotate -d /etc/logrotate.d/zabbix-agent