Перейти к основному содержанию

NXLog — сбор логов Postfix на Ubuntu

NXLog

Пришла задача организовать сбор логов на почтовом сервере Postfix, который развёрнут на Ubuntu Server. Заказчика интересуют логи отправки писем в виде JSON. Он хочет, чтобы почтовый сервер на каждую отправку письма отчитывался — передавал по curl данные из лога. Поможет нам в этом непростом деле NXLog.

NXLog — это высокопроизводительное многоплатформенное решение для управления логами.

https://nxlog.co

Решение существует как в бесплатном исполнении Community Edition, так и в платном — Enterprise Edition. Сравнение редакций:

https://nxlog.co/community-edition-vs-enterprise-edition

Бесплатная редакция полностью удовлетворяет всем требованиям нашей задачи:

  • получение данных из файла и отправка в файл: модуль Files (im_file, om_file)
  • преобразование данных в JSON: модуль JSON (xm_json)
  • получение и отправка данных по HTTP: модуль HTTP (im_http, om_http)

Функции NXLog

  • Непрерывный сбор событий операционной системы, брандмауэров, коммутаторов, маршрутизаторов, модемов, бизнес-систем и пр.
  • Настраиваемая пересылка событий на другие Syslog сервера.
  • Удаление, фильтрация выбранных или ненужных событий.
  • Поиск, сортировка и настраиваемый фильтр событий.

Установка NXLog

У нас почтовый сервер Postfix работает на ОС Ubuntu 16.04.

nxlog

Мануал по установке на Debian нам подойдёт:

https://docs.nxlog.co/userguide/deploy/debian.html

В списке можно найти нужную для нашей ОС версию дистрибутива. Однако, нам она не очень интересна, потому что не Community Edition.

nxlog

Переходим на страничку загрузки пакетов для CE:

https://nxlog.co/downloads/nxlog-ce#nxlog-community-edition

nxlog

Выбираем пакет для нашей операционной системы и скачиваем.

nxlog

No thanks, just start my download.

Загружаем пакет на сервер и пробуем установить:

dpkg -i nxlog-ce_3.1.2319_ubuntu16_amd64.deb

nxlog

И у нас ничего не устанавливается!

nxlog

Есть проблемы зависимостей. Удаляем пакет:

apt-get remove nxlog-ce

Смотрим в документацию и видим волшебную надпись:

If dpkg returned errors about uninstalled dependencies, use apt-get to install them and complete the NXLog installation.

Ну ладно, ставим зависимости:

apt-get install libapr1
apt-get -f install

Повторно устанавливаем пакет NXLog:

dpkg -i nxlog-ce_3.1.2319_ubuntu16_amd64.deb

nxlog

И у нас всё устанавливается!

Автоматически запускается служба nxlog:

service nxlog status

nxlog

Конфигурационный файл находится по адресу:

/etc/nxlog/nxlog.conf

nxlog

И там сейчас находится пример конфигурации.

nxlog

Данный пример нам не нужен, стираем всё, будем настраивать обработку логов Postfix.

Отправка логов Postfix в файл

Для начала просто убедимся в том, что nxlog работает. Для этого организуем запись логов в файл: /var/log/smtp.log. А данные будем брать из логов Postfix: /var/log/mail.log.

Мы будем преобразовывать данные в формат JSON, в конфиге будет модуль xm_json:

<Extension _json>
    Module  xm_json
</Extension>

Для получения данных из файла /var/log/mail.log используем модуль im_file:

