2013-06-03 12 views
9

io non sono sicuro di come parola questo quindi mi tipo fuori e quindi modificare e rispondere alle domande che sorgono ..Tailing file di registro e scrivere i risultati al nuovo file

Attualmente sul mio dispositivo di rete locale (Basato su PHP4) Sto usando questo per accodare un file di log dal vivo: http://commavee.com/2007/04/13/ajax-logfile-tailer-viewer/

Questo funziona bene e ogni 1 secondo carica una pagina esterna (logfile.php) che fa un tail -n 100 logfile.log Lo script non fa nessuno buffering in modo che i risultati visualizzati sullo schermo siano le ultime 100 righe del file di registro.

Il logfile.php contiene:

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

Questa parte funziona bene.

ho adattato alla pagina logfile.php di scrivere il $ outputline in un nuovo file di testo, semplicemente utilizzando fwrite($fp,$outputline."\n");

Mentre questo funziona sto avendo problemi con la duplicazione nel nuovo file creato.

Ovviamente ogni volta che tail -n 100 viene eseguito produce risultati, la prossima volta che viene eseguito potrebbe produrre alcune delle stesse linee, poiché questo ripete Posso finire con più righe di duplicazione nel nuovo file di testo.

Non riesco a confrontare direttamente la riga che sto per scrivere sulle righe precedenti in quanto potrebbero esserci corrispondenze identiche.

Esiste un modo per confrontare questo blocco corrente di 100 righe con il blocco precedente e quindi solo scrivere le righe che non corrispondono. È possibile che il blocco A & B contenga le righe identiche necessarie.

È possibile aggiornare logfile.php per prendere nota della posizione in cui è stata utilizzata per ultimo nel mio file di registro e quindi leggere solo le successive 100 righe da lì e scriverle nel nuovo file?

Il file di registro potrebbe essere fino a 500 MB, quindi non voglio leggere tutto in ogni volta ..

Qualsiasi consiglio o suggerimenti di benvenuto ..

Grazie

UPDATE @ 16 : 30

ho sorta di ottenuto questo lavoro utilizzando:

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

Sembra funzionare, ma prima carica l'intero file e poi solo gli aggiornamenti.

Come posso iniziare dalle ultime 50 righe e quindi solo dagli aggiornamenti?

Grazie :)

UPDATE 04.06.2013 Anche se questo funziona è molto lento con file di grandi dimensioni.

Ho provato questo codice e sembra più veloce, ma non si legge solo da dove era stato interrotto.

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

In qualsiasi modo questo può essere modificato in modo da leggere dall'ultima posizione nota ..?

Grazie

+1

Il mio primo suggerimento sarebbe di aggiornare PHP. http://php.net/eol.php – vascowhite

+0

Purtroppo non è possibile.È incorporato nel dispositivo :( – MacMan

+0

Può il dispositivo eseguire perl? Potrebbe essere un one-liner epico in perl .. –

risposta

0

Utilizzare tail -c <number of bytes, al posto del numero di linee, e quindi controllare la dimensione del file. L'idea di base è:

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

Il vantaggio è che è possibile eliminare tutti i processi di elaborazione speciali e ottenere buone prestazioni. Lo svantaggio è che devi dividere manualmente l'output in linee e probabilmente potresti finire con linee non finite. Ma questo non è un grosso problema, puoi facilmente aggirare il problema omettendo l'ultima riga dall'output (e sottraendo opportunamente l'ultimo numero di byte di linea da old_file_size).

1

Non proprio chiaro su come si desidera utilizzare l'uscita, ma sarebbe qualcosa di simile a questo lavoro ....

$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 è solo un file di testo che contiene in cui la posizione di posizione di lettura è stato dal corsa precedente. Sto solo cercando quella posizione e rimando il resto al buffer di output.

2

Introduzione

È possibile coda di un file con il tracciamento della ultima posizione;

Esempio

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

TailLog è una semplice classe che ho scritto per questo compito: ecco un semplice esempio per mostrare la sua realtà tailing il file

semplice test

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

Uscita

// 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 

Tempo reale Tailing

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

Nota: Tailing 100 linee non significa che sarebbe sempre ritornare 100 linee. Restituirebbe nuove righe aggiunte 100 è solo il numero massimo di righe da restituire. Questo potrebbe non essere efficiente in cui si dispone pesante la registrazione di oltre 100 linea per sec è che non c'è alcuna

Tail Classe

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

coda Blocco

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