Tailing Log File и запись результатов в новый файл

Я не знаю, как это сказать, поэтому я напечатаю его, а затем отредактирую и отвечу на любые возникающие вопросы.

В настоящее время на моем локальном сетевом устройстве (на основе PHP4) я использую это, чтобы закрепить файл системного журнала в реальном времени: http://commavee.com/2007/04/13/ajax-logfile-tailer-viewer/

Это работает хорошо, и каждые 1 секунду он загружает внешнюю страницу (logfile.php), которая делает tail -n 100 logfile.log . Сценарий не выполняет никакой буферизации, поэтому результаты, отображаемые на экране, – это последние 100 строк из файла журнала ,

Файл logfile.php содержит:

 <? // logtail.php $cmd = "tail -10 /path/to/your/logs/some.log"; exec("$cmd 2>&1", $output); foreach($output as $outputline) { echo ("$outputline\n"); } ?> 

Эта часть работает хорошо.

Я адаптировал страницу logfile.php для записи строки $ output в новый текстовый файл, просто используя fwrite($fp,$outputline."\n");

Хотя это работает, у меня возникают проблемы с дублированием в новом файле, который создается.

Очевидно, каждый раз, когда tail -n 100 запускает результаты, в следующий раз, когда он запускается, он может создавать некоторые из тех же строк, поскольку это повторяется, я могу получить несколько строк дублирования в новом текстовом файле.

Я не могу напрямую сравнить строку, которую я собираюсь записать на предыдущие строки, поскольку могут быть одинаковые совпадения.

Есть ли способ сравнить этот текущий блок из 100 строк с предыдущим блоком, а затем написать строки, которые не совпадают. Опять возможная проблема, которая блокирует A & B, будет содержать идентичные строки, которые необходимы …

Можно ли обновить logfile.php, чтобы отметить позицию, занятую последним в моем файле журнала, а затем читать только следующие 100 строк и записать их в новый файл?

Файл журнала может быть до 500 МБ, поэтому я не хочу читать все это каждый раз.

Любые советы или предложения приветствуются.

благодаря

ОБНОВЛЕНИЕ @ 16:30

Я как-то справился с этим:

 $file = "/logs/syst.log"; $handle = fopen($file, "r"); if(isset($_SESSION['ftell'])) { clearstatcache(); fseek($handle, $_SESSION['ftell']); while ($buffer = fgets($handle)) { echo $buffer."<br/>"; @ob_flush(); @flush(); } fclose($handle); @$_SESSION['ftell'] = ftell($handle); } else { fseek($handle, -1024, SEEK_END); fclose($handle); @$_SESSION['ftell'] = ftell($handle); } 

Это похоже на работу, но сначала загружает весь файл, а затем только обновления.

Как мне начать с последних 50 строк, а затем только обновлений?

Благодаря 🙂

ОБНОВЛЕНИЕ 04/06/2013 Хотя это работает очень медленно с большими файлами.

