为什么不使用java.util.logging? [英] Why not use java.util.logging?

查看:139
本文介绍了为什么不使用java.util.logging?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我生命中第一次发现自己处于一个可以开源的Java API的位置。希望被包含在许多其他项目中。

For the first time in my life I find myself in a position where I'm writing a Java API that will be open sourced. Hopefully to be included in many other projects.

对于日志记录我(实际上和我一起工作的人)总是使用JUL(java.util.logging)而且从来没有任何问题。但是现在我需要更详细地了解我应该为我的API开发做些什么。我已经对此做了一些研究,而且我得到的信息让我感到更加困惑。因此这篇文章。

For logging I (and indeed the people I work with) have always used JUL (java.util.logging) and never had any issues with it. However now I need to understand in more detail what I should do for my API development. I've done some research on this and with the information I've got I just get more confused. Hence this post.

因为我来自JUL,所以我对此有偏见。我对其余的知识并不是那么大。

Since I come from JUL I'm biased on that. My knowledge of the rest is not that big.

从我所做的研究中我得出了人们不喜欢JUL的原因:

From the research I've done I've come up with these reasons why people do not like JUL:


  1. 在Sun发布JUL之前很久我就开始用Java开发了,我继续使用日志记录框架更容易 - X而不是学习新的东西。嗯。我不是在开玩笑,这实际上就是人们所说的。有了这个论点,我们都可以做COBOL。 (但我自己肯定会认为这是一个懒惰的家伙)

  1. "I started developing in Java long before Sun released JUL and it was just easier for me to continue with logging-framework-X rather than to learn something new". Hmm. I'm not kidding, this is actually what people say. With this argument we could all be doing COBOL. (however I can certainly relate to this being a lazy dude myself)

我不喜欢JUL中日志级别的名称 。好吧,说真的,这还不足以引入新的依赖。

"I don't like the names of the logging levels in JUL". Ok, seriously, this is just not enough of a reason to introduce a new dependency.

我不喜欢标准格式的JUL的输出。嗯。这只是配置。你甚至不需要做任何代码方面的事情。 (的确,过去你可能不得不创建自己的Formatter类来实现它。)

"I don't like the standard format of the output from JUL". Hmm. This is just configuration. You do not even have to do anything code-wise. (true, back in old days you may have had to create your own Formatter class to get it right).

我使用其他库也使用logging-framework-X所以我认为只使用那个更容易。这是一个循环论证,不是吗?为什么'每个人'都使用logging-framework-X而不是JUL?

"I use other libraries that also use logging-framework-X so I thought it easier just to use that one". This is a cyclic argument, isn't ? Why does 'everybody' use logging-framework-X and not JUL?

其他人都在使用logging-framework-X。这对我来说只是上面的一个特例。多数并不总是正确的。

"Everybody else is using logging-framework-X". This to me is just a special case of the above. Majority is not always right.

所以真正的大问题是为什么不是JUL? 。我错过了什么?伐木立面的存在理由(SLF4J,JCL)是历史上存在多种伐木实施,其原因可以追溯到JUL之前的时代,正如我所看到的那样。如果JUL是完美的那么伐木外墙将不存在,或者什么?我们不应该接受它们,而不应该首先质疑为什么它们是必要的? (看看这些原因是否仍然存在)

So the real big question is why not JUL?. What is it I have missed ? The raison d'être for logging facades (SLF4J, JCL) is that multiple logging implementations have existed historically and the reason for that really goes back to the era before JUL as I see it. If JUL was perfect then logging facades wouldn't exist, or what? Rather than embracing them shouldn't we question why they were necessary in the first place? (and see if those reasons still exist)

好的,到目前为止,我的研究已经导致了一些我可以看到的可能真正的问题与JUL:

Ok, my research so far has led to a couple of things that I can see may be real issues with JUL:


  1. 效果。有人说SLF4J的表现优于其他表现。在我看来,这是一个过早优化的案例。如果你需要每秒记录数百兆字节,那么无论如何我都不确定你是否在正确的路径上。 JUL也在不断发展,你在Java 1.4上做的测试可能不再适用。您可以在此处阅读此内容并修复此问题已经使它成为Java 7.许多人还谈到了日志记录方法中字符串连接的开销。但是,基于模板的日志记录避免了这种成本,它也存在于JUL中。我个人从来没有真正编写基于模板的日志记录太懒了。例如,如果我使用JUL执行此操作:

  1. Performance. Some say that performance in SLF4J is superior to the rest. This seems to me to be a case of premature optimization. If you need to log hundreds of megabytes per second then I'm not sure you are on the right path anyway. JUL has also evolved and the tests you did on Java 1.4 may no longer be true. You can read about it here and this fix has made it into Java 7. Many also talk about the overhead of string concatenation in logging methods. However template based logging avoids this cost and it exist also in JUL. Personally I never really write template based logging. Too lazy for that. For example if I do this with JUL:

log.finest("Lookup request from username=" + username 
   + ", valueX=" + valueX
   + ", valueY=" + valueY));

我的IDE会警告我并请求允许它将其更改为:

my IDE will warn me and ask permission that it should change it to:

log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}", 
   new Object[]{username, valueX, valueY});

..我当然会接受。许可授予 !感谢您的帮助。

.. which I will of course accept. Permission granted ! Thank you for your help.

所以我实际上并没有自己编写这样的语句,这是由IDE完成的。

So I don't actually write such statements myself, that is done by the IDE.

关于表现问题的结论我没有发现任何表明JUL的表现与竞争对手相比不好的事情。

In conclusion on the issue of performance I haven't found anything that would suggest that JUL's performance is not ok compared to the competition.

从类路径配置。开箱即用的JUL无法从类路径加载配置文件。这是一个几行代码。我可以看到为什么这可能很烦人,但解决方案简短而简单。

Configuration from classpath. Out-of-the-box JUL cannot load a configuration file from the classpath. It is a few lines of code to make it do so. I can see why this may be annoying but the solution is short and simple.

输出处理程序的可用性。 JUL带有5个开箱即用的输出处理程序:控制台,文件流,套接字和内存。这些可以扩展,也可以写新的。例如,这可能是写入UNIX / Linux Syslog和Windows事件日志。我个人从未有过这个要求,也没有看过它,但我当然可以说明为什么它可能是一个有用的功能。例如,Logback附带了Syslog的附加程序。我仍然认为

Availability of output handlers. JUL comes with 5 output handlers out-of-the-box: console, file stream, socket and memory. These can be extended or new ones can be written. This may for example be writing to UNIX/Linux Syslog and Windows Event Log. I have personally never had this requirement nor have I seen it used but I can certainly relate to why it may be a useful feature. Logback comes with an appender for Syslog for example. Still I would argue that


  1. 99.5%的输出目的地需求由JUL开箱即用的内容涵盖。

  2. 特殊需求可以通过JUL之上的自定义处理程序来满足,而不是在其他方面。对我来说,没有什么可以表明为JUL编写Syslog输出处理程序需要花费更多时间,而不是为另一个日志框架编写。


我真的很担心我忽略了一些东西。除了JUL之外,使用伐木外墙和伐木实施是如此普遍,我必须得出结论,我只是不明白。那恐怕不是第一次。 : - )

I'm really concerned that there's something I've overlooked. The use of logging facades and logging implementations other than JUL is so widespread that I have to come to the conclusion that it's me who just doesn't understand. That wouldn't be the first time, I'm afraid. :-)

那么我应该怎样处理我的API?我希望它成功。我当然可以顺其自然并实施SLF4J(这些日子似乎最受欢迎)但是为了我自己的缘故,我仍然需要了解今天的JUL究竟有什么问题需要保证所有的模糊?我会为我的图书馆选择JUL来破坏自己吗?

