为什么不使用的java.util.logging?为什么不使用的java.util.logging?

2019-06-14 16:14发布

这是我平生第一次,我发现自己在我写了一个Java API,这将是开源的位置。 但愿被列入许多其他项目。

对于我的日志记录(事实上我一起工作的人)一直使用JUL(java.util.logging中),从未发生过任何问题了。 但是现在我需要更详细地了解我应该为我的API开发做什么。 我已经做了这一点,与我有我只是得到更糊涂一些信息研究。 因此,这个职位。

由于我来自JUL我上有失偏颇。 我其余的知识是没有那么大。

从研究,我已经做了我想出来的这些原因,为什么人们不喜欢JUL:

  1. “我刚开始用Java开发很久之前Sun发布JUL,它只是更容易为我继续日志框架-X,而不是学习新的东西”。 嗯。 我不是在开玩笑,其实这是人说的话。 有了这个说法我们都可以做COBOL。 (不过,我可以肯定涉及到这是一个懒惰的家伙我自己)

  2. “我不喜欢的日志记录级别的JUL的名称”。 好了,说真的,这只是没有足够的理由来引进新的依赖。

  3. “我不喜欢从JUL输出的标准格式”。 嗯。 这仅仅是配置。 你甚至不用做任何代码明智。 (真,回到过去,你可能不得不创建自己的格式化类得到它的权利)。

  4. “我使用也使用日志框架-X,所以我想它更容易只是使用一个其他库”。 这是一个循环论证,是不是? 为什么“大家”使用日志记录框架-X,而不是七月?

  5. “其他人都使用日志框架-X”。 这对我来说是上述的只是一个特例。 多数并不总是正确的。

所以,真正的大问题是,为什么不七月? 。 这是什么我错过了什么? 日志记录门面(SLF4J,JCL)存在的理由是,多个日志实现历来存在,我看到它其中的原因确实可以追溯到纪元前JUL。 如果JUL是完美的,然后登录外立面也就不存在了,还是什么? 为了使问题更混乱JUL是在一定程度上门面本身,允许处理程序,格式化程序,甚至LogManager中被交换。

而不是拥抱做同样的事情(记录)的多种方式,我们不应该质疑为什么他们首先是有必要吗? (看看这些理由仍然存在)

好了,我的研究,到目前为止已导致一对夫妇的事情,我可以看到可能是真正的问题与JUL:

  1. 性能 。 有人说这SLF4J性能优于其他地区。 在我看来这是过早优化的情况。 如果您需要登录数百个兆字节每秒的话,我不知道你是在正确的道路上呢。 JUL也发生了变化,你在Java 1.4中做了测试,可能不再是真实的。 你可以阅读有关它在这里 ,这修补程序已使它成为Java 7中许多人还谈字符串连接在测井方法的开销。 但是基于模板的记录避免这一成本,且还存在于七月 个人而言,我从来没有真正写的基于模板的日志记录。 懒得为。 例如,如果我这样做与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的表现并不好。

  2. 从类路径配置 。 外的现成JUL不能从类路径加载的配置文件。 这是一个几行代码 ,使其做到这一点。 我明白为什么这可能是小麻烦,但解决的办法是短而简单。

  3. 可用性输出处理程序 。 JUL自带5的输出处理程序外的开箱:控制台,文件流,插座和内存。 这些可以扩展或新的可写。 例如,这可以被写入到UNIX / Linux的系统日志和Windows事件日志。 我个人从来没有这样的要求,也没看到它用,但我可以肯定涉及到为什么它可能是一个非常有用的功能。 的logback自带的系统日志一个appender例如。 不过我认为,

    1. 需求的输出目标99.5%是由什么是JUL外的开箱覆盖。
    2. 特别需要可以通过自定义处理程序上JUL的顶部,而不是对别的东西顶部照顾。 没有什么,我认为表明,它需要更多的时间来写系统日志输出处理程序JUL比它的另一日志框架。

我真的很担心,有件事情我已经忽视。 使用记录外墙,比其他JUL日志实现的是如此普遍,我一定要来,这是我谁只是不明白的结论。 这不会是第一次,我很害怕。 :-)

所以,我该怎么办我的API? 我希望它成为成功的。 我当然可以只是“随大流”,实行SLF4J(这似乎是最流行的这些天),但为了我自己,我仍然需要准确地了解今天有什么不对的JUL权证全部模糊? 我会选择JUL我的图书馆破坏自己?

性能测试

(07-JUL-2012加入部分通过nolan600)