Я пробовал этот код, и он кажется быстрее, но он не просто читает, откуда он остановился.

 function last_lines($path, $line_count, $block_size = 512){ $lines = array(); // we will always have a fragment of a non-complete line // keep this in here till we have our next entire line. $leftover = ""; $fh = fopen($path, 'r'); // go to the end of the file fseek($fh, 0, SEEK_END); do{ // need to know whether we can actually go back // $block_size bytes $can_read = $block_size; if(ftell($fh) < $block_size){ $can_read = ftell($fh); } // go back as many bytes as we can // read them to $data and then move the file pointer // back to where we were. fseek($fh, -$can_read, SEEK_CUR); $data = fread($fh, $can_read); $data .= $leftover; fseek($fh, -$can_read, SEEK_CUR); // split lines by \n. Then reverse them, // now the last line is most likely not a complete // line which is why we do not directly add it, but // append it to the data read the next time. $split_data = array_reverse(explode("\n", $data)); $new_lines = array_slice($split_data, 0, -1); $lines = array_merge($lines, $new_lines); $leftover = $split_data[count($split_data) - 1]; } while(count($lines) < $line_count && ftell($fh) != 0); if(ftell($fh) == 0){ $lines[] = $leftover; } fclose($fh); // Usually, we will read too many lines, correct that here. return array_slice($lines, 0, $line_count); } 

В любом случае это может быть изменено, поэтому он будет читать из последней известной позиции ..?

благодаря

Solutions Collecting From Web of "Tailing Log File и запись результатов в новый файл"

Введение

Вы можете перетащить файл, отслеживая последнюю позицию;

пример

 $file = __DIR__ . "/a.log"; $tail = new TailLog($file); $data = $tail->tail(100) ; // Save $data to new file 

TailLog – это простой класс, который я написал для этой задачи, вот простой пример, показывающий его фактический хвост файла

Простой тест

 $file = __DIR__ . "/a.log"; $tail = new TailLog($file); // Some Random Data $data = array_chunk(range("a", "z"), 3); // Write Log file_put_contents($file, implode("\n", array_shift($data))); // First Tail (2) Run print_r($tail->tail(2)); // Run Tail (2) Again print_r($tail->tail(2)); // Write Another data to Log file_put_contents($file, "\n" . implode("\n", array_shift($data)), FILE_APPEND); // Call Tail Again after writing Data print_r($tail->tail(2)); // See the full content print_r(file_get_contents($file)); 

Вывод

 // First Tail (2) Run Array ( [0] => c [1] => b ) // Run Tail (2) Again Array ( ) // Call Tail Again after writing Data Array ( [0] => f [1] => e ) // See the full content a b c d e f 

Времени в реальном времени

 while(true) { $data = $tail->tail(100); // write data to another file sleep(5); } 

Примечание. Стояние 100 строк не означает, что оно всегда возвращает 100 строк. Он вернет новые добавленные строки. 100 – это максимальное количество строк для возврата. Это может быть неэффективно, если у вас есть более тяжелая регистрация более 100 строк в секунду, есть ли какие-либо

Класс хвоста

 class TailLog { private $file; private $data; private $timeout = 5; private $lock; function __construct($file) { $this->file = $file; $this->lock = new TailLock($file); } public function tail($lines) { $pos = - 2; $t = $lines; $fp = fopen($this->file, "r"); $break = false; $line = ""; $text = array(); while($t > 0) { $c = ""; // Seach for End of line while($c != "\n" && $c != PHP_EOL) { if (fseek($fp, $pos, SEEK_END) == - 1) { $break = true; break; } if (ftell($fp) < $this->lock->getPosition()) { break; } $c = fgetc($fp); $pos --; } if (ftell($fp) < $this->lock->getPosition()) { break; } $t --; $break && rewind($fp); $text[$lines - $t - 1] = fgets($fp); if ($break) { break; } } // Move to end fseek($fp, 0, SEEK_END); // Save Position $this->lock->save(ftell($fp)); // Close File fclose($fp); return array_map("trim", $text); } } 

Хвост блокировки

 class TailLock { private $file; private $lock; private $data; function __construct($file) { $this->file = $file; $this->lock = $file . ".tail"; touch($this->lock); if (! is_file($this->lock)) throw new Exception("can't Create Lock File"); $this->data = json_decode(file_get_contents($this->lock)); // Check if file is valida json // Check if Data in the original files as not be delete // You expect data to increate not decrease if (! $this->data || $this->data->size > filesize($this->file)) { $this->reset($file); } } function getPosition() { return $this->data->position; } function reset() { $this->data = new stdClass(); $this->data->size = filesize($this->file); $this->data->modification = filemtime($this->file); $this->data->position = 0; $this->update(); } function save($pos) { $this->data = new stdClass(); $this->data->size = filesize($this->file); $this->data->modification = filemtime($this->file); $this->data->position = $pos; $this->update(); } function update() { return file_put_contents($this->lock, json_encode($this->data, 128)); } } 

Не совсем понятно, как вы хотите использовать выход, но что-то вроде этой работы ….

 $dat = file_get_contents("tracker.dat"); $fp = fopen("/logs/syst.log", "r"); fseek($fp, $dat, SEEK_SET); ob_start(); // alternatively you can do a while fgets if you want to interpret the file or do something fpassthru($fp); $pos = ftell($fp); fclose($fp); echo nl2br(ob_get_clean()); file_put_contents("tracker.dat", ftell($fp)); 

tracker.dat – это всего лишь текстовый файл, содержащий позицию позиции чтения из предыдущего прогона. Я просто ищу эту позицию и передаю остальную часть в выходной буфер.

Используйте tail -c <number of bytes , а не количество строк, а затем проверьте размер файла. Грубая идея:

 $old_file_size = 0; $max_bytes = 512; function last_lines($path) { $new_file_size = filesize($path); $pending_bytes = $new_file_size - $old_file_size; if ($pending_bytes > $max_bytes) $pending_bytes = $max_bytes; exec("tail -c " + $pending_bytes + " /path/to/your_log", $output); $old_file_size = $new_file_size; return $output; } 

Преимущество состоит в том, что вы можете избавиться от всех специальных материалов обработки и получить хорошую производительность. Недостатком является то, что вам нужно вручную разделить вывод на строки, и, вероятно, вы можете закончить с незавершенными линиями. Но это не имеет большого значения, вы можете легко обойтись, опустив последнюю строку отдельно от вывода (и соответственно вычитая последнее количество строк байтов из old_file_size ).