为什么不使用java.util.logging?
这是我一生中第一次发现自己处于一个我正在编写一个开源Java API的位置。 希望被纳入许多其他项目。
对于日志记录,我(和我工作的人)总是使用JUL(java.util.logging),并且从来没有任何问题。 但是现在我需要更详细地了解我应该为我的API开发做些什么。 我已经对此进行了一些研究,并且我得到的信息让我更加困惑。 因此这篇文章。
因为我来自JUL,所以我对此很有偏见。 我对其余的知识并不那么大。
从我所做的研究中,我想出了人们不喜欢JUL的原因:
“早在Sun发布JUL之前我就开始用Java开发,并且对我来说继续使用logging-framework-X而不是学习新东西更容易。 嗯。 我不是在开玩笑,这实际上是人们说的。 有了这个论点,我们都可以做COBOL。 (但是我当然可以把这当作是一个懒惰的家伙)
“我不喜欢JUL的伐木水平名称”。 好吧,严重的是,这仅仅是不足以引入新的依赖关系。
“我不喜欢JUL输出的标准格式”。 嗯。 这只是配置。 你甚至不需要在代码方面做任何事情。 (的确,在过去,你可能必须创建自己的Formatter类才能正确使用它)。
“我使用其他也使用logging-framework-X的库,所以我认为仅仅使用它就更容易。” 这是一个循环论证,不是吗? 为什么'每个人'都使用logging-framework-X而不是JUL?
“每个人都在使用logging-framework-X”。 这对我来说只是上述的一个特例。 多数并不总是对的。
所以真正的大问题是为什么不是JUL? 。 我错过了什么? 登录门面的存在理由(SLF4J,JCL)是历史上存在多种日志实现方式,其原因实际上可以追溯到JUL发现之前的时代。 如果JUL是完美的,那么登录门面不会存在,或者什么? 我们不应该问他们为什么必须摆在首位? (并看看这些原因是否仍然存在)
好的,到目前为止,我的研究已经导致了一些我可以看到的问题 ,可能是JUL的真正问题 :
性能 。 有人说SLF4J的表现优于其他。 这在我看来是一个过早优化的例子。 如果你需要记录每秒数百兆字节,那么我不确定你是否在正确的道路上。 JUL也已经发展,并且您在Java 1.4上所做的测试可能不再成立。 你可以在这里阅读它,并且这个修复已经将它写入了Java 7中。许多人还谈到了日志记录方法中字符串串联的开销。 然而,基于模板的日志记录避免了这种成本,并且在JUL中也存在。 我个人从未真正写过基于模板的日志记录。 太懒了。 例如,如果我在JUL上做这件事:
log.finest("Lookup request from username=" + username
+ ", valueX=" + valueX
+ ", valueY=" + valueY));
我的IDE会警告我并请求允许它将其更改为:
log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}",
new Object[]{username, valueX, valueY});
..我当然会接受。 许可授予 ! 感谢您的帮助。
所以我实际上并没有自己编写这样的语句,这是由IDE完成的。
关于表演问题的结论我没有发现任何可能表明JUL的表现与比赛相比并不好的事情。
从类路径配置 。 开箱即用的JUL无法从类路径加载配置文件。 这是几行代码。 我可以看到为什么这可能会令人讨厌,但解决方案很简单。
输出处理程序的可用性 。 JUL自带5个输出处理程序:控制台,文件流,套接字和内存。 这些可以扩展或者可以写入新的。 例如,这可以写入UNIX / Linux系统日志和Windows事件日志。 我个人从来没有这样的要求,也没有看到它的使用,但我可以肯定它为什么可能是一个有用的功能。 例如,Logback带有一个用于Syslog的appender。 我仍然会争辩说
我真的很担心,我忽略了一些东西。 JUL以外的日志外观和日志实现的使用非常广泛,我必须得出这样的结论,即我是不明白的。 恐怕这不会是第一次。 :-)
那么我应该如何处理我的API? 我希望它成功。 我当然可以“顺其自然”地执行SLF4J(目前看来最受欢迎),但是为了我自己的缘故,我仍然需要明白今天的JUL有什么问题可以保证所有的模糊性? 我会为我的图书馆选择JUL来破坏自己吗?
测试性能
(2012年7月7日由nolan600添加的部分)
以下是来自Ceki的关于SLF4J参数化的参考,比JUL快10倍或更多。 所以我开始做一些简单的测试。 乍一看,这个说法当然是正确的。 以下是初步结果(但请继续阅读!):
上面的数字是msecs,所以越少越好。 所以10倍的性能差异实际上非常接近。 我最初的反应是:很多!
这是测试的核心。 可以看出,一个整数和一个字符串被构建在一个循环中,然后在log语句中使用它:
for (int i = 0; i < noOfExecutions; i++) {
for (char x=32; x<88; x++) {
String someString = Character.toString(x);
// here we log
}
}
(我希望log语句具有原始数据类型(在本例中为int)和更复杂的数据类型(在本例中为String)。不确定它是否重要,但是您有它。)
SLF4J的日志语句:
logger.info("Logging {} and {} ", i, someString);
JUL的日志声明:
logger.log(Level.INFO, "Logging {0} and {1}", new Object[]{i, someString});
在实际测量完成之前,JVM被一次性地执行了相同的测试。 在Windows 7上使用了Java 1.7.03。使用了SLF4J(v1.6.6)和Logback(v1.0.6)的最新版本。 Stdout和stderr被重定向到空设备。
然而,现在请注意,JUL花费大部分时间在getSourceClassName()
因为JUL默认在输出中输出源类名,而Logback则不会。 所以我们比较苹果和橘子。 我必须再次进行测试,并以类似的方式配置日志实现,以便它们实际输出相同的东西。 然而,我确实怀疑SLF4J + Logback仍然排名靠前,但远远低于上面给出的数字。 敬请关注。
顺便说一句:测试是我第一次使用SLF4J或Logback。 愉快的体验。 当你出发时,JUL肯定会少得多。
测试性能(第2部分)
(由2012年7月8日nolan600添加的部分)
事实证明,如何在JUL中配置模式对性能无关紧要,即它是否包含源名称。 我尝试了一个非常简单的模式:
java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"
并没有改变上述时机。 我的分析器显示记录器仍然花费了大量的时间调用getSourceClassName()
即使这不是我的模式的一部分。 模式并不重要。
因此,我总结了性能问题,至少对于基于测试模板的日志语句,JUL(慢速)和SLF4J + Logback(快速)之间的实际性能差异似乎大致为10倍。 就像Ceki说的那样。
我还可以看到另一件事情,即SLF4J的getLogger()
调用比JUL的同上要贵很多。 (如果我的分析器是准确的话,则为95 ms vs 0.3 ms)。 这是有道理的。 SLF4J必须在底层日志实现的绑定上花费一些时间。 这不会吓到我。 这些调用在应用程序的生命周期中应该是比较少见的。 牢度应该在实际的日志调用中。
定论
(由2012年7月8日nolan600添加的部分)
感谢您的答复。 与我最初认为我最终决定为我的API使用SLF4J相反。 这是基于一些事情和您的输入:
它提供了在部署时选择日志实施的灵活性。
在应用程序服务器中运行时JUL配置缺乏灵活性的问题。
如果你将它与Logback结合起来,SLF4J的速度肯定会更快。 即使这只是一个粗略的测试,我仍然有理由相信SLF4J + Logback上的优化比在JUL上做了更多的努力。
文档。 SLF4J的文档更加全面和精确。
模式灵活性。 正如我所做的测试,我设定让JUL模仿Logback的默认模式。 该模式包含线程的名称。 事实证明,JUL无法做到这一点。 好的,到现在为止我还没有错过它,但我不认为这是应该从日志框架中丢失的东西。 期!
如今,大多数(或许多)Java项目都使用Maven,因此添加依赖项并不是什么大事,特别是如果依赖关系相当稳定,即不会不断更改它的API。 对于SLF4J来说这似乎是正确的。 SLF4J瓶子和朋友的体积也很小。
所以发生的奇怪之处在于,在与SLF4J合作后,我实际上对JUL感到非常不安。 我仍然很遗憾,它必须和JUL一样。 JUL远非完美,但这种工作很有帮助。 只是不够好。 关于Properties
也可以这样说,但我们不考虑抽象,以便人们可以插入他们自己的配置库以及你有什么。 我认为原因是Properties
刚好在酒吧的上方,而今天的JUL则恰好相反......过去,因为它不存在,因此它的值为零。
免责声明 :我是log4j,SLF4J和logback项目的创始人。
喜欢SLF4J有客观的原因。 首先,它授予最终用户选择底层日志记录框架的自由。 另外,喜欢用户的人更喜欢logback,它提供了log4j以外的功能,而且jul落后了。 对于某些用户来说,功能明智的jul可能已经足够,但对于许多其他用户来说却不是。 简而言之,如果日志记录对您很重要,您可能希望将SLF4J和logback作为基础实施。 如果日志记录不重要,那么jul就可以。
但是,作为oss开发人员,您需要考虑用户的偏好,而不仅仅是您自己的偏好。 因此,您应该采用SLF4J并不是因为您确信SLF4J比jul更好,而是因为目前大多数Java开发人员(2012年7月)都更喜欢SLF4J作为其日志API。 如果最终你决定不关心民意,请考虑以下事实:
因此,在这种情况下,将“硬性事实”置于舆论之上,虽然看起来很勇敢,但这是一种逻辑谬误。
如果仍然不相信,JB Nizet会提出一个更有力的论点:
除了最终用户可能已经为自己的代码或使用log4j或logback的另一个库完成了此定制。 jul是可扩展的,但必须扩展logback,jul,log4j和God只知道哪个其他日志框架,因为他使用了四个使用四个不同日志框架的库,这很麻烦。 通过使用SLF4J,您可以让他配置他想要的日志框架,而不是您选择的日志框架。 请记住,一个典型的项目使用无数的图书馆,而不仅仅是你的图书馆 。
如果因为某种原因你讨厌SLF4J API并使用它将会减少你工作中的乐趣,那么通过一切手段去争取JUL毕竟,有办法将jul重定向到SLF4J。
顺便说一下,jul参数化至少比SLF4J慢10倍,最终导致显着差异。
java.util.logging
是在Java 1.4 java.util.logging
引入的。 在此之前有用于日志记录的情况,这就是为什么有许多其他日志API存在的原因。 那些在Java 1.4之前大量使用的API,因此在1.4发布时,它们的市场份额并不只是下降到0。
JUL没有提到所有那些很好的东西,你提到的很多东西在1.4中糟糕得多,而且在1.5中只有更好(我猜也是在6中,但我不太确定)。
JUL不适合在同一个JVM中使用不同配置的多个应用程序(想象不应该交互的多个Web应用程序)。 Tomcat需要跳过一些环节才能实现这个目标(如果我理解正确的话,有效地重新实现JUL)。
你不能总是影响你的库使用什么日志框架。 因此,使用SLF4J(实际上是其他库之上的非常薄的API层)有助于保持整个日志记录世界的某种一致性图像(这样您可以决定底层日志记录框架,同时仍在同一系统中记录库)。
图书馆不能轻易改变。 如果以前版本的库用于使用logging-library-X,那么它不能轻易切换到logging-library-Y(例如JUL),即使后者显然是最好的:该库的任何用户都需要学习新的日志框架和(至少)重新配置日志。 这是一个很大的禁忌,特别是当它对大多数人没有明显的收益时。
说完所有我认为JUL现在至少是其他日志框架的有效替代方案。
恕我直言,使用像slf4j这样的日志外观的主要优点是你可以让库的最终用户选择他想要的具体日志实现,而不是将你的选择强加给最终用户。
也许他已经在Log4j或LogBack(特殊格式化器,appender等)上投入了时间和金钱,并且倾向于继续使用Log4j或LogBack,而不是配置jul。 没问题:slf4j允许。 在JUL上使用Log4j是明智的选择吗? 也许,也许不是。 但你不在乎。 让最终用户选择他喜欢的东西。
链接地址: http://www.djcxy.com/p/85797.html