Задача: обеспечить возможность просмотра структурированных по дате создания журналов переписки в публичном "чате", работающем на движке "MU-Conference". Очень полезно для "разбора полётов" между службой технической поддержки и пользователями, в случае возникновения претензий или в самообразовательных целях.
Я знаю два способа сделать это:
Первый - с помощью "бота", внедрённого в конференцию, подслушивающего трафик и сохраняющего его;
Второй - отобразить содержимое директории журнала самого модуля, обеспечивающего работу конференции.
Второй - отобразить содержимое директории журнала самого модуля, обеспечивающего работу конференции.
Мне больше нравится второй путь, хотя бы и потому, что не нужно будет устанавливать лишнее программное обеспечение.
Задача отображения содержимого директорий с текстовыми файлами и содержимого этих самых файлов проста и незатейлива - отдадим её на исполнение легковесному HTTP-серверу Nginx. По идее, всё просто: ставим HTTP-сервер, натравливаем его на директорию с журнальными файлами - готово. Но, при таком подходе мы получим в окно браузера кучу информационного шума, вроде: "пользователь такой-то вошёл в конференцию", "пользователь такой-то вышел из конференции", и так далее, и тому подобное, и так чуть-ли не половину от выводимого содержимого. Нам это ни к чему, следует вырезать лишнее с минимальными усилиями.
Сделаем это с помощью Perl. Да, я в курсе того, что встроенный в Nginx Perl исполняется как блокирующий процесс и резко снизит отзывчивость при отдаче контента, но ничего лучше не придумал.
В пакете Nginx для Debian Lenny поддержка Perl не предусмотрена. Стало быть, нужно собрать свой пакет. Для создания рабочего окружения (скрипты инициализации, конфигурационные файлы, файлы журналов и тому подобного) я рекомендовал бы предварительно установить пакет Nginx, идущий с дистрибутивом Debian. Меньше возни с последующей настройкой:
# aptitude install nginx
Запустим сервер. Он запишет что-нибудь в свои файлы и те не будут удалены при последующем удалении самого приложения, как подвергшиеся изменениям:
# /etc/init.d/nginx start
Инсталлируем минимально необходимый набор пакетов Perl (если он уже не стоит в более расширенном варианте, разумеется):
# aptitude install perl-base libperl-dev
Устанавливаем утилиту, что соберет нам после сборки из исходных кодов пакет, готовый для установки в систему:
# aptitude install checkinstall
Инсталлятор потянет кроме указанных продуктов ещё как минимум build-essential, bzip, dpkg-dev, g++, make.
Устанавливаем пакеты, требующиеся свежему Nginx:
# aptitude install libpcre3 libpcre3-dev libssl-dev zlib1g-dev
Скачиваем дистрибутив по ссылке полученной с сайта разработчиков:
# cd /usr/src
# wget http://sysoev.ru/nginx/nginx-0.8.53.tar.gz
# wget http://sysoev.ru/nginx/nginx-0.8.53.tar.gz
Распаковываем архив. Переходим в корень директории с исходными кодами:
# tar -xvf nginx-0.8.53.tar.gz
# cd ./nginx-0.8.53
# cd ./nginx-0.8.53
Смотрим, не придумали ли разработчики чего нового, нет ли несовместимых с прежней конфигурацией ключей:
# ./configure --help
Проверяем, удовлетворяет ли наша система зависимостям устанавливаемого программного обеспечения:
# ./configure --prefix=/var/lib/nginx --sbin-path=/usr/sbin --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx.lock --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log \
--user=www-data --group=www-data \
--with-cc-opt="-I /usr/include" --with-ld-opt="-L /usr/lib" \
--http-proxy-temp-path=/var/cache/nginx \
--with-http_realip_module --with-http_gzip_static_module --with-http_stub_status_module --with-http_perl_module --with-http_ssl_module \
--without-http_sub_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --without-http_geo_module --without-http_ssi_module --without-http_empty_gif_module --without-http_browser_module --without-http_memcached_module
--user=www-data --group=www-data \
--with-cc-opt="-I /usr/include" --with-ld-opt="-L /usr/lib" \
--http-proxy-temp-path=/var/cache/nginx \
--with-http_realip_module --with-http_gzip_static_module --with-http_stub_status_module --with-http_perl_module --with-http_ssl_module \
--without-http_sub_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --without-http_geo_module --without-http_ssi_module --without-http_empty_gif_module --without-http_browser_module --without-http_memcached_module
Вывод конфигуратора "говорящий" и явно даёт понять, успешно ли прошла процедура.
Компилируем продукт:
# checkinstall -D --install=no --pkggroup=Nginx --pkgname=nginx-perl --pkgversion=0.8.53 --pkgrelease=1 --pkgsource=sysoev.ru --maintainer=your@mail.com make install
На выходе утилиты получаем готовый пакет, уложенный в директории с исходными кодами, если не было иных указаний на путь сохранения. Устанавливаем полученный пакет:
Done. The new package has been saved to
/usr/src/nginx-0.8.53/nginx-perl_0.8.53-1_i386.deb
You can install it in your system anytime using:
dpkg -i nginx-perl_0.8.53-1_i386.deb
/usr/src/nginx-0.8.53/nginx-perl_0.8.53-1_i386.deb
You can install it in your system anytime using:
dpkg -i nginx-perl_0.8.53-1_i386.deb
Останавливаем и удаляем пакет работающего ранее Nginx:
# /etc/init.d/nginx stop
# aptitude remove nginx
# aptitude remove nginx
Устанавливаем подготовленный нами пакет Nginx+Perl:
# dpkg -i ./nginx-perl_0.8.53-1_i386.deb
Делаем резервные копии затрагиваемых нами конфигурационных файлов:
# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.dist
Перейдем к конфигурированию Nginx.
Общая конфигурация Nginx находится в файле "/etc/nginx/nginx.conf", конфигурации хостов и сайтов описываются в файлах, располагающихся в директориях "/etc/nginx/conf.d." и "/etc/nginx/sites-enabled.", подключаемых с помощью директив "include /etc/nginx/conf.d/*.conf;" и "include /etc/nginx/sites-enabled/*;".
Приведём общий конфигурационный файл "/etc/nginx/nginx.conf" к следующему виду:
# Указываем пользователя и группу, от чьего имени запускается Nginx
user www-data www-data;
# Количество запускаемых рабочих процессов приравняем к количеству процессорных ядер на нашем сервере
worker_processes 4;
# Указываем месторасположение журнального файла сообщений об ошибках
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
# Подключаем описание типов файлов
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Месторасположение журнального файла событий доступа
access_log /var/log/nginx/access.log;
sendfile on;
keepalive_timeout 65;
tcp_nodelay on;
# Запрещаем сообщать версию Nginx в ответе клиенту
server_tokens off;
# Подключаем файлы описания дополнительных конфигураций
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
user www-data www-data;
# Количество запускаемых рабочих процессов приравняем к количеству процессорных ядер на нашем сервере
worker_processes 4;
# Указываем месторасположение журнального файла сообщений об ошибках
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
# Подключаем описание типов файлов
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Месторасположение журнального файла событий доступа
access_log /var/log/nginx/access.log;
sendfile on;
keepalive_timeout 65;
tcp_nodelay on;
# Запрещаем сообщать версию Nginx в ответе клиенту
server_tokens off;
# Подключаем файлы описания дополнительных конфигураций
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Создаем файл конфигурации виртуального хоста "log.conference.xmpp.local":
# touch /etc/nginx/sites-available/log.conference.xmpp.local
Приводим его к следующему виду:
# Указываем на месторасположение самодельных модулей Perl
perl_modules /var/lib/nginx/perl;
perl_require cut-strings.pl;
server {
listen *:80;
server_name log.conference.xmpp.local;
# Указываем кодировку отдаваемых страниц
charset utf-8;
# Указываем корень нашего web-ресурса
root /var/www/log.conference.xmpp.local;
# Запрещаем отдавать кому бы то ни было файлы .htaccess и .htpasswd
location ~* /\.ht {
deny all;
}
location / {
# Размещаем вызов процедуры Perl в самом начале обработки обращения к ресурсу
perl cutter::handler;
# Учим Nginx отображать содержимое директории и отдавать файлы
autoindex on;
autoindex_exact_size on;
autoindex_localtime on;
# Ограничиваем доступ к ресурсу
allow 192.168.0.0/16;
deny all;
}
}
perl_modules /var/lib/nginx/perl;
perl_require cut-strings.pl;
server {
listen *:80;
server_name log.conference.xmpp.local;
# Указываем кодировку отдаваемых страниц
charset utf-8;
# Указываем корень нашего web-ресурса
root /var/www/log.conference.xmpp.local;
# Запрещаем отдавать кому бы то ни было файлы .htaccess и .htpasswd
location ~* /\.ht {
deny all;
}
location / {
# Размещаем вызов процедуры Perl в самом начале обработки обращения к ресурсу
perl cutter::handler;
# Учим Nginx отображать содержимое директории и отдавать файлы
autoindex on;
autoindex_exact_size on;
autoindex_localtime on;
# Ограничиваем доступ к ресурсу
allow 192.168.0.0/16;
deny all;
}
}
Создаём домик для скриптов Perl:
# mkdir -p /var/lib/nginx/perl
# touch /var/lib/nginx/perl/cut-strings.pl
# chown -R www-data:www-data /var/lib/nginx/perl
# touch /var/lib/nginx/perl/cut-strings.pl
# chown -R www-data:www-data /var/lib/nginx/perl
Пишем модуль с процедурой изменения "на лету" запрашиваемого ресурса:
# cat /var/lib/nginx/perl/cut-strings.pl
package cutter;
use nginx;
sub handler {
my $resource = shift;
# Отлавливаем ситуацию, когда запрошенный ресурс - текстовый файл
if ( -T ($resource->filename) ) {
# Инициируем сеанс передачи данных клиенту
$resource->send_http_header;
# Открываем для чтения запрашиваемый клиентом файл
open(FLID, $resource->filename) || die "Error";
# Перебираем последовательно все строки запрашиваемого файла
while(<FLID>) {
# Применяем к локальной переменной "$test" значение последней переменной "по умолчанию" "$_", используемой Perl при чтении данных из файла (какой-то хитрый способ Perl, суть которого мне не до конца ясна)
my $test = $_;
# Отлавливаем интересующие нас строк и выводим их в поток передачи клиенту
if ($test =~ m/<span class=\"nick\">/i ) {
$resource->print($test);
}
}
# Закрываем сеанс работы с файлом
close(FLID);
# Завершаем соединение к клиентом
return OK;
} else {
# ...иначе - передаём управление Nginx (для просмотра содержимого директории или выдачи затесавшегося не текстового файла)
return DECLINED;
}
}
1;
use nginx;
sub handler {
my $resource = shift;
# Отлавливаем ситуацию, когда запрошенный ресурс - текстовый файл
if ( -T ($resource->filename) ) {
# Инициируем сеанс передачи данных клиенту
$resource->send_http_header;
# Открываем для чтения запрашиваемый клиентом файл
open(FLID, $resource->filename) || die "Error";
# Перебираем последовательно все строки запрашиваемого файла
while(<FLID>) {
# Применяем к локальной переменной "$test" значение последней переменной "по умолчанию" "$_", используемой Perl при чтении данных из файла (какой-то хитрый способ Perl, суть которого мне не до конца ясна)
my $test = $_;
# Отлавливаем интересующие нас строк и выводим их в поток передачи клиенту
if ($test =~ m/<span class=\"nick\">/i ) {
$resource->print($test);
}
}
# Закрываем сеанс работы с файлом
close(FLID);
# Завершаем соединение к клиентом
return OK;
} else {
# ...иначе - передаём управление Nginx (для просмотра содержимого директории или выдачи затесавшегося не текстового файла)
return DECLINED;
}
}
1;
Указываем символической ссылкой Nginx на доступную конфигурацию виртуального хоста:
# ln -s /etc/nginx/sites-available/log.conference.xmpp.local /etc/nginx/sites-enabled/log.conference.xmpp.local
Перезапускаем Nginx:
# /etc/init.d/nginx restart
По завершению конфигурирования Nginx закрываем от постороннего взгляда директорию конфигурации:
# chown -R root:root /etc/nginx
# chmod -R o-rwx /etc/nginx
# chmod -R o-rwx /etc/nginx
23 февраля 2011 в 15:12
23 февраля 2011 в 17:32