| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Perl: Общие вопросы > дописать из файла в базу |
| Автор: box 24.1.2010, 00:53 | ||
есть текстовый файл с логом и мне ничего не стоит распарсить его и закидать в базу на примере :
но проблема в том что скрипт вызавается каждую минуту а лог обновляется по мере поступления данных , как реализовать что б скрипт записывал в базу только новые данные что поступили с момента прошлого обновления лога . и еще , лог может периодически обнулятся , тоесть файл просто удаляется и создается новый , пустой . в таком случае по мере поступления данных в лог тоже должно происходить дописывание в базу . |
| Автор: Egik2 24.1.2010, 10:53 |
| Если у тебя в логе есть временная метка, а если нет то лучше сделать То как вариант могу предложить писать в какой-нить отдельный файл, дату записи, которую ты последнюю вставил в базу, а потом начинать с этой даты. |
| Автор: arto 24.1.2010, 12:46 |
| perldoc File::Tail Добавлено через 31 секунду или просто tail |
| Автор: box 24.1.2010, 14:21 | ||
дело в том что я спецом убрал временную метку из логов дабы урезать размер лога , да и время выполнения скрипта возрастет если я буду парсить временную мерку и сравнивать ее с записью из базы. а если лог будет 1-5 гигов то сервер то и будет делать что все время парсить логи. нужно както по другому . |
| Автор: klem4 24.1.2010, 15:11 |
| Не использовать временные метки - странное решение, но можно и без них решить Вашу задачу. Хранить (где угодно) кол-во строк лог-файла, при запуске скрипта сравнивать хранимую цифру с реальным кол-вом строк в логе, и если она меньше, парсить строки, номера которых больше хранимого индекса. Затем пересохранять индекс. |
| Автор: box 24.1.2010, 15:59 |
| а как быть если файл логов обнулен , тогда счетчик не поможет |
| Автор: klem4 24.1.2010, 16:13 |
| обнулен файл, обнуляй и счетчик, не вижу в чем проблема. |
| Автор: ramus 24.1.2010, 16:22 |
| 0) Лог не содержащий время - не лог 1) Если лог размером 1-5 гига, то предложение "при запуске скрипта сравнивать хранимую цифру с реальным кол-вом строк в логе" ОЧЕНЬ сильно нагрузит бессмысленной работой сервер (надо читать 1-5 гигов одного и того же файла при каждом запуске программы) 2) Вам рекомендовал уважаемый arto команду tail - это правильное решение. 3) если же хочется реализовать самому, то посмотрите команды seek и tell. Идея такова: Когда Ваша программа в первый раз дочитает лог до конца (с записью в БД распарсенных значений), надо в конце файла вывод команды tell сохранить для следующего запуска вашей программы(в БД или в файле). При следующем запуске вы зачитываете последнее сохраненное значение и встаете на эту позицию файла лога командой seek, пропустив уже отпарсенное. Команда seek работает почти мгновенно, почти не зависит от размера файла и практически не нагружает сервер. Опять читаете лог до конца файла с записью в БД распарсенных значений и записываете новое значение tell в БД или файл. Узнать, что файл лога отрезался можно сравнив размер зачитанный из БД и реальный размер файла лога. Если реальный размер меньше, то наверняка файл отрезался. При этом Ваша программа должна читать файл с начала. Правда могут быть нюансы если запуски программы реже чем отрезки файла лога. Если Ваша программа должна работать ТОЛЬКО на UNIX(Linux) я бы для этого кроме размера проверял бы еще i-node файла, так как имя лога обычно бывает одно и тоже, а меняется только сам файл, т.е. i-node. |
| Автор: klem4 24.1.2010, 16:33 | ||
Никогда не слышали про замечательную команду wc ? На логе 300+mb, wc -l Отрабатывает менее чем за 1 секунду. |
| Автор: ramus 24.1.2010, 16:34 |
| Кстати, а что за БД используется Вами? Она поддерживает переменные привязки (bind)? Я бы на месте админа БД убил бы эту сессию вместе с разработчиком такой проги ;) Если БД - ORACLE, то код while(<LOG>){ my ($ip_temp, $host_temp, $string_temp) = split(/\|/, $_); $query = "INSERT INTO log (ip, host, string) VALUES ('".$ip_temp."', '".$host_temp."', '".$string_temp."')"; $query_handle = $connect->prepare($query); $query_handle->execute(); } очень быстро забьет sql area сервера БД, понизив тем самым общую производительность сервера код должен быть таким (примерно, я не проверял): my $query = "INSERT INTO log (ip, host, string) VALUES (?, ?, ?)"; $query_handle = $connect->prepare($query); while(<LOG>){ my ($ip_temp, $host_temp, $string_temp) = split(/\|/, $_); $query_handle->execute($ip_temp, $host_temp, $string_temp); } |
| Автор: klem4 24.1.2010, 16:37 |
| К моему последнему сообщению: на логе 1.2G результат более плачевный. Так что если файлы большие то вариант мой действительно не проходит. |
| Автор: ramus 24.1.2010, 16:39 |
| На логе 300+mb, wc -l Отрабатывает менее чем за 1 секунду. Забавно А знаете что она (wc) реально делает? Это говорит, что либо файл уже в кеше, либо сервер ОЧЕНЬ мощный (например дисковая система на внешнем массиве по FC), так как чтение 300MB/секунду это хорошо (естественно если ВЕСЬ сервер не в вашем распоряжении и на нем еще идет полезная работа) Я против загрузки сервера тупой работой. |
| Автор: box 24.1.2010, 21:11 |
| да нет , не то это все и сервер ложится при использовании базы , не вывозит нагрузки уже при 10 метровом логе.хоть проц 2 ядра и рама 4 гига . не вариант юзать базу данных в моем случае , а так хотелось ! |
| Автор: shamber 25.1.2010, 00:19 |
| box, а ложиться скорее всего из-за, того что Вам ramus написал по поводу prepare и execute |
| Автор: shamber 25.1.2010, 10:20 |
я в этом не сомневаюсь, я говорю, что их нужно использовать, а не каждый раз по новой выполнять |
| Автор: Egik2 25.1.2010, 10:44 | ||||
| Ну ведь он, это и советует: Не надо:
То есть prepare происходит для каждой записи, что неправильно - и по идее одно и то же, что вставка без prepare. И как должно быть
То есть идет подготовка выражения с самого начала, а потом используется подготовленное. Разве это не правильно? |
| Автор: shamber 25.1.2010, 12:16 |
| ramus, предложил верное решение. позднее время, а также то,что чукча писатель, а не читатель(чукча -> я), и не позволило, вам увидеть эту мысль в моей фразе. Каюсь |
| Автор: ramus 26.1.2010, 00:00 |
| "хоть проц 2 ядра и рама 4 гига ." У нас особо "одаренные" программисты таким образом "напрягали" гораздо более крутой сервер - 8 двухядерных итаниумов с 64 гигами оперативки. Я не говорю, что это предложение панацея от всего, но то, что надо один раз отпарсить SQL, а потом многократно использовать с разными данными-это существенно облегчит жизнь серверу и админу. "что prepare statement наоборот помогает, позволяет держать базе в кэше объект SQL statement, что избавляет от необходимости каждый раз парсить запрос." Как раз в Вашем варианте происходит парсинг для каждой строки лога, так как каждый раз строка разная, например INSERT INTO log (ip, host, string) VALUES ('1.1.1.1', 'host_temp', 'string') INSERT INTO log (ip, host, string) VALUES ('2.2.2.2', 'host_temp', 'string') В предложенном мной варианте парсинг (в том числе определение плана выполнения) выполняется один раз, INSERT INTO log (ip, host, string) VALUES (:ip, :host, :string) в области хранения SQL запросов ( SQL area) будет только ОДНА строчка (от нашей сессии). Число execute для нее будет равняться числу строк в логе. В Вашем же случае число строк в sql area БД будет равно числу строк в логе и для каждой такой строки число execute будет =1. PS Лучше много раз по разу, чем ни разу много раз ;) |
| Автор: box 26.1.2010, 06:29 | ||
пишу следующее :
такой вариант работает только в том случае если лог не обноляется , но у меня он периодически обнуляется и получается что новая запись в базе не добавится пока кол-во строк в новом файле не будет больше чем кол-во записей в базе , вообщем бред получается . вообщем вопрос номер один "как определить что лог обновился а не просто еще не успел набрать того кол-ва строк что в базе" |
| Автор: shamber 26.1.2010, 11:27 |
У вас тут с логикой все совершенно жестко. Вам предложили пару вариантов, но вы их не хотите использовать, вместо этого изобретаете велосипед, и удивляетесь что ничего не работает. Чем Вам не нравится вариант с seek? Добавлено @ 11:29 ну добавьте в скрипт, чтение параметров файла, к примеру время последней модификации. и все проблемы решены |
| Автор: ginnie 26.1.2010, 12:50 |
| box, у меня вот какой вопрос возник: если у Вас лог периодически обнуляется и этот процесс никак не завязан со скриптом, Вы, случайно, часть данных не теряете (которые добавилась после запуска скрипта, но до обнуления лога)? |
| Автор: box 26.1.2010, 17:02 |
| "ну добавьте в скрипт, чтение параметров файла, к примеру время последней модификации. и все проблемы решены" к сожалению это проблемы не решает потому как время модификации файла будет меняться каждый раз когда добавляется новая строка файла. у меня была идея создавать lock файл или запись в бд о том что файл обновлен и потом соответсвующим образом обрабатывать лог но это займет больше ресурсов. |
| Автор: shamber 26.1.2010, 17:05 | ||
что в моем предложении, мешает осуществить перечисленное вами? |
| Автор: arto 26.1.2010, 17:16 |
| интересно, когда вы повторите функциональность обыкновенного tail? который может следить хоть за дескриптором, хоть за именем... |
| Автор: box 26.1.2010, 18:32 |
| приведите пожалуйста пример использования tail в перле , а то я нашел только для командной строки . |
| Автор: klem4 26.1.2010, 19:22 |
| А почему не хотите использовать tail коммандной строки из perl ? |
| Автор: arto 26.1.2010, 20:57 |
| tail | perl самое простое. либо perldoc -f open |
| Автор: klem4 26.1.2010, 21:39 | ||
Дак можно прямо в перл получать результат tail
|
| Автор: arto 26.1.2010, 21:54 |
| нет. я так понял, что вы не прочитали man tail ? |
| Автор: klem4 26.1.2010, 23:34 | ||
не совсем понял, какоe отношение имеет способ вызова tail к прочтению/не прочтению мною man'а. |
| Автор: arto 26.1.2010, 23:48 |
| а вы прочитайте. |
| Автор: mvsgt 27.1.2010, 00:11 | ||
В мане есть опция, позволяющая tail отследить смену файла. |