LINUX.ORG.RU

Парсинг логов в MySQL с помощью Perl скрипта

 , , ,


0

1

Помогите пожалуйста. Нужен был скрипт, который парсит файл лога CUPS (page_log) и добавляет эти данные в Mysql таблицу.

Погуглил, ничего свежего не нашел.

Только на этом сайте нашел скрипт, но с ним возникли сложности.

http://extmemory.blogspot.ru/2009/10/cups.html

Система Ubuntu 16.04, LAMP.

Ставим LAMP, phpmyadmin, модули для perl

sudo tasksel install lamp-server

sudo apt-get install phpmyadmin

sudo apt-get install libdbi-perl

sudo apt-get install libdbd-mysql-perl

Создаем базу данных cups_stat содержащую таблицу, tasks_log:

CREATE DATABASE `cups_stat`;

USE `cups_stat`;

Создаем таблицу tasks_log

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 пользователя print/print и даем ему полные права на таблицу tasks_log

Создаем Perl script

#! /usr/bin/perl
use DBI;
use Time::Local;
#Хост MySQL
$dbhost='localhost';
#Пользователь MySQL
$dbuser='print';
#Пароль пользователя MySQL
$dbpass='print';
#IP Сервера CUPS
$CupsIP='127.0.0.1';
#Имя базы 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;

Права на файл page_log

-rw-r--r-- 1 root adm 438 дек 29 08:51 page_log

Содержимое page_log

HP_LaserJet_MFP_M129-M134 user2 17421 [29/Dec/2017:07:55:22 +0500] 1 1 - 192.168.20.102
HP_LaserJet_MFP_M129-M134 user2 17422 [29/Dec/2017:08:20:10 +0500] 1 1 - 192.168.20.102

Пытаемся выполнить скрипт:

root@ubuntu-ltsp-5:/etc/scripts# /var/www/print.pl

Month '-1' out of range 0..11 at /var/www/print.pl line 70.

Т.е. ему не нравится функция преобразования времени в скрипте:

$TIME = timelocal($sec, $min, $hours, $mday, $rmon-1, $year);

Запустил debug (perl -d)

Month '-1' out of range 0..11 at /var/www/print.pl line 70.
 at /usr/share/perl/5.22/Time/Local.pm line 108.
        Time::Local::timegm called at /usr/share/perl/5.22/Time/Local.pm line 155
        Time::Local::timelocal("", undef, undef, undef, -1, undef) called at /var/www/print.pl line 70
Debugged program terminated.  Use q to quit or R to restart,

Как можно исправить эту ошибку?

Спасибо.



Последнее исправление: deemka78 (всего исправлений: 11)

Адавая каша из тем, заданий... Все смешалось.

Как можно исправить эту ошибку?

Не вычитать из января (нулевой месяц) еще еденицу?

mos ★★☆☆☆
()

Time::Local::timelocal("", undef, undef, undef, -1, undef) called at /var/www/print.pl line 70

Так у вас не распарсилась строка.

Вообще должен быть нормальный парсер для дат, без вот этого преобразования месяца в число. Попробуйте парсить в unixtime по шаблону как в логе и потом писать его в БД с преобразованием в нужный шаблон.

И это, perl обязателен?

micronekodesu ★★★
()
Ответ на: комментарий от arto

У автора скрипта строчка в логе имела следующий формат

HP_LaserJet_P2055dn user 9556 [12/May/2009:14:22:51 +0400] 1 2 - host

У меня вроде бы аналогичный

HP_LaserJet_MFP_M129-M134 user2 17421 [29/Dec/2017:07:55:22 +0500] 1 1 - 192.168.20.102

$field[3] в этой строчке это, если я правильно понимаю, значение -[29/Dec/2017:07:55:22 +0500]

deemka78
() автор топика
Ответ на: комментарий от micronekodesu

Perl необязателен вообще. Я если честно в скриптах и языках программирования не силен. Из готовых решений, нашел только это, на Perl.

deemka78
() автор топика
Ответ на: комментарий от micronekodesu

Для моей задачи этот скрипт избыточен. Мне по сути, нужно только имя принтера и счетчик страниц. Т.е. в результате на сайте через php должна отдаваться будет информация «Имя принтера» - «количество страниц в день» - «количество страниц в месяц» - «общее количество страниц»

deemka78
() автор топика
Ответ на: комментарий от deemka78

Как уже писали не распарсилась строка с датами. Нужно повыводить на консоль значения переменных откуда берется эта строка и станет понятно в чем проблема. Для начала: use Data::Dumper; print Dumper @fields. И далее до просветления.

Olegymous ★★★
()
Ответ на: комментарий от Olegymous

Вот что выдал Dumper

DB<15> print Dumper @fields $VAR1 = 'FH'; $VAR2 = undef; $VAR3 = undef; $VAR4 = '-- '; $VAR5 = undef; $VAR6 = undef; $VAR7 = undef; $VAR8 = undef; $VAR9 = '127.0.0.1';

Т.е. получается строка с датой впринципе не распозналась, ни день, ни число, ни месяц

deemka78
() автор топика
Ответ на: комментарий от arto

Запустил дебаг, построчно.

Вот вывод в конце:

main::(/var/www/print.pl:72):        $udt=$year."-".$rmon."-".$mday." ".substr($fields[3],-8);
  DB<35> n
main::(/var/www/print.pl:73):        $fields[3]=$udt;
  DB<35> print Dumper \@fields
$VAR1 = [
          'FH',
          undef,
          undef,
          undef,
          undef,
          undef,
          undef,
          undef,
          '127.0.0.1'
        ];

  DB<36> n
main::(/var/www/print.pl:74):        $TIME = timelocal($sec, $min, $hours, $mday, $rmon-1, $year);
  DB<36> n
Month '-1' out of range 0..11 at /var/www/print.pl line 74.
 at /usr/share/perl/5.22/Time/Local.pm line 108.
        Time::Local::timegm called at /usr/share/perl/5.22/Time/Local.pm line 155
        Time::Local::timelocal("", undef, undef, undef, -1, undef) called at /var/www/print.pl line 74
Debugged program terminated.  Use q to quit or R to restart,
use o inhibit_exit to avoid stopping after program termination,
h q, h R or h o to get additional info.
  DB<36> print Dumper \@fields
$VAR1 = [
          'FH',
          undef,
          undef,
          '-- ',
          undef,
          undef,
          undef,
          undef,
          '127.0.0.1'
        ];

  DB<37> n
Use 'q' to quit or 'R' to restart.  'h q' for details.

Вот эту $VAR1 он выдает раньше, чем запускает функцию

$TIME = timelocal($sec, $min, $hours, $mday, $rmon-1, $year);
а после запуска этой функции, он уже ничего не выдает нового.

deemka78
() автор топика
Ответ на: комментарий от Olegymous

Спасибо огромное!!! Дело было в них получается, убрал их и сразу все спарсилось корректно.

deemka78
() автор топика

Кстати, на будущее, всегда используй в Perl

use strict;
use warnings;

Помогает найти вот такие ошибки как у тебя.

KennyMinigun ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.