为什么不使用之后呢?

时间:2022-09-25 11:02:47

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.

这是我有生以来第一次发现自己处于这样的境地:我正在编写一个开源的Java 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 (java.util.logging),从来没有遇到任何问题。但是现在我需要更详细地了解我应该为API开发做什么。我对此做了一些研究,得到的信息让我更加困惑。因此这篇文章。

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

因为我来自七月,所以我对那有偏见。我对其余的知识没有那么大。

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

从我所做的研究中,我发现了人们不喜欢JUL的原因:

  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)

    “早在Sun发布JUL之前,我就开始在Java中进行开发了,对我来说,继续使用logging- frameworkx比学习新的东西要容易得多”。嗯。我不是开玩笑,这是人们说的。有了这个论点,我们就可以做COBOL了。(不过我自己也很懒)

  2. "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上的日志级别。”好吧,说真的,这还不足以成为引入新依赖项的理由。

  3. "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).

    “我不喜欢JUL输出的标准格式”。嗯。这是配置。你甚至不需要做任何代码上的事情。(的确,在以前,您可能需要创建自己的Formatter类才能正确地使用它)。

  4. "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的库,因此我认为使用那个库更容易些”。这是一个循环论证,不是吗?为什么“每个人”都使用logging- frameworkx而不是JUL?

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

    “其他人都在使用loggingframeworkx”。这对我来说只是上述的一个特例。多数并不总是正确的。

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)

所以真正重要的问题是为什么不呢?我错过了什么?日志方面(SLF4J, JCL)存在的理由是,历史上存在过多种日志实现,我认为这可以追溯到7月之前的时代。如果JUL是完美的,那么伐木外立面就不存在了,或者什么?与其拥抱它们,我们难道不应该首先质疑它们为什么是必要的吗?(看看这些理由是否仍然存在)

Ok, my research so far has led to a couple of things that I can see may be real issues with 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:

    的性能。有人说SLF4J的性能优于其他的。在我看来,这似乎是一个过早优化的例子。如果你需要每秒记录几百兆字节,那么我不确定你的路径是否正确。JUL也有所发展,您在Java 1.4上所做的测试可能不再正确。您可以在这里阅读它,这个补丁已经将它变成了Java 7。许多人还讨论了日志记录方法中字符串连接的开销。然而,基于模板的日志记录避免了这种成本,而且它也存在于JUL.个人中,我从来没有真正编写过基于模板的日志记录。太懒了。举个例子,如果我在7月这样做:

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

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

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

    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.

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

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

    我自己不写这样的语句,这是IDE做的。

    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.

    综上所述,我没有发现任何迹象表明朱尔的表现与竞争对手相比是不合格的。

  2. 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无法从类路径加载配置文件。只需要几行代码就可以实现。我明白为什么这可能很烦人,但解决方法很简单。

  3. 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

    输出处理程序的可用性。JUL提供了5个现成的输出处理程序:控制台、文件流、套接字和内存。这些可以扩展,也可以编写新的。例如,可以将其写入UNIX/Linux Syslog和Windows事件日志。我个人从未有过这个要求,也没有见过它被使用过,但我肯定能理解为什么它可能是一个有用的特性。例如,Logback带有Syslog的appender。但我还是要说

    1. 99.5% of the needs for output destinations are covered by what is in JUL out-of-the-box.
    2. 对于输出目的地的99.5%的需求由JUL开箱即用的内容所覆盖。
    3. Special needs could be catered for by custom handlers on top of JUL rather than on top of something else. There's nothing to me that suggests that it takes more time to write a Syslog output handler for JUL than it does for another logging framework.
    4. 特殊需求可以由JUL上的自定义处理程序来满足,而不是在其他东西上。对于我来说,没有什么可以说明为JUL编写Syslog输出处理程序比为另一个日志框架花费更多的时间。

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. :-)

我真的很担心我忽略了一些东西。除了JUL之外,日志facades和日志实现的使用非常广泛,我不得不得出这样的结论,那就是我自己不明白。恐怕这不是第一次了。:-)

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 ?