So what should I do with my API? I want it to become successful. I can of course just "go with the flow" and implement SLF4J (which seems the most popular these days) but for my own sake I still need to understand exactly what is wrong with the JUL of today that warrants all the fuzz? Will I sabotage myself by choosing JUL for my library ?

(nolan600于07年添加的部分-JUL-2012)

(section added by nolan600 on 07-JUL-2012)

下面有一篇来自Ceki的参考文献,其中提到SLF4J的参数化比JUL快10倍或更快。所以我开始做一些简单的测试。乍一看这个说法肯定是正确的。以下是初步结果(但请继续阅读!):

There's a reference below from Ceki about SLF4J's parametrization being 10 times or more faster than JUL's. So I've started doing some simple tests. At first glance the claim is certainly correct. Here are the preliminary results (but read on!):


  • 执行时间SLF4J,后端Logback:1515

  • 执行时间SLF4J,后端JUL:12938

  • 执行时间JUL:16911

上面的数字是msecs,所以越少越好。所以10倍的性能差异实际上非常接近。我最初的反应:这很多!

The numbers above are msecs so less is better. So 10 times performance difference is by first actually pretty close. My initial reaction: That is a lot !

这是测试的核心。可以看出,一个整数和一个字符串是在循环中构造的,然后在日志语句中使用:

Here is the core of the test. As can be seen an integer and a string is construted in a loop which is then used in the log statement:

    for (int i = 0; i < noOfExecutions; i++) {
        for (char x=32; x<88; x++) {
            String someString = Character.toString(x);
            // here we log 
        }
    }

(I希望log语句既包含原始数据类型(在本例中为int),也包含更复杂的数据类型(在本例中为String)。不确定它是否重要但是你有它。)

(I wanted the log statement to have both a primitive data type (in this case an int) and a more complex data type (in this case a String). Not sure it matters but there you have it.)

SLF4J的日志声明:

The log statement for 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被重定向到null设备。

The JVM was 'warmed up' with the same test executed once before the actual measurement was done. Java 1.7.03 was used on Windows 7. Latest versions of SLF4J (v1.6.6) and Logback (v1.0.6) was used. Stdout and stderr was redirected to null device.

但是,现在小心,事实证明JUL大部分时间都花在 getSourceClassName()因为JUL默认在输出中打印源类名,而Logback不输出。所以我们正在比较苹果和橘子。我必须再次进行测试,并以类似的方式配置日志记录实现,以便它们实际输出相同的内容。但是我确实怀疑SLF4J + Logback仍然会出现在顶部但远离上面给出的初始数字。请继续关注。

However, careful now, it turns out JUL is spending most of its time in getSourceClassName() because JUL by default prints the source class name in the output, while Logback doesn't. So we are comparing apples and oranges. I have to do the test again and configure the logging implementations in a similar manner so that they actually output the same stuff. I do however suspect that SLF4J+Logback will still come out on top but far from the initial numbers as given above. Stay tuned.

Btw:测试是我第一次真正使用SLF4J或Logback。愉快的经历。当你开始时,JUL肯定不那么热情。

Btw: The test was first time I've actually worked with SLF4J or Logback. A pleasant experience. JUL is certainly a lot less welcoming when you are starting out.

( nolan600于2012年7月8日添加的部分)

(section added by nolan600 on 08-JUL-2012)

事实证明,在JUL中如何配置模式对性能无关紧要,即是否它包括源名称与否。我尝试了一个非常简单的模式:

As it turns out it doesn't really matter for performance how you configure your pattern in JUL, i.e. whether or not it includes the source name or not. I tried with a very simple pattern:

java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"

这并没有改变上述时间。我的分析器显示,即使这不是我的模式的一部分,记录器仍然花费大量时间来调用 getSourceClassName()。这种模式并不重要。

and that did not change the above timings at all. My profiler revealed that the logger still spent a lot of time in calls to getSourceClassName() even if this was not part of my pattern. The pattern doesn't matter.

