拖尾日志文件并将结果写入新文件

我不知道怎么说这个,所以我会输入它然后编辑并回答任何问题。

目前在我的本地网络设备(基于PHP4)上,我正在使用它来定制一个实时系统日志文件: http : //commavee.com/2007/04/13/ajax-logfile-tailer-viewer/

这很好,并且每1秒加载一个外部页面(logfile.php),它执行tail -n 100 logfile.log该脚本不进行任何缓冲,因此它在屏幕上显示的结果是日志文件中的最后100行。

logfile.php包含:

 &1", $output); foreach($output as $outputline) { echo ("$outputline\n"); } ?> 

这部分运作良好。

我已经调整了logfile.php页面,将$ outputline写入一个新的文本文件,只需使用fwrite($fp,$outputline."\n");

虽然这有效但我在创建的新文件中存在重复问题。

显然,每次运行tail -n 100都会产生结果,下次运行它会产生一些相同的行,因为重复这种情况我最终会在新文本文件中出现多行重复。

我无法直接比较我要写入前一行的行,因为可能有相同的匹配。

有没有什么方法可以比较当前100行的块与前一个块,然后只写不匹配的行..再次可能的问题,块A和B将包含所需的相同行…

是否可以更新logfile.php以记录它在我的日志文件中最后占用的位置,然后只读取那里的下一行并将其写入新文件?

日志文件可能高达500MB,所以我不想每次都读取它。

任何建议或建议欢迎..

谢谢

更新@ 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."
"; @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); } 

任何方式这可以修改,所以它将从最后的已知位置读取..?

谢谢

介绍

您可以通过跟踪最后一个位置来拖尾文件;

 $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

 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 而不是行数,然后检查文件大小。 粗略的想法是:

 $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适当地减去最后一行的字节数)来轻松解决。