2013-06-03 4 views
9

Я не уверен, как это слово, так что я ввожу его, а затем редактировать и отвечать на любые вопросы, которые приходят ..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 написать $ outputline в новый текстовый файл, просто используя fwrite($fp,$outputline."\n");

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

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

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

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

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

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

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

Благодаря

UPDATE @ 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 строк, а затем только обновлений?

Спасибо :)

UPDATE 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); 
} 

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

Благодаря

+1

Моего первым было бы предложение обновить PHP. http://php.net/eol.php – vascowhite

+0

К сожалению, это невозможно.Он встроен в устройство :( – MacMan

+0

Может ли устройство работать perl? Это может быть эпический однострочный в perl .. –

ответ

0

Используйте 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).

1

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

$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 это просто текстовый файл, который содержит, где позиция позиции считывании была из предыдущий запуск. Я просто ищу эту позицию и передаю остальную часть в выходной буфер.

2

Введение

Вы можете хвост файл путем отслеживания последней позиции;

Пример

$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 

Real Time Tailing

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

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

Tail Класс

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); 
    } 
} 

Tail Замка

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)); 
    } 
}