V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
BraveXaiver
V2EX  ›  Java

Java 中, logback 和 log4j2 日志工具,不使用 log.isDebugEnabled 判断就直接调用 debug 进行日志,在日志级别没有到 debug 的情况下,到底带来什么损失呢?

  •  
  •   BraveXaiver · 188 天前 · 1765 次点击
    这是一个创建于 188 天前的主题,其中的信息可能已经有所发展或是发生改变。
    不加这个东西,我写着爽不说,代码整体看起来也更加美观。不知道大家是不是持相同看法。

    所以我是真的很想不写,但又不知道这个到底为什么是约定俗成的最佳范式。

    感谢任何分享和解答!
    第 1 条附言  ·  187 天前
    谢谢,主要就是字符串格式化时,担心 toString 大 POJO 时带来的性能开销。但是即便以 jdk8 这样的老 JVM ,不要说 toString ,就算是调用 jackson 处理 1MB 不到的请求体,也是几乎不用担心性能开销的吧(若无高并发)。

    换言之,如果确定程序中能遇到的 POJO json 化后最多也就 10-20 kb, debugEnabled 不查也没问题。
    16 条回复    2023-10-23 16:03:58 +08:00
    NotFoundEgg
        1
    NotFoundEgg  
       187 天前   ❤️ 1
    即使不打印日志,但如果涉及到字符串拼接或 toString 也会损耗性能,所有要不就判断,要不就占位符,不要使用“+”的方式拼接

    不过实际写的时候我个人也很少在意这个
    clickhouse
        2
    clickhouse  
       187 天前   ❤️ 1
    很简单,比如你 debug 打印一个对象的具体内容,不管你事 toString 也好,还是转 JSON 打印也好,这个方法都会被执行。而你不是 debug 级别,那么这个方法就白白消耗了系统的资源。
    wdlth
        3
    wdlth  
       187 天前   ❤️ 1
    因为用占位符的话,后续的参数还是需要经过执行的,不过大多时候参数是已经确定的值/引用,性能开销没这么大。
    如果日志占位参数是较复杂的方法,加上 isDebugEnabled 跳过更好。
    stinkytofu
        4
    stinkytofu  
       187 天前
    @clickhouse #2 所以说 C/C++中的预编译的机制真的挺好的
    vitoliu
        5
    vitoliu  
       187 天前
    目光向前看,debug 和 trace 日志都没有意义了。
    因为已经有了 arthas 。
    就像 Spring 之前 xml 、tomcat web.xml 配置也有一堆范式一样,现在谁还用啊?
    BraveXaiver
        6
    BraveXaiver  
    OP
       187 天前
    @NotFoundEgg
    @clickhouse
    @wdlth

    谢谢,主要就是字符串格式化时,担心 toString 大 POJO 时带来的性能开销。但是即便以 jdk8 这样的老 JVM ,不要说 toString ,就算是调用 jackson 处理 1MB 不到的请求体,也是几乎不用担心性能开销的吧(若无高并发)。

    换言之,如果确定程序中能遇到的 POJO json 化后最多也就 10-20 kb, debugEnabled 不查也没问题。
    BBCCBB
        7
    BBCCBB  
       187 天前
    方法调用要资源+时间.. 如果你 log.debug 的参数里有需要计算得到的结果, 那也要浪费资源..

    比如
    log.debug("{}", computeXXX());

    这个 computeXXX()需要耗费很多资源..
    BBCCBB
        8
    BBCCBB  
       187 天前   ❤️ 1
    10-20kb json 字符串已经是很大的开销了..

    要养成好习惯. debug log 里有较大消耗, 比如非 xxx.getXX() 简单获取属性的操作, 都加上 log.isDebugEnable
    zsdroid
        9
    zsdroid  
       187 天前
    这简单,自己用 lambda 封装一下就解决这个问题了。
    cloud107202
        10
    cloud107202  
       187 天前
    不加判断会带来额外的 Call by Value Evaluation 开销


    高版本 slf4j 2.X ( spring boot3 的自动依赖) 有个 Fluent Logging API 能优雅解决这个问题(和因为强迫症希望少一组 if-block 引发心里不适的问题)
    oneisall8955
        11
    oneisall8955  
       187 天前 via Android
    用对象包一层,tostring 在将源对象输出
    aqua02
        12
    aqua02  
       187 天前 via Android
    按计算机原理的角度来说,一个主频为 1ghz 执行一个机器指令 时间为 1/1g 秒, 又因为它是函数 那就加几个指令 当 4 条吧,又因为它是 java 封装 ,总指令数 x5 吧,时间就是 ( 4+1 )*5 / 1g 秒,忽略不计吧😂,1g=10^9 。 具体几条可以反编译看看。
    Masoud2023
        13
    Masoud2023  
       187 天前
    不是我非在这抬杠,一大堆第三方库开源组件也没非得在 log.debug 前面判断环境吧。

    都考虑到这种性能损耗了,为什么不换其他的编译语言?

    觉得不爽可以自己给 java 写个 babel ,打包的时候把 log.debug 全删了。

    或者直接换个语言。
    Aresxue
        14
    Aresxue  
       187 天前
    如果参数是已经计算好的变量判断不判断其实都还好,如果占位符的参数还涉及到比较吃 cpu 的计算最好还是判断下能节省点 cpu 。
    oldshensheep
        15
    oldshensheep  
       187 天前   ❤️ 1
    如果你看 log4j2 源码会发现实际上 log4j2 已经自动检查 log level 了,不会做无谓的调用。但是如果你手动拼接字符串 "log some %s some".formated(obj),这个损耗会大一些,因为会调用 obj.toString 。调用这样的 log 方法 (final String message, final Object... params),而不是手动拼接字符串。

    还有一直情况就是做大量计算,这种情况可以使用,lambda ,()-> computeSome() 这种也是一样会检查后再调用
    cnzjl
        16
    cnzjl  
       187 天前
    突然想到写一个编译插件,打包项目的时候判断下 log.debug()有没有被 if(log.isDebugEnable)包裹,没有的话就加上[绿帽 doge]
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2964 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 13:09 · PVG 21:09 · LAX 06:09 · JFK 09:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.