суббота, 7 ноября 2015 г.

Запись access_log nginx в mysql через syslog-ng

На днях озадачился вопросом записи access-лога nginx не в файл, а в СУБД. Прогуглив интернеты нашел один из вариантов решения с использованием syslog-ng, но как его реализовать готовой информации нигде нет.
Ну что ж, вызов принят, погнали!

Что мне понадобилось для реализации: Ubuntu 14.04.03, Nginx, syslog-ng,  MySQL.
Первым делом создаем базу данных, юзера с правами на эту базу, как это делать описывать не буду, статей на эту тему куча.

После делаем табличку в созданной базе.

Create-код для таблички:

CREATE TABLE `log` (
    `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
    `ip` VARCHAR(40) NOT NULL DEFAULT '0.0.0.0',
    `user` VARCHAR(15) NULL DEFAULT NULL,
    `logdate` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
    `method` VARCHAR(8) NULL DEFAULT NULL,
    `file` VARCHAR(200) NOT NULL,
    `proto` VARCHAR(10) NULL DEFAULT NULL,
    `answer` SMALLINT(3) UNSIGNED NULL DEFAULT NULL,
    `bytes` INT(10) UNSIGNED NULL DEFAULT '0',
    `referer` TEXT NULL,
    `user_agent` TINYTEXT NULL,
    `host` VARCHAR(50) NULL DEFAULT '-',
    PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;


Индексы и значения по умолчанию думаю добавите сами. 

Далее приступаем к установке и настройке syslog-ng, ставим дополнительно библиотеку, которую использует syslog-ng для работы с MySQL.

sudo apt-get update
sudo apt-get install syslog-ng libdbd-mysql


После установки приступаем к настройке syslog-ng. Открываем для редактирования файл с конфигом syslog-ng nano /etc/syslog-ng/syslog-ng.conf
 
 У меня получился вот такой конфиг:

#####
#Описываем источник логов
#### 

source nginx_local { udp(ip(127.0.0.1) port(514) tags("nginx"));};

###
#Описываем пункт назначения логов. Для нас это сервер mysql.
#Данные, выделенные жирным шрифтом 
#нужно заполнить самостоятельно
#В моем случае MyTable - это вышесозданная табличка c именем log
###

destination mysql {
sql(type(mysql)
host("localhost") username("MyUser") password("SECRET")
database("My_DataBase")
table("MyTable")
columns("ip", "user", "logdate", "method", "file", "proto" , "answer", "bytes", "referer", "user_agent", "host" )
values("$CLIENT_IP", "$USER", $TIME , "$METHOD", "$FILENAME","$PROTO", $STATUS, $BYTES,  "$REFERER", "$USER_AGENT", "$SERVER_NAME")
);
};


###
#Описываем правла парсинга логов, прилетевших от nginx
###

parser p_nginx {
    csv-parser(columns("CLIENT_IP", "USER", "TIME",
        "METHOD", "FILENAME", "PROTO",
        "STATUS", "BYTES", "REFERER",
        "USER_AGENT", "SERVER_NAME")
         flags(escape-double-char,strip-whitespace)
         delimiters(" ")
         quote-pairs('""[]')
         );
};



###
#Описываем самое главное правило
###

log{
source(nginx_local);
parser(p_nginx);
destination(mysql);
};


Сохраняем файл, и перезапускаем службу командной sudo service syslog-ng restart

И так, осталось настроить NGINX.  
  
Версия NGINX  должна быть 1.7.1 и выше!
 
Открываем главный файл конфигурации NGINX /etc/nginx/nginx.conf и в контекст http добавляем новый logformat с именем formysql.

log_format formysql '$remote_addr  $remote_user $msec $request_method "$request_filename" "$server_protocol" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$server_name"'

Далее настраиваем конфиг хоста, access_log которого хотим писать в СУБД, и в контексте server  добавляем строчку:

access_log syslog:server=127.0.0.1,nohostname formysql;

127.0.0.1 в данном случае - это адрес сервера syslog-ng.

Сохраняем файл, и перазапускаем службу NGINX командой service nginx restart


Вот такое весьма изящное и масштабируемое решение у меня получилось для решения столь нетривиальной задачи.
При использовании материалов статьи ссылка на источник обязательна!