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"
War es hilfreich?

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

konfigurieren

log4j.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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top