有一个关于SLF4J的参数化是10倍以上JUL的快从Ceki参考下面。 所以,我开始做一些简单的测试。 乍一看,这要求当然是正确的。 这里有初步结果(但阅读!):

  • 执行时间SLF4J,后端的logback:1515
  • 执行时间SLF4J,后端JUL:12938
  • 执行时间JUL:16911

上面的数字是毫秒所以少用为好。 因此,10倍的性能差异是第一其实相当接近。 我最初的反应:这是一个很大!

下面是测试的核心。 如可以看到的一个整数和一个串construted在一个循环,然后将其在日志语句中使用:

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

(我想日志语句既具有原始数据类型(在这种情况下,一个int)和更复杂的数据类型(在这种情况下,一个字符串)。不知道它的问题,但你有它。)

为SLF4J日志语句:

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

对于JUL日志语句:

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

该JVM是“回暖”与做实际测量前执行一次同样的测试。 Java的03年1月7日被用来在Windows中使用7最新SLF4J(v1.6.6)的logback和(1.0.6)的版本。 输出和错误重定向到空设备。

不过,现在仔细,原来JUL花费其大部分时间在getSourceClassName()的输出,因为JUL默认打印源类的名称,而的logback没有。 所以,我们是在比较苹果和橘子。 我必须再次进行测试,并以类似的方式,让他们实际输出同样的东西配置日志实现。 然而,我怀疑是SLF4J +的logback仍然拔得头筹,但远从最初的数作为上面给出。 敬请关注。

BTW:这次试验是第一次,我实际上SLF4J或工作的logback。 一个愉快的经历。 JUL肯定是少了很多热情,当你开始了。

性能测试(部分2)

(08-JUL-2012加入部分通过nolan600)

事实证明这并不重要性能如何配置你的模式在七月,即它是否包括源名称或没有。 我试图用一个非常简单的模式:

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

,但这并没有改变上述时序。 我的探查,发现该记录器还花了很多时间在调用getSourceClassName()即使这不是我的模式的一部分。 该模式并不重要。

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

我还可以看到另外一件事即SLF4J的getLogger()调用是一个很大的价格比JUL的同上。 (95 ms和0.3毫秒,如果我的探查是准确的)。 这是有道理的。 SLF4J必须做对结合底层日志实现的一段时间。 这不吓唬我。 这些调用应该是在应用程序的生命周期比较少见。 色牢度的应该是实际的日志调用。

定论

(08-JUL-2012加入部分通过nolan600)

感谢您对所有的答案。 相反的是我最初以为我已经结束了在决定使用SLF4J我的API。 这是基于一些事情和你输入:

  1. 它提供了灵活的选择在部署时登录的实现。

  2. 与缺乏JUL的配置灵活性问题的应用程序服务器中运行时。

  3. SLF4J肯定是快了很多,如特定上面详述,如果你对夫妇它的logback。 即便这只是一个粗略的测试我有理由相信,更多的努力已经进入优化上SLF4J +的logback超过年7月

  4. 文档。 为SLF4J文档仅仅是大量更全面,更精确。

  5. 模式的灵活性。 当我做了测试,我开始有JUL从模仿的logback默认模式。 这种模式包括线程的名称。 原来JUL无法做到这一点的开箱。 好吧,我没有错过它到现在为止,但我不认为这是一个应该从日志框架中缺少的东西。 期!

  6. 大多数(或多个)Java项目现在使用Maven因此增加的依赖没有那么大的事,特别是如果这种依赖性是相当稳定的,即不会不断地改变其API。 这似乎是SLF4J如此。 另外,SLF4J罐子和朋友都在小尺寸。

这样发生的奇怪的事情是,我工作过一点与SLF4J后竟变得十分心烦七月 我仍然感到遗憾的是它必须是这样与七月 JUL远非完美,但那种做这项工作。 只要不是很不够好。 也可以这样说,大约Properties作为一个例子,但我们没有想到的是抽象,使人们可以在他们自己的配置库插件和你有什么。 我想原因是Properties来在正上方的酒吧,而相对来说今天的JUL是真的......而在过去,它在零进来,因为它不存在。

Answer 1:

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

虽然对于SLF4J客观原因。 为一体,SLF4J允许最终用户自由选择的底层日志框架 。 此外,精明的用户往往喜欢的logback它提供超越log4j的能力 ,与七月下降远远落后。 功能方面七月可能是足够的一些用户,但对许多其他人只是并非如此。 概括地说,如果日志记录是对你很重要,你可能需要使用SLF4J的logback与作为底层的实现。 如果日志记录是不重要的,七月是罚款。