<Input postfix>
    Module  im_file
    File    "/var/log/mail.log"
    <Exec>
        if $raw_event =~ /(?x)^(\S+\ +\d+\ \d+:\d+:\d+)\ (\S+)
                          \ postfix\/(\S+)\[(\d+)\]:\ (.+)$/
        {
            $EventTime = parsedate($1);
            $HostName = $2;
            $SourceName = "postfix";
            $Component = $3;
            $ProcessID = $4;
            $Message = $5;
            if $Component == "smtpd" and
               $Message =~ /(\w+): client=(\S+)\[([\d.]+)\]/
            {
                $QueueID = $1;
                $ClientHostname = $2;
                $ClientIP = $3;
            }
            if $Component == "cleanup" and
               $Message =~ /(\w+): message-id=(<\S+@\S+>)/
            {
                $QueueID = $1;
                $MessageID = $2;
            }
            if $Component == "qmgr" and
               $Message =~/(\w+): from=(<\S+@\S+>), size=(\d+), nrcpt=(\w+)/
            {
                $QueueID = $1;
                $Sender = $2;
                $Size = $3;
                $Nrcpt = $4;
            }
            if $Component == "smtp" and
               $Message =~ /(?x)(\w+):\ to=(<\S+@\S+>),\ relay=([\w.]+)\[([\d.]+)\],
                            \ delay=(\d+),\ status=(\w+)\ \((\d+)\ \w+:\ queued\ as
                            \ (\w+)\)/
            {
                $QueueID = $1;
                $Recipient = $2;
                $RelayHostname = $3;
                $RelayIP = $4;
                $Delay = $5;
                $Status = $6;
                $SMTPCode = $7;
                $QueueIDDelivered = $8;
            }
        }
    </Exec>
</Input>

Целиком взял этот блок из документации.

Для записи данных в файл /var/log/smtp.log используем модуль om_file:

<Output out>
    Module  om_file
    File    "/var/log/smtp.log"
    <Exec>
        if $Component != "smtp" drop();
        to_json();
    </Exec>
</Output>

В итоге получаем:

########################################
# Global directives                    #
########################################
User nxlog
Group nxlog

