Frage
Ich habe eine Datei listern, wenn ihr Inhalt hinzugefügt wird, werde ich die neue Linie, und die Arbeit an dem Inhalt der neuen Zeile gelesen. Die Länge der Datei wird nie abnehmen. (In der Tat, es ist die Kater Protokolldatei).
Ich verwende die folgenden Codes:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import org.apache.log4j.Logger;
import com.zjswkj.analyser.ddao.LogEntryDao;
import com.zjswkj.analyser.model.LogEntry;
import com.zjswkj.analyser.parser.LogParser;
public class ListenTest {
private RandomAccessFile raf;
private long lastPosition;
private String logEntryPattern = "^([\\d.]+) (\\S+) (\\S+) \\[([\\w:/]+\\s[+\\-]\\d{4})\\] \"(.+?)\" (\\d{3}) (\\S+) \"([^\"]+)\" \"([^\"]+)\"";
private static Logger log = Logger.getLogger(ListenTest.class);
public void startListenLogOfCurrentDay() {
try {
if (raf == null)
raf = new RandomAccessFile(
"/tmp/logs/localhost_access_log.2010-12-20.txt",
"r");
String line;
while (true) {
raf.seek(lastPosition);
while ((line = raf.readLine()) != null) {
if (!line.matches(logEntryPattern)) {
// not a complete line,roll back
lastPosition = raf.getFilePointer() - line.getBytes().length;
log.debug("roll back:" + line.getBytes().length + " bytes");
if (line.equals(""))
continue;
log.warn("broken line:[" + line + "]");
Thread.sleep(2000);
} else {
// save it
LogEntry le = LogParser.parseLog(line);
LogEntryDao.saveLogEntry(le);
lastPosition = raf.getFilePointer();
}
}
}
} catch (FileNotFoundException e) {
log.error("can not find log file of today");
} catch (IOException e) {
log.error("IO Exception:" + e.getMessage());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new ListenTest().startListenLogOfCurrentDay();
}
}
Nun, mein Problem ist, dass, wenn eine Linie, die in die Akten der neuen Zeile geschrieben wird nicht abgeschlossen ist, wird eine tote Schleife auftreten.
Zum Beispiel, wenn der Kater versuchen zu schreiben in die Datei eine neue Zeile:
10.33.2.45 - - [08/Dec/2010:08:44:43 +0800] "GET /poi.txt HTTP/1.1" 200 672 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8"
Und wenn nur ein Teil der Zeile geschrieben (zum Beispiel: << strong> 10.33.2.45 - - [08 / Dec / 2010: 08: 44: 43 0.800] „GET /poi.txt HTTP / 1.1 "200 672 >), jetzt, da sie das Muster nicht übereinstimmen kann ich definiert, das zu sagen ist, tomcat nicht seine Schreibarbeit abgeschlossen ist, so werde ich versuchen, den Dateizeiger zu rollen zurück und schlafen 2 Sekunden und dann lesen wieder.
Während der Ruhezeit, der letzte Teil der Linie noch vielleicht geschrieben (in der Tat ich sich schreiben, anstatt tomcat für Test), meiner Meinung nach, wird Random eine neue Zeile lesen, die das Muster entsprechen können, aber es scheint nicht .
Jeder kann einen Scheck haben die Codes?
Hinweis : das Format der Protokolldatei "combined" wie folgt aus:
10.33.2.45 - - [08/Dec/2010:08:44:43 +0800] "GET /poi.txt HTTP/1.1" 200 672 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8"
Lösung
Ich sehe (aus dem Code), dass Ihr Hauptziel ist die zu filtern log-Einträge / Ereignisse und dann schreiben die gefilterten Protokolle Datenbank. Sie haben 2 Möglichkeiten
Option 1: Best und der richtige Weg zu tun. Aber Sie sollten die log4j Konfigurationsdatei ändern können, die mit Kater kommt
Wenn dies der Fall ist, dann ist der beste Weg, dies zu tun ist log4j vordefinierten Erweiterungspunkte zu verwenden. In Ihrem Fall ist die Entnahmestelle des Appender
Log4j kommt bereits mit dem DBAppender , dass Sie vielleicht erweitern möchten delegieren die Protokolle mit Ihrem regulären Ausdruck zu filtern und dann den Rest auf DBAppender wie es gut getestet wird. Unten ist ein Beispiel dafür, wie die custome appender
konfigurierenlog4j.rootLogger = DEBUG, S
log4j.appender.S = com.gurock.smartinspect.log4j.MyCustomAppender
log4j.appender.S.layout = org.apache.log4j.SimpleLayout
Ich schlage vor, Sie schauen auch bei Verwendung der AsyncAppender und DBAppender wenn Sie möchten, um die Leistung zu verbessern.
Option 2: Fallback-Option, wenn Sie keinen Zugriff auf den log4j Konfigurationsdatei des Katers
Statt Ihre eigene Datei ändern Hörer schreiben, Blick href="https://stackoverflow.com/questions/494869/file-changed-listener-in-java">. Wählen Sie das, das am besten Ihren Bedürfnissen entspricht. Sie werden dann mit dem Schreiben von Code zum Filtern und persistierende das Protokoll in DB nur links. Sie können diese Link als Beispiel für den Umgang mit Random.
Andere Tipps
Ich denke, es ist kein guter Weg, um neue hinzugefügt Linien zu überprüfen. Ich empfehle Ihnen, eine benutzerdefinierte appender für log4j zu schreiben. Mit einem benutzerdefinierten appender können Sie sich alle neu hinzugefügten Zeilen mit einem Ereignis bekommen. Es ist ein Beispiel hier
und Google für benutzerdefinierte appender.
Das erste, was ich in dieser Situation tun würde, waren das Thema Lesen eine wachsende Datei aus dem Problem trennen die Linien der Verarbeitung.
Erstellen Sie eine Klasse GrowingFileReader
deren readLine
Methode tut, was Sie wollen. Dann wird der Rest des Codes wird einfacher.
Im Falle eines ausgefallenen Spiel, warum aktualisieren Sie lastPosition
überhaupt? Sollte es nicht so bleiben, wie ist?
RAF Readline- ein Sperrverfahren und ist ineffizient (liest Byte für Byte und macht so viele Systemaufrufe) Beachten Sie, dass in Ihrem Code lines.getBytes (). Länge nicht genau wie die Methode Readline verwendet werden überspringt Newline / Wagenrücklauf Zeichen.
So verwenden BufferedReader auf RAF meine Antwort hier überprüfen https://stackoverflow.com/a/19867481/1282907