缓冲记录器(Java)

时间:2011-11-16 21:38:55

标签: java logging log4j

我正在考虑构建一个日志系统,将日志语句推送到内部缓冲区,直到达到预定义的容量,然后立即转储(刷新)整个缓冲区。

这是因为我喜欢在我的方法中撒上大量的TRACE语句(所以我可以看到每几行都会发生什么;让调试变得更容易,至少对我而言)。而且我担心(可能)数百/数千个日志语句会触发整个地方,这样一个大的I / O需求会使我的程序陷入困境。

“缓冲”记录器解决方案可能会缓解这种情况。

三个问题:

  1. 这样的事情已经存在了吗?讨厌在这里重新发明轮子,但在线搜索没有回头任何事情。
  2. 我正在考虑这样一个事实:只要程序意外停止(运行时异常等)并且记录器没有被刷新,我就可以很好地丢失日志语句。在这种情况下,我希望记录器覆盖finalize(),这样如果程序终止仍然在其缓冲区中的项目,它可以在退出之前刷新(发布)它们。想法?
  3. 这是一个糟糕的主意吗?如果是这样,为什么!

6 个答案:

答案 0 :(得分:5)

如果可以避免,请不要重新发明这个特定的轮子。查看Log4j或更好slf4j

如果你没有跟踪,Log4j和slf4j都非常高效,所以在生产系统中你可以调低日志记录的水平并且仍然具有良好的性能。

log4j和slf4j都会立即写入日志文件并刷新,默认情况下不要执行缓冲,这是因为您希望在日志文件中看到导致崩溃的异常。如果你真的想要添加缓冲,你可以这样做(FileAppender#bufferedIO

就finalize()而言,不保证在退出时调用它。来自System#runFinalizersOnExit

  

已过时。这种方法本质上是不安全的。它可能导致   在其他线程所在的活动对象上调用终结器   同时操纵这些对象,导致不稳定的行为   或死锁。退出时启用或禁用完成;这样做   指定具有终结器的所有对象的终结器   还没有被自动调用的是在Java之前运行   运行时退出。 默认情况下,退出时终止

我的重点。所以,似乎缓冲记录器似乎没有固有的问题。

答案 1 :(得分:2)

我将证明你提出的第三个问题。这是一个可怕的想法,它与您作为程序员的技能无关。与它有关的是像log4j这样的项目所暴露的场景数量以及它们所考虑的不同边缘情况。我认为这项工作对你来说相当大,并且会引起很多麻烦。

答案 2 :(得分:1)

Log4J已经支持IO缓冲。关于Log4J here

的一些不错的性能提示

答案 3 :(得分:0)

不知道现有的框架,AFAIK在本地内存中没有“缓冲区”。但请查看标准的Log4J等。

finalize()不是正确的事。使用Runtime.addShutdownHook()。最近查看what I learned

答案 4 :(得分:0)

我们对生产服务器做了类似的事情,除了他们通过网络连接触发日志消息。我们只有一个有界链接队列,并决定弹出调试消息并在队列满时保持错误。然后我们在后台有一个线程将消息发送到服务器。

  1. 我不知道log4j或slf4j的一部分。

  2. 丢失消息的唯一方法是JVM崩溃,在这种情况下缓冲区编写器会遇到同样的问题。如果你编写的线程不是守护进程,那么它可以在应用程序停止运行之前完成日志消息的写入。

  3. 唯一的理由是,如果您的日志记录确实没有性能问题,那将是一个糟糕的主意。最好确保将日志记录调用隔离到自己的日志记录包装,以防需要将它们排队以备将来使用。但是对于短期来说只需写入log4j或其他任何内容。您还可以在此包装类中放置一些统计信息,以查看日志记录消息是否完全阻止了该过程,然后通过排队做出明智的决定以提高其性能。

答案 5 :(得分:0)

正如已经提到的 - 不要重新发明轮子 - 使用log4j甚至更好的logback(它的继承者),但明智地做。立即写入和刷新到磁盘的默认简单appender将影响应用程序的整体性能。通常,appender会在调用者的线程上进行繁重的工作。为了避免这种情况,您可以编写自己的appender,以异步方式(使用缓冲)或使用包装器 - 根据框架,您可以使用异步行为包装一些appender而无需编写单行代码。我有这样的appender here(见页面底部),你可以自由使用代码或只是想一想。我的appender适用于TCP套接字,但问题是相同的 - 防止阻塞调用者并在单独的线程上进行刷新,以便顶层的应用程序不会感觉到它。