include /etc/nxlog/nxlog.d/*.conf
LogFile /var/log/nxlog/nxlog.log
LogLevel INFO

########################################
# Modules                              #
########################################

<Extension _json>
    Module  xm_json
</Extension>

<Input postfix>
    Module  im_file
    File    "/var/log/mail.log"
    <Exec>
        if $raw_event =~ /(?x)^(\S+\ +\d+\ \d+:\d+:\d+)\ (\S+)
                          \ postfix\/(\S+)\[(\d+)\]:\ (.+)$/
        {
            $EventTime = parsedate($1);
            $HostName = $2;
            $SourceName = "postfix";
            $Component = $3;
            $ProcessID = $4;
            $Message = $5;
            if $Component == "smtpd" and
               $Message =~ /(\w+): client=(\S+)\[([\d.]+)\]/
            {
                $QueueID = $1;
                $ClientHostname = $2;
                $ClientIP = $3;
            }
            if $Component == "cleanup" and
               $Message =~ /(\w+): message-id=(<\S+@\S+>)/
            {
                $QueueID = $1;
                $MessageID = $2;
            }
            if $Component == "qmgr" and
               $Message =~/(\w+): from=(<\S+@\S+>), size=(\d+), nrcpt=(\w+)/
            {
                $QueueID = $1;
                $Sender = $2;
                $Size = $3;
                $Nrcpt = $4;
            }
            if $Component == "smtp" and
               $Message =~ /(?x)(\w+):\ to=(<\S+@\S+>),\ relay=([\w.]+)\[([\d.]+)\],
                            \ delay=(\d+),\ status=(\w+)\ \((\d+)\ \w+:\ queued\ as
                            \ (\w+)\)/
            {
                $QueueID = $1;
                $Recipient = $2;
                $RelayHostname = $3;
                $RelayIP = $4;
                $Delay = $5;
                $Status = $6;
                $SMTPCode = $7;
                $QueueIDDelivered = $8;
            }
        }
    </Exec>
</Input>

<Output out>
    Module  om_file
    File    "/var/log/smtp.log"
    <Exec>
        if $Component != "smtp" drop();
        to_json();
    </Exec>
</Output>

########################################
# Routes                               #
########################################
<Route postfix>
    Path        postfix => out
</Route>

Перезапускаем службу и смотрим что у нас в логе NXLog.

service nxlog restart
LogFile /var/log/nxlog/nxlog.log

nxlog

А у нас не хватает прав на чтение файла /var/log/mail.log. Дадим права. Я пока тестирую, делаю совсем просто, добавляю пользователя nxlog в группу администраторов:

usermod -a -G adm nxlog

nxlog

Перезапускаем службу и смотрим что у нас в логе NXLog.

service nxlog restart

nxlog

Нет доступа к файлу /var/log/smtp.log. Да у нас просто нет такого файла, создадим.

cd /var/log
touch smtp.log
chown nxlog\: ./smtp.log

nxlog

Перезапускаем службу.

service nxlog restart

И у нас всё заработало.

nxlog

Логи Postfix считываются из файла /var/log/mail.log, преобразуются в JSON и записываются в файл /var/log/smtp.log.

Отправка логов Postfix по HTTP

Модифицируем конфигурацию для отправки логов по HTTP на адрес:

http://test.example.local/api/v1/stats/email
########################################
# Global directives                    #
########################################
User nxlog
Group nxlog

include /etc/nxlog/nxlog.d/*.conf
LogFile /var/log/nxlog/nxlog.log
LogLevel INFO

########################################
# Modules                              #
########################################

<Extension _json>
    Module  xm_json
</Extension>

<Input postfix>
    Module  im_file
    File    "/var/log/mail.log"
    <Exec>
        if $raw_event =~ /(?x)^(\S+\ +\d+\ \d+:\d+:\d+)\ (\S+)
                          \ postfix\/(\S+)\[(\d+)\]:\ (.+)$/
        {
            $EventTime = parsedate($1);
            $HostName = $2;
            $SourceName = "postfix";
            $Component = $3;
            $ProcessID = $4;
            $Message = $5;
            if $Component == "smtpd" and
               $Message =~ /(\w+): client=(\S+)\[([\d.]+)\]/
            {
                $QueueID = $1;
                $ClientHostname = $2;
                $ClientIP = $3;
            }
            if $Component == "cleanup" and
               $Message =~ /(\w+): message-id=(<\S+@\S+>)/
            {
                $QueueID = $1;
                $MessageID = $2;
            }
            if $Component == "qmgr" and
               $Message =~/(\w+): from=(<\S+@\S+>), size=(\d+), nrcpt=(\w+)/
            {
                $QueueID = $1;
                $Sender = $2;
                $Size = $3;
                $Nrcpt = $4;
            }
            if $Component == "smtp" and
               $Message =~ /(?x)(\w+):\ to=(<\S+@\S+>),\ relay=([\w.]+)\[([\d.]+)\],
                            \ delay=(\d+),\ status=(\w+)\ \((\d+)\ \w+:\ queued\ as
                            \ (\w+)\)/
            {
                $QueueID = $1;
                $Recipient = $2;
                $RelayHostname = $3;
                $RelayIP = $4;
                $Delay = $5;
                $Status = $6;
                $SMTPCode = $7;
                $QueueIDDelivered = $8;
            }
        }
    </Exec>
</Input>

<Output http>
    Module              om_http
    URL                 http://test.example.local/api/v1/stats/email
    ContentType         text/plain
    <Exec>
        if $Component != "smtp" drop();
        to_json();
    </Exec>
</Output>


########################################
# Routes                               #
########################################
<Route postfix>
    Path        postfix => http
</Route>

P.S.

Почему-то в документации странный конфиг и регулярное выражение. Переделал регулярку под рабочий вариант:

########################################
# Global directives                    #
########################################
User nxlog
Group nxlog

include /etc/nxlog/nxlog.d/*.conf
LogFile /var/log/nxlog/nxlog.log
LogLevel INFO

########################################
# Modules                              #
########################################

<Extension _json>
    Module  xm_json
</Extension>

<Input postfix>
    Module  im_file
    File    "/var/log/mail.log"
    <Exec>
        if $raw_event =~ /(?x)^(\S+\ +\d+\ \d+:\d+:\d+)\ (\S+)
                          \ postfix\/(\S+)\[(\d+)\]:\ (.+)$/
        {
            $eventTime = parsedate($1);
            $hostName = $2;
            $sourceName = "postfix";
            $component = $3;
            $processId = $4;
            $message = $5;
            if $component == "smtpd" and
               $message =~ /(\w+): client=(\S+)\[([\d.]+)\]/
            {
                $queueId = $1;
                $clientHostname = $2;
                $clientIp = $3;
            }
            if $component == "cleanup" and
               $message =~ /(\w+): message-id=(<\S+@\S+>)/
            {
                $queueId = $1;
                $messageId = $2;
            }
            if $component == "qmgr" and
               $message =~ /(\w+): from=(<\S+@\S+>), size=(\d+), nrcpt=(\w+)/
            {
                $queueId = $1;
                $sender = $2;
                $size = $3;
                $nrcpt = $4;
            }
            if $component == "smtp" and
               $message =~ /(?x)(\w+):\ [host]*\ ?([\w.\ -]*)?\[?[\d.]+\]?\ ?(\w*:?\ ?([\d.\ -]*)?\ (.+)?)/
            {
                $queueId = $1;
                $relayHostname = $2;
                $smtpCode = $4;
                if not defined($4)
                {
                    $smtpInfo = $3;
                } else {
                    $smtpInfo = $5;
                }
            }
            if $component == "smtp" and
               $message =~ /(?x)(\w+):\ to=<(\S+@\S+)>,\ relay=([\w.-]+)\[?([\d.]*)\]?:?(\d*),\ delay=([\d.]+),\ delays=[\d.]+\/[\d.]+\/[\d.]+\/[\d.]+,\ dsn=[\d.]+,\ status=(\w+)\ \(((host|connect)?\ ?[\w.\ -]*\[?[\d.]*\]?[\w\ ]*:\ ?)?([\d.\ -]*)\ (.+)\)/
            {
                $queueId = $1;
                $recipient = $2;
                $relayHostname = $3;
                $relayIp = $4;
                $relayPort = $5;
                $delay = $6;
                $status = $7;
                $smtpCode = $10;
                $smtpInfo = $11;
            }
        }
    </Exec>
</Input>

#<Output out>
#    Module  om_file
#    File    "/var/log/smtp.log"
#    <Exec>
#        if $component != "smtp" drop();
#        #if $relayHostname != "mail.example.com" drop();
#        to_json();
#    </Exec>
#</Output>

<Output http>
    Module              om_http
    URL                 http://test.example.local/api/v1/stats/email
    ContentType         text/plain
    <Exec>
        if $component != "smtp" drop();
        to_json();
    </Exec>
</Output>

########################################
# Routes                               #
########################################
<Route postfix>
    Path        postfix => http
</Route>

#<Route postfix>
#    Path       postfix => out
#</Route>

Теги

 

Похожие материалы

Postfix — ограничить поток исходящих писем

Почтовый сервер postfix ориентирован на максимальную производительность. Если у него есть письмо, то он постарается его как можно быстрее отправить. Но иногда требуется ограничить поток исходящих писем. При этом желательно, чтобы postfix продолжал принимать письма без ограничений, но отправлял их постепенно. Бывает, что провайдер ограничивает ваш сервер и разрешает отправлять, например, не более 300 писем в минуту. 

Теги

Автоматически чистить почтовый ящик из Ubuntu

Понадобилось мне как-то автоматически стирать все письма из почтового ящика. Ящик был на Exchange, автоматически там можно удалять письма, но только в папку "Удалённые", что не совсем то что нужно. Не найдя нормального функционала автоматической очистки папки плюнул и решил с соседнего сервера Ubuntu кроном удалять письма из ящика. Итак, на сервере Ubuntu ставим пакет fetchmail:

Теги