我必须监听一个文件,当它的内容被添加时,我将读取新行,并处理新行的内容。文件的长度永远不会减少。(实际上,它是tomcat日志文件)。
我使用以下代码:
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();
}
}现在,我的问题是,如果正在写入文件的新行的一行未完成,则会出现一个死循环。
例如,如果tomcat试图向文件写入新行:
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"当只编写一行(example:<10.33.2.45-08/Dec/2010:08:44:43 +0800 "GET /poi.txt HTTP/1.1“200 672>)时,由于它与我定义的模式不匹配,也就是说,tomcat没有完成它的编写工作,所以我将尝试回滚文件指针,然后睡眠2秒,然后再读一遍。
在睡眠期间,行的最后一部分可能还没有写好(实际上是我写的,而不是tomcat测试),在我看来,随机访问文件将读取一个新的行,它可以与模式相匹配,但是它似乎不是。
有人能查一下密码吗?
注意事项:日志文件的格式是“组合”的,如下所示:
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"发布于 2010-12-24 17:53:47
我从您的代码中看到,您的主要目标是过滤日志条目/事件,然后将过滤后的日志写入数据库。你有两个选择
选项1:最佳和正确的方法。但是您应该能够更改tomcat附带的log4j配置文件。
如果是这样的话,那么最好的方法就是使用log4j的预定义扩展点。在您的例子中,点击点是阿彭德
Log4j已经附带了您可能希望扩展的DBAppender,以便使用正则表达式过滤日志,然后在经过良好测试后将其余部分委托给DBAppender。下面是关于如何配置custome appender的示例
log4j.rootLogger=DEBUG,S log4j.appender.S=com.gurock.smartinspect.log4j.MyCustomAppender log4j.appender.S.layout=org.apache.log4j.SimpleLayout
如果您想要提高性能,我建议您也考虑使用AsyncAppender和DBAppender。
选项2:如果您无法访问tomcat的log4j配置文件,则选择回退
与其编写您自己的文件更改监听器,不如查看这个职位是如此。选择一个最适合你的需求。然后只剩下编写代码来过滤和持久化DB中的日志。您可以使用这个链接为例来处理RandomAccessFile。
发布于 2010-12-24 16:46:21
我认为这不是检查新增加的行的好方法。我建议您为log4j编写一个自定义附录。使用自定义的附加器,您可以获得每个新添加的带有事件的行。有一个示例这里
和谷歌的定制附录。
发布于 2010-12-27 00:02:25
在这种情况下,我要做的第一件事是将读取不断增长的文件的问题与处理行的问题分开。
创建一个类GrowingFileReader,其readLine方法可以满足您的需要。然后代码的其余部分变得更简单。
如果匹配失败,为什么要更新lastPosition呢?不应该原样吗?
https://stackoverflow.com/questions/4486620
复制相似问题