那么我应该如何使用我的API呢?我希望它成功。当然,我可以“随波逐流”并实现SLF4J(这似乎是最近最流行的),但就我个人而言,我仍然需要确切地了解,今天的7月究竟出了什么问题,导致了所有的模糊?我会选择JUL作为我的图书馆来破坏我自己吗?

Testing performance

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

(nolan600在2012年7月至7月添加的部分)

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!):

下面有一个来自Ceki的引用,关于SLF4J的参数化比JUL快10倍或更多。我开始做一些简单的测试。乍一看,这种说法当然是正确的。以下是初步结果(但请继续阅读!)

  • Execution time SLF4J, backend Logback: 1515
  • 执行时间SLF4J,后端登录:1515
  • Execution time SLF4J, backend JUL: 12938
  • 执行时间SLF4J,后端JUL: 12938
  • Execution time JUL: 16911
  • 执行时间7月:16911

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 !

上面的数字是msecs,所以越少越好。所以10乘以性能差首先是非常接近的。我的第一反应是:这太多了!

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 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.)

(我希望日志语句同时具有原始数据类型(在本例中为int)和更复杂的数据类型(在本例中为字符串)。我不确定它是否重要,但它就在那里。

The log statement for SLF4J:

SLF4J的日志语句:

logger.info("Logging {} and {} ", i, someString);

The log statement for JUL:

7月的日志:

logger.log(Level.INFO, "Logging {0} and {1}", new Object[]{i, someString});

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.

在实际的度量完成之前,通过执行一次相同的测试来“热身”JVM。在Windows 7上使用了Java 1.7.03。使用了SLF4J (v1.6.6)和Logback (v1.0.6)的最新版本。Stdout和stderr被重定向到空设备。

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.

然而,现在要注意的是,JUL大部分时间都在getSourceClassName()中,因为JUL默认地在输出中打印源类名,而Logback则不打印。我们在比较苹果和橘子。我必须再次进行测试,并以类似的方式配置日志实现,以便它们实际上输出相同的内容。然而,我确实怀疑SLF4J+Logback仍然会排在最前面,但与上面给出的初始数字相去甚远。请继续关注。

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.

顺便说一句:这个测试是我第一次使用SLF4J或Logback。一个令人愉快的体验。当你刚开始的时候,朱儿肯定不那么受欢迎了。

Testing performance (part 2)

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

(nolan600于2012年7月8日加列)

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:

事实证明,在JUL中如何配置您的模式并不真正影响性能,例如,它是否包含源名称。我尝试了一个非常简单的模式:

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

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.

这并没有改变以上的时间安排。我的profiler显示,即使这不是我的模式的一部分,logger仍然花费了大量的时间来调用getSourceClassName()。这种模式并不重要。

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.

因此,我在性能问题上的结论是,至少对于基于测试模板的日志语句来说,在JUL (slow)和SLF4J+Logback (quick)之间的实际性能差异中,似乎大约有10倍。就像Ceki说。

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.

我还可以看到另一件事,即SLF4J的getLogger()调用比JUL的同上要昂贵得多。(95 ms vs 0.3 ms,如果我的轮廓仪是准确的)。这是有意义的。SLF4J必须在底层日志实现的绑定上花一些时间。这不是吓唬我。在应用程序的生命周期中,这些调用应该比较少见。速度应该在实际的日志调用中。

Final conclusion

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

(nolan600于2012年7月8日加列)

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:

谢谢你的回答。与我最初的想法相反,我最终决定为我的API使用SLF4J。这是基于一些事情和你的输入:

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

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

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

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

  3. 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确实比上面详细介绍的要快得多,特别是如果您将它与Logback结合起来。即使这只是一个粗略的测试,我也有理由相信,在SLF4J+Logback的优化中,要比在JUL上花费更多的精力。

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

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

  5. 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!

    模式的灵活性。当我进行测试时,我开始让JUL模拟来自Logback的默认模式。此模式包含线程的名称。事实证明,JUL不能在盒子里做这些。好吧,我现在还没错过,但我不认为这是日志框架中应该缺失的东西。期!

  6. 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.

    现在大多数(或许多)Java项目都使用Maven,所以添加依赖项并不是什么大问题,尤其是在依赖项相当稳定的情况下,也就是说,不会经常更改它的API。对于SLF4J来说,这似乎是正确的。SLF4J jar和朋友的大小也很小。

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.

奇怪的是,我在使用SLF4J之后,实际上对JUL很不满意。我仍然很遗憾,在7月的比赛中,我必须这样做。只是还不够好。属性也可以用一个例子来说明,但是我们不考虑抽象,这样人们就可以插入到他们自己的配置库中。我认为原因在于,属性只出现在酒吧的上方,而对今天的7月来说则恰恰相反。在过去,它以零的速度出现,因为它并不存在。

5 个解决方案

#1


152  

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

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

There are objective reasons for preferring SLF4J. For one, it grants 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.

选择SLF4J有客观原因。首先,它授予终端用户选择底层日志框架的*。此外,更精明的用户倾向于使用j.u来支持log4j以外的功能。l下降。Feature-wise j.u。对一些用户来说,l可能已经足够了,但对其他很多用户来说,它还不够。简而言之,如果日志记录对您很重要,您可能希望使用SLF4J并将logback作为底层实现。如果日志记录是不重要的,j.u。我很好。

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:

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

  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. 那些喜欢j.u。我这么做是为了方便,因为j.u。l与JDK绑定。据我所知,没有其他客观的理由支持j.u.l。
  3. your own preference for j.u.l is just that, a preference.
  4. 你对j.u的偏好。l就是那个,一个偏好。

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

因此,将“硬事实”凌驾于公众舆论之上,虽然看似勇敢,但在这种情况下,这是一种逻辑谬误。

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

如果仍未被说服,JB Nizet提出了另一个有力的论点:

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.

除了最终用户可以为他自己的代码或使用log4j或logback的其他库进行这种定制。j.u。l是可扩展的,但是必须扩展logback, j.u。l、log4j和God只知道还有哪些日志框架,因为他使用了4个使用4个不同日志框架的库,这很麻烦。通过使用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.

无论出于什么原因,如果您讨厌SLF4J API并使用它将扼杀您工作中的乐趣,那么请务必使用j.u.l。SLF4J l。

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

顺便说一下,j.u。l参数化至少比SLF4J慢10倍,这最终会产生显著的差异。

#2


25  

  1. java.util.logging was introduced in Java 1.4. There were uses for logging before that, that's why many other logging APIs exist. Those APIs where used heavily before Java 1.4 and thus had a great marketshare that didn't just drop to 0 when 1.4 was release.

    java.util。在Java 1.4中引入了日志记录。在此之前有日志记录的用途,这就是为什么有许多其他日志api存在的原因。这些api在Java 1.4之前大量使用,因此在1.4发布时市场份额并没有降到0。

  2. JUL didn't start out all that great, many of the things you mentioned where a lot worse in 1.4 and only got better in 1.5 (and I guess in 6 as well, but I'm not too sure).

    JUL开始的时候并不是很好,你提到的很多东西在1.4中更差,只有1.5中更好(我猜在6中也是如此,但我不太确定)。

  3. JUL isn't well suited for multiple applications with different configurations in the same JVM (think multiple web applications that should not interact). Tomcat needs to jump through some hoops to get that working (effectively re-implementing JUL if I understood that correctly).

    JUL不适用于同一JVM中具有不同配置的多个应用程序(请考虑不应该交互的多个web应用程序)。Tomcat需要跳过一些限制以使其工作(如果我理解正确的话,可以有效地重新实现JUL)。

  4. You can't always influence what logging framework your libraries use. Therefore using SLF4J (which is actually just a very thin API layer above other libraries) helps keeping a somewhat consistent picture of the entire logging world (so you can decide the underlying logging framework while still having library logging in the same system).

    您不能总是影响库使用的日志框架。因此,使用SLF4J(实际上它只是其他库之上的一个非常瘦的API层)有助于保持整个日志记录世界的某种一致性(因此,您可以在同一系统中拥有库日志记录的同时确定底层日志记录框架)。

  5. Libraries can't easily change. If a previous version of a library used to use logging-library-X it can't easily switch to logging-library-Y (for example JUL), even if the latter is clearly superious: any user of that library would need to learn the new logging framework and (at least) reconfigure their logging. That's a big no-no, especially when it brings no apparent gain to most people.

    图书馆不能轻易改变。如果以前使用loggon -library- x的库的一个版本不能很容易地切换到loggon -library- y(例如JUL),即使后者显然很好:该库的任何用户都需要学习新的日志框架并(至少)重新配置他们的日志。这是一个大禁忌,尤其是当它没有给大多数人带来明显的利益时。

