2010-12-20 2 views
3

파일을 listern해야합니다. 내용이 추가되면 새 줄을 읽고 새 줄의 내용을 처리합니다. 파일의 길이는 결코 줄어들지 않습니다 (실제로는 tomcat 로그 파일입니다).RandomAccessFile 문제

나는 다음과 같은 코드를 사용 :


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

지금, 내 문제를 파일의 새로운 라인에 기록되는 라인이 완료되지 않을 경우, 죽은 루프 것, 그 나오다. 예를 들어

, 바람둥이 파일에 새 라인을 작성하려고하는 경우 :

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" 

그리고 라인의 한 부분 (예를 들어, 작성 : < 10.33.2.45 - - [08/Dec/2010 : 08 : 44 : 43 +0800] "GET /poi.txt HTTP/1.1"200 672>) 이제 정의 된 패턴과 일치 할 수 없으므로, 작동하므로 파일 포인터를 롤백하고 2 초 동안 기다렸다가 다시 읽으려고합니다.

잠자기 시간 동안, 라인의 마지막 부분이 아직 쓰여질 수 있습니다. (필자는 테스트를 위해 바람둥이 라기보다는 사실 쓰고 있습니다.) 제 생각에, randomaccessfile은 패턴과 일치 할 수있는 새로운 라인을 읽습니다. 아니.

코드를 확인할 수있는 사람은 누구입니까?

참고 : 로그 파일의 형식은 다음과 같이 "결합"된다

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" 
+0

내 대답을 확인 RAF에서의 BufferedReader를 사용합니다. 또한, pls하지 않습니다. – Will

+0

로그에 둘 이상의 행이있는 샘플 로그 파일을 게시하고 또한 정확히 무엇이 문제인지 알 수 없음 –

답변

3

귀하의 주된 목적은 log entries/events을 필터링 한 다음 필터링 된 로그를 데이터베이스에 쓰는 것입니다. 2 가지 옵션이 있습니다

옵션 1 :최선의 방법입니다. 하지만 tomcat과 함께 제공되는 log4j 설정 파일을 변경할 수 있어야합니다.

이 경우 가장 좋은 방법은 log4j의 사전 정의 된 확장 점을 사용하는 것입니다. 귀하의 경우에는 태핑 점은 이미 Appender

Log4j는 당신이 정규 표현식을 사용하여 로그를 필터링과 잘 테스트로 다음 DBAppender 나머지를 위임 확장 할 수있는 DBAppender와 함께 제공됩니다. 다음은

log4j.rootLogger = DEBUG 펜더 손님,

log4j.appender.S = com.gurock.smartinspect.log4j S

을 구성하는 방법에 대한 예입니다.MyCustomAppender

log4j.appender.S.layout = org.apache.log4j.SimpleLayout

난 당신이 또한 성능을 향상하려는 경우 AsyncAppender 및 DBAppender를 사용하여 보는 것이 좋습니다.

옵션 2 : 대체 옵션이

하는 대신 자신의 파일 변경 청취자를 작성하는 바람둥이의의 log4j 설정 파일에 액세스 할 수없는 경우, this post in SO을 찾습니다. 귀하의 필요에 가장 잘 맞는 것을 선택하십시오. 그런 다음 DB에 로그를 유지하고 필터링하기위한 코드를 작성해야합니다. 이 link as an example을 RandomAccessFile 처리에 사용할 수 있습니다.

+0

tomcat의 로그가 log4j에 의해 생성되고 로그가 localhost_access_log.2010-12-20에 기록됨을 의미합니까? .txt, 또한 db에 기록 될 수 있습니까? db를 탐색하기 전에 필터링을 할 수 있습니까? – hguser

+0

나는 tomcat도 log4j를 사용하여 로그를 생성한다고 추측하고있다. 그렇다면 필터링하고 필자의 게시물을 따라 db에 쓸 수 있습니다. 로그가 log4j에 의해 생성되지 않으면 옵션 2가 남습니다. –

0

나는 그것이 새로운 추가 라인을 확인하는 좋은 방법이 아니다라고 생각합니다. log4j에 대한 사용자 정의 appender 작성하는 것이 좋습니다. 사용자 정의 appender를 사용하면 이벤트가 추가 될 때마다 새로 추가 된 행을 얻을 수 있습니다. 샘플이 있습니다 here

그리고 google for custom appender가 있습니다.

0

이 상황에서 내가 할 첫 번째 일은 늘어나는 파일을 읽는 문제와 줄 처리 문제를 구분하는 것이 었습니다.

readLine 메서드가 원하는대로 수행되는 GrowingFileReader 클래스를 만듭니다. 나머지 코드는 더 간단 해집니다.

일치하지 않는 경우에는 lastPosition을 전혀 업데이트하지 않는 이유는 무엇입니까? 그대로 두어야하지 않습니까?

+0

raf.getFilePointer() - line.getBytes(). length ;;를 사용하여 차이점은 무엇입니까? – hguser

0

RAF의 readline은 블로킹 방법이며 비효율적입니다 (1 바이트 단위로 읽고 많은 시스템 호출을합니다). 또한 코드 라인에서 readLine 메서드가 newline/carriage를 건너 뛸 때 정확하게 사용할 수 없습니다. 반환 문자.

당신은 현상금을 제공하는 시도 할 수 있습니다 여기 https://stackoverflow.com/a/19867481/1282907