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

查看:22
本文介绍了为什么不使用 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 进行开发,对我来说继续使用 logging-framework-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 circular 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 是完美的,那么日志外观将不存在,或者什么?更令人困惑的是,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? To make matters more confusing JUL is to some extent a facade itself, allowing Handlers, Formatters and even the LogManager to be swapped.

与其采用多种方式来做同一件事(日志记录),我们难道不应该首先质疑为什么它们是必要的吗?(看看这些原因是否仍然存在)

Rather than embracing multiple ways of doing the same thing (logging), 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 系统日志和 Windows 事件日志.我个人从未有过这个要求,也没有见过它被使用过,但我当然可以理解为什么它可能是一个有用的功能.例如,Logback 带有一个用于 Syslog 的 appender.我仍然认为

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. 7 月开箱即用的内容涵盖了 99.5% 的输出目的地需求.
  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 于 2012 年 7 月 7 日添加的部分)

下面有来自 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,后端 7 月:12938
  • 执行时间 7 月:16911

上面的数字是毫秒,所以越少越好.所以 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 
        }
    }

(我希望 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).标准输出和标准错误被重定向到空设备.

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.

顺便说一句:该测试是我第一次实际使用 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 日添加的部分)

事实证明,在 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.

因此,我总结了性能问题,至少对于基于测试模板的日志语句来说,JUL(慢)和 SLF4J+Logback(快)之间的实际性能差异似乎大约是 10 倍.就像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 毫秒与 0.3 毫秒).这是有道理的.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 于 2012 年 7 月 8 日添加的部分)

感谢您的所有回答.与我最初的想法相反,我最终决定将 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 jar 和朋友的体积都很小.

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 远非完美,但可以完成这项工作.只是不够好.以 Properties 为例,也可以这样说,但我们不考虑将其抽象化,以便人们可以插入他们自己的配置库以及您拥有的内容.我认为原因是 Properties 刚好位于条形上方,而今天的 7 月正好相反……而在过去,它之所以为零,是因为它不存在.

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 的功能,而 j.u.l 远远落后.功能方面的 j.u.l 可能对某些用户来说就足够了,但对许多其他用户来说却不是.简而言之,如果日志记录对您很重要,您可能希望使用带有 logback 的 SLF4J 作为底层实现.如果日志记录不重要,则 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. 那些喜欢 j.u.l 的人是为了方便,因为 j.u.l 与 JDK 捆绑在一起.据我所知,没有其他客观论据支持 j.u.l.
  2. 你自己对 j.u.l 的偏好就是这样,偏好.

因此,将确凿的事实"置于舆论之上,虽然看似勇敢,但在这种情况下是一种逻辑谬误.

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 和 God知道其他哪个日志记录框架,因为他使用了四个库使用四种不同的日志框架很麻烦.通过使用 SLF4J,您允许他配置他想要的日志框架,而不是那个你已经选择.请记住,一个典型的项目使用无数图书馆,而不仅仅是你的.

Except the end user could have already done this customization for his own code, or another library that uses log4j or logback. j.u.l is extensible, but having to extend logback, j.u.l, log4j and God only knows which other logging framework because he uses four libraries that use four different logging frameworks is cumbersome. By using SLF4J, you allow him to configure the logging frameworks he wants, not the one you have chosen. Remember that a typical project uses myriads of libraries, and not just yours.

如果出于某种原因您讨厌 SLF4J API 并且使用它会扼杀您工作中的乐趣,那么请务必选择 j.u.l.毕竟,有办法将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.

顺便说一下,j.u.l 参数化至少比 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天全站免登陆