Having said all that I think JUL is at least a valid alternative to other logging frameworks these days.

说了这么多,我认为JUL至少是其他日志框架的有效替代。

#3


22  

IMHO, the main advantage in using a logging facade like slf4j is that you let the end-user of the library choose which concrete logging implementation he wants, rather than imposing your choice to the end user.

IMHO是使用slf4j这样的日志facade的主要优势,它允许库的最终用户选择他想要的具体日志实现,而不是将您的选择强加给最终用户。

Maybe he has invested time and money in Log4j or LogBack (special formatters, appenders, etc.) and prefers continuing using Log4j or LogBack, rather than configuring jul. No problem: slf4j allows that. Is it a wise choice to use Log4j over jul? Maybe, maybe not. But you don't care. Let the end user choose what he prefers.

也许他在Log4j或LogBack(特殊格式器、附加器等)上投入了时间和金钱,并且更喜欢继续使用Log4j或LogBack,而不是配置jul. No problem: slf4j允许这样做。使用Log4j而不是jul是明智的选择吗?也许是,也许不是。但是你不在乎。让最终用户选择他喜欢的。

#4


4  

I started, like you I suspect, using JUL because it was the easiest one to get going immediately. Over the years, however, I have come to wish I had spent a little more time choosing.

我和你一样,开始使用JUL,因为它是最容易的。然而,这些年来,我开始希望我花了更多的时间来选择。

