有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java日志记录的复杂性和对MessageFormat性能的关注

我的应用程序使用log4j进行日志记录,通常我通过检查是否启用了特定级别来进行日志记录,然后按照以下方式进行日志记录

if(Logger.isApplicationDebugEnabled()){
   Logger.logApplicationDebug("something"+values);  
 }

现在,这个if检查减少了jUnit测试期间的分支覆盖率。为了克服这个问题,我的朋友建议取消日志的“如果”检查

  1. 首先,我的一个朋友建议删除if检查并直接登录。这种方法的问题是,它可能会由于字符串的形成而减慢应用程序的速度,而这些字符串无论如何都不会出现在日志文件中
  2. 我想到的第二种方法与SLF4j非常相似

    记录器。调试(“编号{0},日期{1,日期}”,1234,新日期())

这感觉非常有吸引力和简单。(此解决方案在内部使用MessageFormat.format(str,object[])方法。但我担心这可能会有什么表现。还要注意,“Logger”是我的内部实用程序类,在它的每个日志方法中,都有一个日志启用检查。 你们有什么建议?我浏览了velocity模板,但它需要参数图。是否有任何轻量级解决方案仅根据参数索引位置替换值,或者该解决方案可以吗


共 (4) 个答案

  1. # 1 楼答案

    好的,我将问一个显而易见的问题:为什么不在运行单元测试时启用调试日志记录——或者实际上启用所有级别的日志记录?这样做的好处是增加了代码覆盖率测试和日志问题测试(这远远不是不可能的)

    检查是否启用日志记录是有原因的:不仅构造最终日志字符串可能很昂贵(在大循环中),而且构造单个参数本身也可能很昂贵。使用MessageFormat或java。util。格式化程序或任何东西都无法解决第二个问题。我真的鼓励你保持沉默

  2. # 2 楼答案

    我可以强烈推荐用于log4j的slf4j facade,它允许您使用这种语法

    日志。信息(“你好,{}来自,{}”,“世界”,“我”)

    只有在确定事件实际上应该被记录之后,字符串才会展开,这样您就不必指定ifEnabled包装器。然后使用log4j作为slf4j的后端

    此外,与MessageFormatter相比,它的速度要快得多

  3. # 3 楼答案

    知道的唯一方法是测量。对性能的猜测几乎总是错误的:)

    就我个人而言,我可能会坚持使用您最初的log4j代码——不要对覆盖率太过担心。防止对始终遵循的代码路径进行太多的日志调用是合理的,但我不会为错误条件之类的事情而烦恼,因为在这种情况下,您已经处于一种奇怪的、希望是罕见的情况。在这里面,编写最可读的代码,然后确保你的应用程序按你需要的方式运行如果没有,则对其进行分析以找出问题所在如果它在日志代码中,则对其进行优化

  4. # 4 楼答案

    事实上,我已经在一个项目上完成了你的建议,我对这种方法有着积极的经验。我在commons日志上创建了一个附加层,允许在引擎盖下使用MessageFormat进行消息格式化

    这些是我在测量了与您描述的几乎相同的使用模式后得到的结果,10000次调用类似:

    ^{pr1}$

    1. 登录时:commons logging=664ms,Slf4j=559ms,MyLog=3134ms
    2. 注销时:commons logging=6ms,Slf4j=7ms,MyLog=7ms
    很明显,“MyLoG”在调试输出时慢得多,但在调试时关闭时达到了与之一致的程度。为了清楚起见,在“MyLog”中,我在实际格式化消息之前显式地检查了isDebugEnabled()

    然而,产生的日志代码现在更加清晰,我们的整个团队最终生成了更有用、更详细的消息。在此之前,使用单独的方法来构造更长的记录器消息并不少见

    考虑到关闭日志记录时几乎没有额外的性能影响,我可以预见自己将来会使用这种技术