为什么不使用java.util.logging?最终结论
这是我人生中第一次发现自己处于这样一个位置,我正在编写一个开源的Java API。希望能被纳入许多其他项目。
对于日志记录,我(以及与我一起工作的人)一直使用JUL(),并且从未遇到过任何问题。但是,现在我需要更详细地了解我应该为我的API开发做些什么。我对此做了一些研究,有了我得到的信息,我只是变得更加困惑。因此,这篇文章。java.util.logging
由于我来自7月,我对此有偏见。我对其余部分的了解并不大。
根据我所做的研究,我提出了人们不喜欢JUL的这些原因:
-
“早在 Sun 发布 JUL 之前,我就已经开始使用 Java 进行开发,对我来说,继续使用 logging-framework-X 比学习新东西更容易。嗯。我不是在开玩笑,这实际上是人们说的。有了这个论点,我们都可以做COBOL。(然而,我当然可以理解这是一个懒惰的家伙)
-
“我不喜欢 JUL 中日志记录级别的名称”。好吧,说真的,这还不足以成为引入新依赖项的理由。
-
“我不喜欢 JUL 输出的标准格式”。嗯。这只是配置。您甚至不必在代码方面执行任何操作。(没错,在过去,您可能必须创建自己的格式化程序类才能正确使用)。
-
“我使用其他也使用loging-framework-X的库,所以我认为使用那个库更容易”。这是一个循环论证,不是吗?为什么“每个人”都使用loging-framework-X而不是JUL?
-
“其他人都在使用loging-framework-X”。对我来说,这只是上述情况的一个特例。多数并不总是正确的。
所以真正的大问题是为什么不是JUL?。我错过了什么?日志记录外观(SLF4J,JCL)存在的理由是历史上存在多个日志记录实现,其原因实际上可以追溯到我所看到的JUL之前的时代。如果JUL是完美的,那么伐木立面就不会存在,或者什么?为了使事情更加混乱,JUL在某种程度上本身就是一个门面,允许处理程序,格式化程序甚至LogManager被交换。
与其采用多种方式来做同样的事情(日志记录),难道我们不应该质疑为什么它们首先是必要的吗?(看看这些原因是否仍然存在)
好吧,到目前为止,我的研究已经导致了一些事情,我可以看到可能是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的附加器。我仍然会争辩说
- 99.5%的输出目的地需求由 JUL 开箱即用的内容满足。
- 特殊需求可以通过在 JUL 之上而不是在其他事物之上的自定义处理程序来满足。在我看来,没有什么表明为 JUL 编写 Syslog 输出处理程序比为另一个日志记录框架编写 Syslog 输出处理程序需要更多的时间。
我真的很担心有些东西我忽略了。除 JUL 之外,日志记录外观和日志记录实现的使用非常普遍,以至于我不得不得出结论,就是我不明白。恐怕那已经不是第一次了。:-)
那么我应该如何处理我的 API 呢?我希望它成功。我当然可以“顺其自然”并实现SLF4J(这似乎是现在最流行的),但为了我自己,我仍然需要确切地了解今天的JUL有什么问题,需要所有的模糊?我会因为选择JUL作为我的图书馆而破坏自己吗?
测试性能
(nolan600 于 2012 年 7 月 7 日添加的部分)
Ceki下面有一个关于SLF4J参数化的参考,比JUL快10倍或更多。所以我开始做一些简单的测试。乍一看,这种说法肯定是正确的。以下是初步结果(但请继续阅读!
- 执行时间SLF4J,后端日志:1515
- 执行时间 SLF4J,后端 7 月:12938
- 执行时间 JUL: 16911
上面的数字是毫秒,所以越少越好。因此,性能差异的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在实际测量完成之前通过执行一次相同的测试进行“预热”。Java 1.7.03在Windows 7上使用。使用了最新版本的 SLF4J (v1.6.6) 和 Logback (v1.0.6)。Stdout 和 stderr 已重定向到空设备。
但是,现在要小心,事实证明 JUL 花费了大部分时间,因为 JUL 默认在输出中打印源类名,而 Logback 则不会。因此,我们正在比较苹果和橙子。我必须再次进行测试,并以类似的方式配置日志记录实现,以便它们实际上输出相同的内容。然而,我确实怀疑SLF4J + Logback仍将名列前茅,但与上面给出的初始数字相去甚远。敬请期待。getSourceClassName()
顺便说一句:这个测试是我第一次真正使用SLF4J或Logback。一次愉快的体验。当你开始时,JUL肯定不那么受欢迎。
测试性能(第 2 部分)
(nolan600 于 08 年 2012 月 <> 日添加的部分)
事实证明,在 JUL 中如何配置模式对于性能并不重要,即它是否包含源名称。我尝试了一个非常简单的模式:
java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"
这根本没有改变上述时间。我的分析器显示,记录器仍然花了很多时间进行调用,即使这不是我模式的一部分。模式无关紧要。getSourceClassName()
因此,我在性能问题上得出结论,至少对于经过测试的基于模板的日志语句,JUL(慢速)和SLF4J + Logback(快速)之间的实际性能差异似乎大约为10倍。就像Ceki说的。
我还可以看到另一件事,即SLF4J的调用比JUL的同类产品贵得多。(如果我的分析器准确无误,则为 95 毫秒与 0.3 毫秒)。这是有道理的。SLF4J 必须在底层日志记录实现的绑定上做一些时间。这不会吓到我。这些调用在应用程序的生存期内应该有些罕见。快速度应该在实际的日志调用中。getLogger()
最终结论
(nolan600 于 08 年 2012 月 <> 日添加的部分)
感谢您的所有回答。与我最初的想法相反,我最终决定使用SLF4J作为我的API。这是基于许多事情和您的输入:
-
它提供了在部署时选择日志实现的灵活性。
-
在应用程序服务器内运行时,JUL 配置缺乏灵活性的问题。
-
SLF4J肯定要快得多,如上所述,特别是如果您将其与Logback结合使用。即使这只是一个粗略的测试,我也有理由相信,在SLF4J + Logback上进行优化的努力比在JUL上付出了更多的努力。
-
文档。SLF4J的文档更加全面和精确。
-
图案灵活性。当我进行测试时,我开始让 JUL 模仿 Logback 的默认模式。此模式包括线程的名称。事实证明,JUL不能开箱即用地做到这一点。好吧,直到现在我还没有错过它,但我不认为这是日志框架中应该缺少的东西。时期!
-
如今,大多数(或许多)Java项目都使用Maven,因此添加依赖项并不是一件大事,特别是如果该依赖项相当稳定,即不会不断更改其API。对于SLF4J来说,这似乎是正确的。此外,SLF4J罐子和朋友的尺寸也很小。
所以奇怪的事情是,在与SLF4J合作过一段时间后,我实际上对JUL感到非常沮丧。我仍然感到遗憾的是,JUL必须以这种方式。JUL远非完美,但有点做这项工作。只是不够好。作为一个例子,也可以这样说,但我们不考虑抽象,这样人们就可以插入他们自己的配置库,你有什么。我认为原因是它出现在酒吧上方,而今天的七月则相反......在过去,它以零进入,因为它不存在。Properties
Properties