Все админы рано или поздно сталкиваются с необходимостью приобретения нового принтера. Сразу отмечу, что все что будет написано ниже, будет относиться исключительно к CUPS. Соответственно возникает вопрос, какой принтер брать, на какую нагрузку закладываться? Можно пойти несколькими путями:
Поскольку самым надежным методом определения текущей нагрузки на принтеры является анализ информации содержащейся в файле /var/log/cups/page_log, будем работать с ним. Но, как отмечалось ранее, тут возникает проблема получения информации о заданиях за достаточно длительный срок. Я решил этот вопрос путем складывания данных из page_log в БД MySQL, поскольку на машине где крутится CUPS он уже был.
Для начала определим структуру таблицы, в которую будем складывать записи из page_log. Для этого посмотрим на структуру лога:
Теперь самое интересное, нужно взять данные из лога и положить в БД. Изначально я реализовал это на shell с использованием AWK, но видимо я не очень хорошо знаю AWK, поскольку информация периодически задваивалась. В итоге был написан следующий скрипт на Perl:
#! /usr/bin/perl
use DBI;
use Time::Local;
#Хост MySQL
$dbhost='localhost';
#Пользователь MySQL
$dbuser='user';
#Пароль пользователя MySQL
$dbpass='password';
#IP Сервера CUPS
$CupsIP='192.168.0.10';
#Имя базы MySQL
$dbname='cups_stat';
#Полное имя page_log
$log='/var/log/cups/page_log';
%mnts = (
Jan => "01",
Feb => "02",
Mar => "03",
Apr => "04",
May => "05",
Jun => "06",
Jul => "07",
Aug => "08",
Sep => "09",
Oct => "10",
Nov => "11",
Dec => "12"
);
#Получаем дату и ID последнего задания в базе
#Подключение к DB
$dbh = DBI->connect("DBI:mysql:database=$dbname;host=$dbhost",$dbuser, $dbpass) || die print "Can't connect";
$sth = $dbh->prepare(q{SELECT UNIX_TIMESTAMP(MAX(p_date)), MAX(task_id) FROM tasks_log});
$sth -> execute;
#print $sth."/n";
$cols = $sth->{NUM_OF_FIELDS}; # кол-во строк в таблице
$rows = $sth->rows; # кол-во столбцов в таблице
@FieldNames = @{ $sth->{NAME} }; # массив содержащий названия
# полей таблицы
@row = $sth->fetchrow_array;
$MaxDate=$row[0];
$MaxTaskId=$row[1];
# print $MaxTaskId."->".$MaxDate."\n";
#Открываем лог-файл cups
open (FH,$log)|| die print 'Не могу открыть файл! \n';
while (< FH >)
{
@fields=split(' ');
# print $MaxTaskId." > ".$fields[2]."\n";
#Меняем localhost на IP серевера CUPS
if ($fields[8]=="localhost")
{
$fields[8]=$CupsIP;
}
#Если ID задания из лог-файла больше либо равно ID последнего задания в базе
#и его дата больше даты в базе пишем его в базу.
#Преобразуем формат даты в понятный для MySQL datetime
if ($fields[2]=>$MaxTaskId || ! $MaxTaskId)
{
$year=substr($fields[3],8,4);
$rmon=$mnts{substr($fields[3],4,3)};
$mday=substr($fields[3],1,2);
$sec=substr($fields[3],-2);
$min=substr($fields[3],-5,2);
$hours=substr($fields[3],-8,2);
$udt=$year."-".$rmon."-".$mday." ".substr($fields[3],-8);
$fields[3]=$udt;
$TIME = timelocal($sec, $min, $hours, $mday, $rmon-1, $year);
if ($TIME>$MaxDate)
{
#Создаем запрос SQL и выполняем его
$query="insert into tasks_log (prn_name, user_name, task_id, p_date, page_num, rep_num, host) values('".$fields[0]."','".$fields[1]."','".$fields[2]."','".$fields[3]."','".$fields[5]."','".$fields[6]."','".$fields[8]."')";
$sth = $dbh->prepare(qq{$query});
$sth -> execute;
}
}
}
# Закрываем лог-файл
close(FH);
# Отключаемся от базы
$sth -> finish;
$dbh -> disconnect;
exit;
Дальше прописываем выполнение скрипта в crontab через желаемый промежуток времени. У меня, например, каждые 30 минут.
Для удобства работы с MySQL можно поставить phpmyadmin, в нем же можно и анализировать данные. конструируя запросы. Я для этих целей написал WEB-интерфейс на PHP, получилось вот как то так:
Если кому нужно - пишите, могу выслать. Правда дописано не до конца, лень напала.
UPD: Про WEB-интерфейс читаем тут.
UPD2: Рабочий скрипт лежит тут
- Прикинуть как часто покупаются расходники и исходя из этого приблизительно оценить нагрузку
- Переговорить с пользователями (самый бестолковый вариант)
- Проанализировать лог-файл принт-сервера (тут возникает проблема, поскольку логи, как правило, хранятся весьма ограниченное время и полученные данные могут быть не отражающими реальное положение дел)
- Просто купить тот, который понравился (чего уж греха таить, самый распространенный метод)
Поскольку самым надежным методом определения текущей нагрузки на принтеры является анализ информации содержащейся в файле /var/log/cups/page_log, будем работать с ним. Но, как отмечалось ранее, тут возникает проблема получения информации о заданиях за достаточно длительный срок. Я решил этот вопрос путем складывания данных из page_log в БД MySQL, поскольку на машине где крутится CUPS он уже был.
Для начала определим структуру таблицы, в которую будем складывать записи из page_log. Для этого посмотрим на структуру лога:
HP_LaserJet_P2055dn user 9556 [12/May/2009:14:22:51 +0400] 1 2 - hostЗдесь по порядку:
- HP_LaserJet_P2055dn - имя принтера
- user - имя пользователя
- 9556 - номер задания
- [12/May/2009:14:22:51 +0400] - дата и время печати
- 1 - номер страницы в задании
- 2 - количество копий страницы
- host - хост, с которого производилась печать
CREATE DATABSE `cups_stat`;
USE `cups_stat`;
CREATE TABLE IF NOT EXISTS `tasks_log` (
`id` bigint(10) NOT NULL auto_increment,
`prn_name` varchar(50) NOT NULL,
`user_name` varchar(50) NOT NULL,
`task_id` int(10) NOT NULL,
`p_date` datetime NOT NULL,
`page_num` int(3) NOT NULL,
`rep_num` int(3) NOT NULL,
`host` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;Далее заводим пользователя в MySQL, даем ему права на работу с созданной БД.
Теперь самое интересное, нужно взять данные из лога и положить в БД. Изначально я реализовал это на shell с использованием AWK, но видимо я не очень хорошо знаю AWK, поскольку информация периодически задваивалась. В итоге был написан следующий скрипт на Perl:
#! /usr/bin/perl
use DBI;
use Time::Local;
#Хост MySQL
$dbhost='localhost';
#Пользователь MySQL
$dbuser='user';
#Пароль пользователя MySQL
$dbpass='password';
#IP Сервера CUPS
$CupsIP='192.168.0.10';
#Имя базы MySQL
$dbname='cups_stat';
#Полное имя page_log
$log='/var/log/cups/page_log';
%mnts = (
Jan => "01",
Feb => "02",
Mar => "03",
Apr => "04",
May => "05",
Jun => "06",
Jul => "07",
Aug => "08",
Sep => "09",
Oct => "10",
Nov => "11",
Dec => "12"
);
#Получаем дату и ID последнего задания в базе
#Подключение к DB
$dbh = DBI->connect("DBI:mysql:database=$dbname;host=$dbhost",$dbuser, $dbpass) || die print "Can't connect";
$sth = $dbh->prepare(q{SELECT UNIX_TIMESTAMP(MAX(p_date)), MAX(task_id) FROM tasks_log});
$sth -> execute;
#print $sth."/n";
$cols = $sth->{NUM_OF_FIELDS}; # кол-во строк в таблице
$rows = $sth->rows; # кол-во столбцов в таблице
@FieldNames = @{ $sth->{NAME} }; # массив содержащий названия
# полей таблицы
@row = $sth->fetchrow_array;
$MaxDate=$row[0];
$MaxTaskId=$row[1];
# print $MaxTaskId."->".$MaxDate."\n";
#Открываем лог-файл cups
open (FH,$log)|| die print 'Не могу открыть файл! \n';
while (< FH >
{
@fields=split(' ');
# print $MaxTaskId." > ".$fields[2]."\n";
#Меняем localhost на IP серевера CUPS
if ($fields[8]=="localhost")
{
$fields[8]=$CupsIP;
}
#Если ID задания из лог-файла больше либо равно ID последнего задания в базе
#и его дата больше даты в базе пишем его в базу.
#Преобразуем формат даты в понятный для MySQL datetime
if ($fields[2]=>$MaxTaskId || ! $MaxTaskId)
{
$year=substr($fields[3],8,4);
$rmon=$mnts{substr($fields[3],4,3)};
$mday=substr($fields[3],1,2);
$sec=substr($fields[3],-2);
$min=substr($fields[3],-5,2);
$hours=substr($fields[3],-8,2);
$udt=$year."-".$rmon."-".$mday." ".substr($fields[3],-8);
$fields[3]=$udt;
$TIME = timelocal($sec, $min, $hours, $mday, $rmon-1, $year);
if ($TIME>$MaxDate)
{
#Создаем запрос SQL и выполняем его
$query="insert into tasks_log (prn_name, user_name, task_id, p_date, page_num, rep_num, host) values('".$fields[0]."','".$fields[1]."','".$fields[2]."','".$fields[3]."','".$fields[5]."','".$fields[6]."','".$fields[8]."')";
$sth = $dbh->prepare(qq{$query});
$sth -> execute;
}
}
}
# Закрываем лог-файл
close(FH);
# Отключаемся от базы
$sth -> finish;
$dbh -> disconnect;
exit;
Дальше прописываем выполнение скрипта в crontab через желаемый промежуток времени. У меня, например, каждые 30 минут.
Для удобства работы с MySQL можно поставить phpmyadmin, в нем же можно и анализировать данные. конструируя запросы. Я для этих целей написал WEB-интерфейс на PHP, получилось вот как то так:
Если кому нужно - пишите, могу выслать. Правда дописано не до конца, лень напала.
UPD: Про WEB-интерфейс читаем тут.
UPD2: Рабочий скрипт лежит тут
Добрый день. Очень интересная статистика вывода данных о печати, хотели бы сделать такую же у себя , если не трудно вы не могли бы поделиться скриптами для статистики.
ОтветитьУдалитьЕсли не трудно вышлите на почту sergegm@yandex.ru заранее благодарен.
Все необходимые скрипты для сбора статистики есть в статье. Или интересует WEB-интерфейс?
ОтветитьУдалитьДа нас интересует именно WEB интерфейс.
ОтветитьУдалитьХорошо, как вспомню что я там понаписал, сделаю инструкцию и выложу здесь. Сразу предупреждаю, что писалось все под себя и к тому же дописалось не все что хотелось, но статистику по пользователям и по принтерам посмотреть можно. :)
ОтветитьУдалитьБольшое спасибо, жду.
ОтветитьУдалитьGunther поставили Web интерфейс создали базу и столкнулись с такой проблемой при запуске скрипта выдает такую ошибку.
ОтветитьУдалить17222 >
Day '' out of range 1..31 at db line 70
Какую версию CUPS используете? Выложите сюда пару строк из /var/log/cups/page_log. Должно быть что то типа HP_LaserJet_P2055dn user 231 [08/Apr/2010:09:44:50 +0400] 3 1 - 192.168.0.x
ОтветитьУдалитьЭтот комментарий был удален автором.
ОтветитьУдалитьxerox4510l user 17086 [07/Apr/2010:11:07:43 +0400] 1 1 - 192.168.1.179
ОтветитьУдалитьxerox4510l Domen\s.serge 17087 [07/Apr/2010:11:07:57 +0400] 1 1 - 192.168.1.163
получается вот так , часть пользователей домено часть не в домене Версия Cups 1.3.7
Ищем в скрипте строку
ОтветитьУдалитьopen (FH,$log)|| die print 'Не могу открыть файл! \n';
while ()
и правим while () на while (< FH>)
< FH> должно быть без пробелов!!!
При публикации поста парсер принимает хэндлер файла за HTML тэг. Сорри, не уследил. :)
Да теперь все без проблем спасибо, можно еще пару вопросов , а можно ли с другой машины с Cups системой сделать отправку логов в базу MySQL на сервере , и второй вопрос если я в crontab -e задам параметры 30 * * * * /var/www/cups/script.pl и на скрипт даю права 750 то не надо будет каждый день давать на фаил /var/log/cups/page_log доступ?
ОтветитьУдалить1. Можно, только будет глючить, поскольку на разных серверах могут быть задания с одинаковым временем и номером, а в БД нет идентификатора сервера CUPS. Если добавить в таблицу tasks_log поле идентификатор сервера и подправить скрипт, чтобы он это поле учитывал, то без проблем. Разрешаете MySQL соединения с удаленных клиентов и вперед. Если принтеры на серверах не имеют одинаковых имен, то WEB-интерфейс врать не станет, если есть, то его тоже нужно править. :)
ОтветитьУдалить2. У меня права на page_log стоят 644 по умолчанию, так что их и править то незачем, если есть сомнения, добавьте пользователя, от имени которого запускается скрипт в группу lp. gpasswd -a user lp.
Спасибо, будем пробывать.
ОтветитьУдалитьНашлась ошибка в скрипте единственное я не знаю где, но при повторном выполнение скрипта данные в базу дублируются и получается копия статистики если было напечатано 300 станиц становится 600 скорей всего ошибка #Если ID задания из лог-файла больше либо равно ID последнего задания в базе
ОтветитьУдалить#и его дата больше даты в базе пишем его в базу. но в Perl я не силен)
Странно, может быть еще чего при публикации отъелось. :)
ОтветитьУдалитьВыложил свой скрипт, который у меня на сервере крутится, см. UPD2 внизу поста.
Такого файла не существует или он был удален из-за нарушения авторских прав.
ОтветитьУдалитьhttp://depositfiles.com/files/x3ake60hi
ОтветитьУдалитьМожет кто сталкивался с такой проблемой. Есть принтер XeroxPhaser 4510. При печати в логах CUPS отображается количество страниц и копий всегда 1. Есть решение данной проблемы?
ОтветитьУдалитьНе сталкивался, попробуй переустановить принтер, если не поможет - обновить CUPS/драйвер принтера.
ОтветитьУдалить> $fields[8]=="localhost"
ОтветитьУдалитьЭто бессмысленное сравнение. Правильно: $fields[8] eq "localhost"
Но, удивительным образом, отрабатывает корректно. Однако, спорить не буду - с perl'ом я на Вы....
УдалитьА поделитесь пожалуйста веб-интерфейсом, а то ссылочки уже не актуальны.
ОтветитьУдалитьЕсли найду, 9 лет прошло, как-никак...
УдалитьЕще пришла в голову такая идея, crontab конечно не плох, но чтобы выводилась актуальная статистика в реальном времени сделать скрипт, который будет отслеживать изменения в размере файла и в случае, если таковые будут запускать perl-скрипт.
ОтветитьУдалитьЧто-то вроде:
#!/bin/bash
#$SCRIPT_PATH="./Cups_stat.pl"
i=1
modyfy=0
while true
do
pred=$(stat -c %s "/var/log/cups/page_log-20180318");
echo $pred
echo $modyfy
echo $i
if [ "$pred" -eq "$modyfy" ]
then
modyfy=$pred
echo "Нет изменений"
fi
if [ "$pred" -ne "$modyfy" ]
then
echo "Что-то изменилось"
#source $SCRIPT_PATH "./Cups_stat.pl"
#!/usr/bin/env perl
./Cups_stat.pl
modyfy=$pred
fi
sleep 60
$i = '2';
done
Его конечно еще можно демонизировать, а также всячески улучшить и доработать.
Конечно и очистка самого лога не помешала бы.
Но даже в таком виде на текущий момент все работает довольно не плохо)