扩展log4j / slf4j记录器

时间:2018-10-26 14:26:34

标签: java multithreading logging thread-safety

我处于多个线程(来自同一JVM)正在写入同一文件(使用Logger进行记录)的情况。 我需要在某个时候删除此文件,下次使用logger会创建该文件并进行记录。

日志记录库是同步的,因此我不必担心并发日志记录到同一文件。

但是...我想添加一个操作该文件的外部操作,并且此操作是删除文件,因此我必须以某种方式将日志记录(Logger)与此删除操作进行同步,因为我不想删除记录器正在工作时保存文件。

我想到的事情:

  1. 使用 FileChannel.lock 来锁定文件,Logger也会这样做。由于这个原因,我决定反对:
  

文件锁代表整个Java虚拟机保留。他们   不适合控制多个线程对文件的访问   在同一虚拟机中。

在我的情况下(相同的JVM,多个线程)这将不会导致我想要的效果。

我有什么选择?

我在这里错过了重要的东西吗?

也许有一种方法可以使用Logger中已经存在的东西吗?

3 个答案:

答案 0 :(得分:1)

似乎您正在寻找日志滚动和日志归档功能。日志滚动是Log4j和Logback(也包括SLF4j)的常见功能。

您可以配置日志记录库以根据当前文件的大小或一天中的时间创建一个新的日志文件。您可以为滚动文件配置文件名格式,然后进行外部进程归档或删除旧的滚动日志文件。

您可以参考this答案中给出的Log4j 2配置。

答案 1 :(得分:0)

文件系统通常由OS同步,因此您可以简单地删除文件而不必担心锁或其他问题。但是,根据log4j锁定文件的方式,删除过程可能会失败,因此您需要添加重试循环。

int attempts = 3;
final File logfile = new File(theLogFilePath);
while ((attempts > 0) && logfile.exists() && !logfile.delete()) {
  --attempts;
  try {
    Thread.sleep(1000);
  } catch (InterruptedException e) {
    attempts = 0;
  }
}

这不是完全干净的代码,但是您所做的仍然不是干净的。 ;)

您相当粗鲁地干扰了日志记录过程,但是由于用户也可以随时删除该文件,因此log4j应该妥善处理。最糟糕的情况是,我将要记录的消息会丢失,但是考虑到您仍然只是删除日志文件,这可能不是问题。

有关更清洁的实现,请参见this question

答案 2 :(得分:0)

我在过去没有其他选择时使用的技巧(请参阅Saptarshi Basu的日志滚动建议https://stackoverflow.com/a/53011323/823393)是仅重命名当前日志文件。

重命名后,排队等待进行的所有未完成的日志记录将继续进入重命名的日志记录。通常,任何新的日志请求都会创建一个新文件。

剩下的就是清理重命名的文件了。通常,您可以使用一些外部过程来管理此问题,或者只要此过程触发就删除任何旧的日志文件。