My main issue now is that we have a substantial amount of 'library' code that is used in many applications and they all use JUL. Whenever I use these tools in a web-service type app the logging just disappears or goes somewhere unpredictable or strange.

我现在的主要问题是,我们有大量的“库”代码,在许多应用程序中都使用它们,而且它们都使用juln .每当我在web服务类型的应用程序中使用这些工具时,日志就会消失,或者出现不可预知或奇怪的情况。

Our solution was to add a facade to the library code that meant that the library log calls did not change but were dynamically redirected to whatever logging mechanism is available. When included in a POJO tool they are directed to JUL but when deployed as a web-app they are redirected to LogBack.

我们的解决方案是向库代码添加facade,这意味着库日志调用不会改变,而是动态地重定向到任何可用的日志记录机制。当包含在POJO工具中时,它们被指向JUL,但是当作为web应用部署时,它们被重定向到LogBack。

Our regret - of course - is that the library code does not use parameterised logging but this can now be retrofitted as and when needed.

我们的遗憾(当然)是,库代码没有使用参数化日志记录,但现在可以根据需要进行修改。

We used slf4j to build the facade.

我们使用slf4j构建facade。

#5


1  

I ran jul against slf4j-1.7.21 over logback-1.1.7, output to an SSD, Java 1.8, Win64

我在slf4j-1.7.21上运行了jul,通过logback-1.1.7,输出到SSD, Java 1.8, Win64

jul ran 48449 ms, logback 27185 ms for an 1M loop.

jul运行48449 ms,登录27185 ms进行1米循环。

Still, a little more speed and a bit nicer API is not worth 3 libraries and 800K for me.

不过,稍微快一点和稍微好一点的API对我来说不值得3个库和800K。

package log;

