2016-05-11 3 views
0

Ich habe eine sehr große Protokolldatei. Ich muss die letzte "WARN" -Zeile in dieser Datei effizient herausfinden (dh vom Ende lesen), sie analysieren und als Objekt mit dem "Date" -Feld (DateTime-Typ), dem "Level" -Feld und " Beschreibung "FeldWie effizient finden und analysieren Sie die letzte Textzeile aus einer Protokolldatei über PowerShell?

Irgendwelche Vorschläge?

Hier ist, was die Datei

[Mon Dec 14 14:57:53 2015] [notice] Child 6180: Acquired the start mutex. 
[Mon Dec 14 14:57:53 2015] [notice] Child 6180: Starting 150 worker threads. 
[Mon Dec 14 15:04:43 2015] [warn] pid file C:/Program Files (x86)/Citrix/XTE/logs/xte.pid overwritten -- Unclean shutdown of previous Apache run? 
[Mon Dec 14 15:04:43 2015] [notice] Server built: May 27 2011 16:04:42 
[Mon Dec 14 15:04:43 2015] [notice] Parent: Created child process 5608 

EDIT wie

aussieht: Dieser Befehl in der Datei aussehen muss, die letzte passende Zeile von Suchkriterien finden, diese Zeile zurückkehrt, und „Stop“. Mögliche doppelte Frage ist auf verschiedene Arten unterschiedlich: mein Skript kann nicht einfach da sitzen und warten, bis die Zeile erscheint - es muss laufen, die Zeile so schnell wie möglich bekommen und aussteigen. Darüber hinaus muss es nach Teilzeichenfolge suchen, und schließlich muss ein DateTime und andere Felder aufgeteilt werden. Danke, dass Sie diese Frage nicht abschliessen.

+0

Mögliches Duplikat [Unix tail entsprechender Befehl in Windows Powershell] (http://stackoverflow.com/questions/4426442/unix-tail-equivalent-command -in-windows-powershell) –

+0

Es ist keineswegs äquivalent. Ich muss die letzte passende Zeile basierend auf einem Suchkriterium finden, nicht die letzten Zeilen.Außerdem muss DateTime analysiert werden. Bitte wählen Sie nicht, um zu schließen – Igorek

+0

Im Allgemeinen ist SO ein Ort, um Hilfe mit Code zu bekommen, den Sie geschrieben haben, der nicht funktioniert. Es ist kein Ort, um nach einem Skript zu fragen, das für dich geschrieben wird. Ich bin überrascht, dass jemand mit mehr als 10.000 Ruf das hier posten würde! –

Antwort

-1

Es wird sicherlich nicht effizient sein. Alles in PowerShell und C# (und alles andere) basiert auf Vorwärtslesen, nicht auf Rückwärtslesen. Angesichts dessen und der Tatsache, dass Sie nicht einmal wissen, wo die letzte Zeile sein könnte, sehe ich keine Möglichkeit, die Verarbeitung der gesamten Datei zu vermeiden, es sei denn, Sie möchten mehrere Stunden damit verbringen, Ihren eigenen ReverseStreamReader zu schreiben.

die Datei Unter der Annahme, ist größer als RAM - was IMO Get-Content unpraktisch macht - ich würde wahrscheinlich so etwas wie:

$LineNumber = [uint64]0; 
$StreamReader = New-Object System.IO.StreamReader -ArgumentList "C:\LogFile.log" 
$SearchPattern = [Regex]::Escape('[warn]'); 
while ($Line = $StreamReader.ReadLine()) { 
    $LineNumber++; 
    if ($Line -match $SearchPattern) { 
     $LastLineNumber = $LineNumber; 
     $LastLineMatch = $Line; 
    } 
} 
$StreamReader.Close() 

$LastLineNumber 
$LastLineMatch 

Parsen die Linie gehen wird wahrscheinlich eine Menge String.IndexOf einzubeziehen() und String.Substring(). Drehen Sie das Datum in ein Datetime sollte wie so geschehen:

[datetime]::ParseExact('Mon Dec 14 15:04:43 2015','ddd MMM dd HH:mm:ss yyyy',[System.Globalization.CultureInfo]::InvariantCulture,[System.Globalization.DateTimeStyles]::None); 

ich -match über -like entschieden, weil soweit ich sagen kann, führt es tatsächlich besser. Das könnte aber nur mein System sein.

0

Öffnen Sie die Datei als eine rohe Stream, suchen Sie eine "anständige" Blockgröße vom Ende (sagen 1 MB), dann suchen Sie die resultierenden Bytes für die binäre Darstellung von "warn", bis Sie die letzte Instanz gefunden haben (Ich nehme an, dass Sie die Codierung im Voraus kennen). Wenn Sie es finden, suchen Sie nach den Leitungsabschlüssen. Wenn Sie es nicht finden, suchen Sie 1 + 1 MB und gehen Sie wieder. Wiederholen Sie den Vorgang, bis Sie den Anfang gefunden haben.

Wenn es keine "Warnung" in der gesamten Datei gibt, ist dies langsamer als das sequentielle Lesen der Datei, aber wenn Sie sicher sind, dass eine Zeile der gewünschten Art am Ende vorhanden ist, kann dies ziemlich schnell beendet werden . Die wichtigste Sache zu tun ist nicht lesen Sie die Datei als Text mit einem StreamReader, da Sie die Fähigkeit verlieren, willkürlich zu suchen.

Den Code für diese Idee richtig zu machen, ist komplizierter. Die Schwierigkeit dieses Vorgangs liegt nicht an der PowerShell - es gibt keine einfache Möglichkeit, dies in einer beliebigen Sprache zu tun, da das Lesen einer Datei in umgekehrter Reihenfolge keine effiziente Operation in einem mir bekannten Dateisystem darstellt.

0

würde ich, dass diese Art und Weise nähern:

get-content $file -ReadCount 3000 | 
ForEach-Object { 
    if ($_ -like '*warn*') 
    {$Lastfound = $_} 
} 

($Lastfound -like '*warn*')[-1] 
Verwandte Themen