因此,我在性能问题上得出结论,至少对于基于测试模板的日志语句,似乎大致有一个因素10在JUL(慢)和SLF4J + Logback(快速)之间的实际性能差异。就像Ceki说的那样。

I'm therefore concluding on the issue of performance that at least for the tested template based log statement there seems to be roughly a factor of 10 in real performance difference between JUL (slow) and SLF4J+Logback (quick). Just like Ceki said.

我还可以看到另外一件事,即SLF4J的 getLogger()调用更多比JUL的同样昂贵。 (如果我的探查器准确,则为95 ms vs 0.3 ms)。这是有道理的。 SLF4J必须在底层日志记录实现的绑定上做一些时间。这不会吓到我。这些调用在应用程序的生命周期中应该是少见的。坚固度应该在实际的日志调用中。

I can also see another thing namely that SLF4J's getLogger() call is a lot more expensive than JUL's ditto. (95 ms vs 0.3 ms if my profiler is accurate). This makes sense. SLF4J has to do some time on the binding of the underlying logging implementation. This doesn't scare me. These calls should be somewhat rare in the lifetime of an application. The fastness should be in the actual log calls.

(nolan600在08-增加的部分) JUL-2012)

(section added by nolan600 on 08-JUL-2012)

感谢您的所有答案。与我最初的想法相反,我最终决定将SLF4J用于我的API。这是基于许多事情和您的输入:

Thank you for all your answers. Contrary to what I initially thought I've ended up deciding to use SLF4J for my API. This is based on a number of things and your input:


  1. 它提供了在部署时选择日志实施的灵活性。

  1. It gives flexibility to choose log implementation at deployment time.

在应用服务器内部运行时,JUL配置缺乏灵活性的问题。

Issues with lack of flexibility of JUL's configuration when run inside an application server.

SLF4J如上所述,如果你将它与Logback相结合,肯定会快得多。即使这只是一个粗略的测试,我也有理由相信在SLF4J + Logback上优化比在JUL上更多的努力。

SLF4J is certainly a lot faster as detailed above in particular if you couple it with Logback. Even if this was just a rough test I have reason to believe that a lot more effort has gone into optimization on SLF4J+Logback than on JUL.

文档。 SLF4J的文档更加全面和精确。

Documentation. The documentation for SLF4J is simply a lot more comprehensive and precise.

模式灵活性。当我进行测试时,我开始让JUL模仿Logback的默认模式。此模式包含线程的名称。事实证明,JUL不能开箱即用。好吧,我到目前为止还没有错过它,但我认为这不应该是日志框架中遗漏的东西。期!

Pattern flexibility. As I did the tests I set out to have JUL mimic the default pattern from Logback. This pattern includes the name of the thread. It turns out JUL cannot do this out of the box. Ok, I haven't missed it until now, but I don't think it is a thing that should be missing from a log framework. Period!

今天大多数(或许多)Java项目使用Maven,因此添加依赖项并不是那么重要,特别是如果该依赖项相当稳定,即不不断改变其API。 SLF4J似乎也是如此。此外,SLF4J罐子和朋友的体积都很小。

Most (or many) Java projects today use Maven so adding a dependency is not that big a thing especially if that dependency is rather stable, i.e. doesn't constantly change its API. This seems to be true for SLF4J. Also the SLF4J jar and friends are small in size.

所以发生的奇怪事情是我真的相当在与SLF4J合作之后,对JUL感到不满。我仍然感到遗憾的是,JUL必须采用这种方式。 JUL远非完美,但有点做这项工作。只是不太好。关于属性也可以这样说但是我们不考虑抽象,所以人们可以插入他们自己的配置库以及你有什么。我认为原因是属性位于条形图的上方,而今天的JUL则相反...而在过去,由于它没有不存在。