import java.util.logging.Level;
import java.util.logging.Logger;

public class LogJUL
{
    final static Logger logger = Logger.getLogger(LogJUL.class.getSimpleName());

    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            Object[] o = { lc };

            logger.log(Level.INFO,"Epoch time {0}", o);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }
}

and

package log;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogSLF
{
    static Logger logger = LoggerFactory.getLogger(LogSLF.class);


    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            logger.info("Epoch time {}", lc);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }

}

#1


152  

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

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

There are objective reasons for preferring SLF4J. For one, it grants 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.

选择SLF4J有客观原因。首先,它授予终端用户选择底层日志框架的*。此外,更精明的用户倾向于使用j.u来支持log4j以外的功能。l下降。Feature-wise j.u。对一些用户来说,l可能已经足够了,但对其他很多用户来说,它还不够。简而言之,如果日志记录对您很重要,您可能希望使用SLF4J并将logback作为底层实现。如果日志记录是不重要的,j.u。我很好。

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:

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

  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. 那些喜欢j.u。我这么做是为了方便,因为j.u。l与JDK绑定。据我所知,没有其他客观的理由支持j.u.l。
  3. your own preference for j.u.l is just that, a preference.
  4. 你对j.u的偏好。l就是那个,一个偏好。

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

因此,将“硬事实”凌驾于公众舆论之上,虽然看似勇敢,但在这种情况下,这是一种逻辑谬误。

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

如果仍未被说服,JB Nizet提出了另一个有力的论点:

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.

除了最终用户可以为他自己的代码或使用log4j或logback的其他库进行这种定制。j.u。l是可扩展的,但是必须扩展logback, j.u。l、log4j和God只知道还有哪些日志框架,因为他使用了4个使用4个不同日志框架的库,这很麻烦。通过使用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.

无论出于什么原因,如果您讨厌SLF4J API并使用它将扼杀您工作中的乐趣,那么请务必使用j.u.l。SLF4J l。

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

顺便说一下,j.u。l参数化至少比SLF4J慢10倍,这最终会产生显著的差异。

#2


25  

  1. java.util.logging was introduced in Java 1.4. There were uses for logging before that, that's why many other logging APIs exist. Those APIs where used heavily before Java 1.4 and thus had a great marketshare that didn't just drop to 0 when 1.4 was release.

    java.util。在Java 1.4中引入了日志记录。在此之前有日志记录的用途,这就是为什么有许多其他日志api存在的原因。这些api在Java 1.4之前大量使用,因此在1.4发布时市场份额并没有降到0。

  2. JUL didn't start out all that great, many of the things you mentioned where a lot worse in 1.4 and only got better in 1.5 (and I guess in 6 as well, but I'm not too sure).

    JUL开始的时候并不是很好,你提到的很多东西在1.4中更差,只有1.5中更好(我猜在6中也是如此,但我不太确定)。

  3. JUL isn't well suited for multiple applications with different configurations in the same JVM (think multiple web applications that should not interact). Tomcat needs to jump through some hoops to get that working (effectively re-implementing JUL if I understood that correctly).

    JUL不适用于同一JVM中具有不同配置的多个应用程序(请考虑不应该交互的多个web应用程序)。Tomcat需要跳过一些限制以使其工作(如果我理解正确的话,可以有效地重新实现JUL)。

  4. You can't always influence what logging framework your libraries use. Therefore using SLF4J (which is actually just a very thin API layer above other libraries) helps keeping a somewhat consistent picture of the entire logging world (so you can decide the underlying logging framework while still having library logging in the same system).

    您不能总是影响库使用的日志框架。因此,使用SLF4J(实际上它只是其他库之上的一个非常瘦的API层)有助于保持整个日志记录世界的某种一致性(因此,您可以在同一系统中拥有库日志记录的同时确定底层日志记录框架)。

  5. Libraries can't easily change. If a previous version of a library used to use logging-library-X it can't easily switch to logging-library-Y (for example JUL), even if the latter is clearly superious: any user of that library would need to learn the new logging framework and (at least) reconfigure their logging. That's a big no-no, especially when it brings no apparent gain to most people.

    图书馆不能轻易改变。如果以前使用loggon -library- x的库的一个版本不能很容易地切换到loggon -library- y(例如JUL),即使后者显然很好:该库的任何用户都需要学习新的日志框架并(至少)重新配置他们的日志。这是一个大禁忌,尤其是当它没有给大多数人带来明显的利益时。