然而,作为OSS开发人员,你需要考虑到用户的偏好,而不是只是你自己。 由此可见,你应该采取SLF4J不是因为是相信SLF4J比七月更好,但因为目前大多数Java开发人员(2012年7月)更喜欢SLF4J作为他们的日志API。 如果最终决定不关心民意,考虑以下事实:

  1. 那些喜欢谁七月这样做出来的方便,因为七月与JDK捆绑在一起。 据我所知,有利于七月没有其他客观参数
  2. 您自己的喜好了七月,只是, 一个偏好

因此,持上述民意“铁的事实”,而看似勇敢,在这种情况下,逻辑上的谬误。

如果仍然不服气, JB Nizet进行附加和有效的论点:

除了最终用户可能已经这样做了定制了自己的代码,或使用log4j的logback或另一个库。 七月是可扩展的,但有延长的logback 7月,Log4j和,因为他使用了使用四个不同的日志框架是繁琐的四个库只有上帝知道哪些其他的日志框架。 通过使用SLF4J,你让他来配置他想要的,不是你选择了一个日志框架。 请记住,一个典型的项目利用图书馆的千变万化,而不仅仅是你的

无论什么原因让你讨厌的SLF4J API和使用它会扼杀的乐趣了你的工作,然后通过各种手段去七月毕竟,有手段七月重定向到SLF4J 。

顺便说一句,七月参数化比SLF4J的其最终使一个明显的区别慢的至少10倍。



Answer 2:

  1. java.util.logging是在Java 1.4中引入的。 有对之前记录的用途,这就是为什么许多其他日志记录API存在。 其中大量使用的Java 1.4之前,因此这些API产生了很大的市场份额是不只是下降到0的时候是1.4版本。

  2. JUL没有开始时所有的伟大,很多人都提到了1.4哪里差了不少,仅在1.5病情好转(我猜在6为好,但我也不太清楚)的事情。

  3. JUL是不太适合在同一个JVM不同的配置(认为不应该交互的多个Web应用程序)的多个应用程序。 Tomcat的需要通过一些跳铁圈,以获取工作(实际上是重新实现JUL如果我了解,正确的)。

  4. 你不能总是影响你的库使用的日志框架。 因此,使用SLF4J(这实际上是略高于其他库非常薄API层)有助于保持整个记录世界的有些一致的画面(这样你就可以决定的基本日志框架同时还具有在同一个系统库记录)。

  5. 图书馆不能轻易改变。 如果库的早期版本用于使用日志记录库-X不能方便地切换到记录库-Y(例如7月),即使后者显然superious:该库的任何用户都需要学习新的日志框架和(至少)重新配置自己的日志记录。 这是一个很大的禁忌,特别是当它带来了没有明显的增益最多的人。

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



Answer 3:

恕我直言,在使用日志的外观像SLF4J的主要优点是,你让库的最终用户选择他想要哪个具体的日志记录实现,而不是强加你的选择给最终用户。

也许他已经投入了时间和金钱的Log4j的logback或(特殊格式化,追加程序等)和使用的Log4j或的logback,而不是配置七月宁愿继续。 没问题:SLF4J允许。 它是一个明智的选择使用Log4j在七月? 也许是,也许不是。 但你不在乎。 让终端用户选择他喜欢的东西。



Answer 4:

我开始,像你我怀疑,使用JUL因为它是一个最容易得到立即去。 多年来,但是,我是来希望我花了一点时间选择。

我的主要问题是现在我们有一个在许多应用中使用的“图书馆”代码大量和他们都使用七月 每当我在web服务型应用程序中使用这些工具的记录就这样消失或去某个地方不可预知的或奇怪。

我们的解决方案是一个门面添加到库中的代码,意味着库日志调用并没有改变,但被动态地重定向到任何记录机制可用。 当被包含在POJO的工具,他们是针对JUL,但是当部署为web应用程序,他们将被重定向到的logback。

当然 - - 我们遗憾的是,该库的代码不使用参数化的日志记录,但这个现在可以改装为需要的时候。

我们使用SLF4J建门面。



Answer 5:

我跑七月对SLF4J-1.7.21过的logback-1.1.7,输出到SSD,爪哇1.8,Win64的

七月跑了48449毫秒,27185的logback毫秒的1M循环。

尽管如此,多一点的速度和更好一点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);
    }
}

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);
    }

}


文章来源: Why not use java.util.logging?