So the strange thing that happened was that I actually got quite upset with JUL after having worked a bit with SLF4J. I still regret that it has to be this way with JUL. JUL is far from perfect but kind of does the job. Just not quite well enough. The same can be said about Properties as an example but we do not think about abstracting that so people can plug in their own configuration library and what have you. I think the reason is that Properties comes in just above the bar while the opposite is true for JUL of today ... and in the past it came in at zero because it didn't exist.

推荐答案

免责声明:我是log4j,SLF4J和logback项目的创始人。

Disclaimer: I am the founder of log4j, SLF4J and logback projects.

偏好SLF4J有客观原因。首先, SLF4J允许最终用户自由选择底层日志框架。此外,更精明的用户倾向于更喜欢 logback,它提供的功能超出了log4j ,并且落后于jul 。对于某些用户来说,功能方面的j.u.l可能就足够了,但对于其他许多用户而言,它可能就足够了。简而言之,如果日志记录对您很重要,您可能希望将SLF4J与logback一起用作底层实现。如果日志记录不重要,j.u.l就可以了。

There are objective reasons for preferring SLF4J. For one, SLF4J allows the end-user the liberty to choose the underlying logging framework. In addition, savvier users tend to prefer logback which offers capabilities beyond log4j, with j.u.l falling way behind. Feature-wise j.u.l may be sufficient for some users but for many others it just isn't. In a nutshell, if logging is important to you, you would want to use SLF4J with logback as the underlying implementation. If logging is unimportant, j.u.l is fine.

但是,作为oss开发人员,您需要考虑用户的偏好而不仅仅是您自己的偏好。因此,您应该采用SLF4J,因为确信SLF4J优于j.u.l,但是因为大多数Java开发人员目前(2012年7月)更喜欢SLF4J作为他们的日志API。如果最终你决定不关心流行的意见,请考虑以下事实:

However, as an oss developer, you need to take into account the preferences of your users and not just your own. It follows that you should adopt SLF4J not because you are convinced that SLF4J is better than j.u.l but because most Java developers currently (July 2012) prefer SLF4J as their logging API. If ultimately you decide not to care about popular opinion, consider the following facts:


  1. 那些喜欢jul的人这样做是出于方便,因为jul是与JDK捆绑在一起。据我所知,没有其他客观论据支持jul

  2. 你自己对jul的偏好就是这样,一个偏好

  1. those who prefer j.u.l do so out of convenience because j.u.l is bundled with the JDK. To my knowledge there are no other objective arguments in favor of j.u.l.
  2. your own preference for j.u.l is just that, a preference.

因此,在公众舆论之上持有硬性事实,虽然看似勇敢,但在这种情况下是合乎逻辑的谬误。

Thus, holding "hard facts" above public opinion, while seemingly brave, is a logical fallacy in this case.

如果仍然不相信, JB Nizet 提出了另一个有力的论据:

If still not convinced, JB Nizet makes an additional and potent argument:


除了最终用户可能已经为他的
自己的代码或使用log4j或logback的其他库完成了这个自定义。 j.u.l是
可扩展,但是必须扩展logback,j.u.l,log4j和上帝只有
知道哪个其他日志框架,因为他使用四个库,
使用四个不同的日志框架是很麻烦的。通过使用SLF4J,你
允许他配置他想要的日志框架,而不是你选择的
请记住,一个典型的项目使用无数的
库,而不仅仅是你的

如果无论出于何种原因,你讨厌SLF4J API并使用它会扼杀你的工作带来的乐趣,然后一定要去jul毕竟,有办法将jul重定向到SLF4J

If for whatever reason you hate the SLF4J API and using it will snuff the fun out of your work, then by all means go for j.u.l. After all, there are means to redirect j.u.l to SLF4J.

顺便说一下,jul参数化比SLF4J慢至少10倍,最终会产生明显的差异。

By the way, j.u.l parametrization is at least 10 times slower than SLF4J's which ends up making a noticeable difference.

这篇关于为什么不使用java.util.logging?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