Having said all that I think JUL is at least a valid alternative to other logging frameworks these days.

说了这么多,我认为JUL至少是其他日志框架的有效替代。

#3


22  

IMHO, the main advantage in using a logging facade like slf4j is that you let the end-user of the library choose which concrete logging implementation he wants, rather than imposing your choice to the end user.

IMHO是使用slf4j这样的日志facade的主要优势,它允许库的最终用户选择他想要的具体日志实现,而不是将您的选择强加给最终用户。

Maybe he has invested time and money in Log4j or LogBack (special formatters, appenders, etc.) and prefers continuing using Log4j or LogBack, rather than configuring jul. No problem: slf4j allows that. Is it a wise choice to use Log4j over jul? Maybe, maybe not. But you don't care. Let the end user choose what he prefers.

也许他在Log4j或LogBack(特殊格式器、附加器等)上投入了时间和金钱,并且更喜欢继续使用Log4j或LogBack,而不是配置jul. No problem: slf4j允许这样做。使用Log4j而不是jul是明智的选择吗?也许是,也许不是。但是你不在乎。让最终用户选择他喜欢的。

#4


4  

I started, like you I suspect, using JUL because it was the easiest one to get going immediately. Over the years, however, I have come to wish I had spent a little more time choosing.

我和你一样,开始使用JUL,因为它是最容易的。然而,这些年来,我开始希望我花了更多的时间来选择。

My main issue now is that we have a substantial amount of 'library' code that is used in many applications and they all use JUL. Whenever I use these tools in a web-service type app the logging just disappears or goes somewhere unpredictable or strange.

我现在的主要问题是,我们有大量的“库”代码,在许多应用程序中都使用它们,而且它们都使用juln .每当我在web服务类型的应用程序中使用这些工具时,日志就会消失,或者出现不可预知或奇怪的情况。

Our solution was to add a facade to the library code that meant that the library log calls did not change but were dynamically redirected to whatever logging mechanism is available. When included in a POJO tool they are directed to JUL but when deployed as a web-app they are redirected to LogBack.

我们的解决方案是向库代码添加facade,这意味着库日志调用不会改变,而是动态地重定向到任何可用的日志记录机制。当包含在POJO工具中时,它们被指向JUL,但是当作为web应用部署时,它们被重定向到LogBack。

Our regret - of course - is that the library code does not use parameterised logging but this can now be retrofitted as and when needed.

我们的遗憾(当然)是,库代码没有使用参数化日志记录,但现在可以根据需要进行修改。

We used slf4j to build the facade.

我们使用slf4j构建facade。

#5


1  

I ran jul against slf4j-1.7.21 over logback-1.1.7, output to an SSD, Java 1.8, Win64

我在slf4j-1.7.21上运行了jul,通过logback-1.1.7,输出到SSD, Java 1.8, Win64

jul ran 48449 ms, logback 27185 ms for an 1M loop.

jul运行48449 ms,登录27185 ms进行1米循环。

Still, a little more speed and a bit nicer API is not worth 3 libraries and 800K for me.

不过,稍微快一点和稍微好一点的API对我来说不值得3个库和800K。

package log;

import java.util.logging.Level;
import java.util.logging.Logger;

public class LogJUL
{
    final static Logger logger = Logger.getLogger(LogJUL.class.getSimpleName());

    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            Object[] o = { lc };

            logger.log(Level.INFO,"Epoch time {0}", o);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }
}

and

package log;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogSLF
{
    static Logger logger = LoggerFactory.getLogger(LogSLF.class);


    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            logger.info("Epoch time {}", lc);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }

}