java log is判断引发的一系列事件解析

目录
  • log 自动加上if判断 调研
    • 思考 这个topic干什么的啊?
    • 思考
    • 小结
    • 说回来 lombok 到底有没有自动加if的插件啊
      • 错误案例
      • 错误分析
      • 原因分析
  • log isDebug 判断的必要性
  • 总结
    • 后续

首先来源是 老大code Review的时候 说到日志,让我从 log.debug 加上一个if 判断,log.isDebug ,这一听就想到是 为了防止debug 日志不打印,导致的String拼接等 没必要的损耗

嗯嗯 老大说的确实有道理,改吧

我靠,这一查几百个 log 需要加,这一个一个改也太累了

总 需求列表

  • log 自动加上if判断 如果外面有if判断了,忽略
  • 最后 写了个idea 插件。。。。

log 自动加上if判断 调研

刚上来,我先百度下 是不是有现成的,我现在用的lombok,按道理应该有一个属性 控制 是否加if的,嗯嗯 没错,找找,我一般先看看 @Sl4J 给我提供了什么参数配置

@Retention( RetentionPolicy . SOURCE )
@Target({ElementType.TYPE})
public @interface Slf4j{
    String topic() default
    }

思考 这个topic干什么的啊?

说实话 我之前没有用过这个属性。。。。狗头。。

@Slf4j 注解有个topic 属性可以进行设置要采用的logger,
topic 的值对应的就是logback.xml中定的logger name。root logger是默认就存在的。

到这 你可能要问了,root logger 是默认实现,你说是默认实现就是默认实现了? 证据呢?

对应的启动Config类为 ch.qos.logback.classic.BasicConfigurator

嗯嗯 根上是ROOT

有一个细节,我们在配置logback.xml的时候 都会写这种

<logger name="com" level="DEBUG" >
    <appender-ref ref="STDOUT"/>
</logger>
<logger name="com.example.demo" level="warn" >
    <appender-ref ref="STDOUT"/>
</logger>

你是不是好奇 这种的name怎么解析的?

他是从头开始 遍历包名 从loggerCache 中看看是否有匹配的,一层层找

思考

不说这些理论了,一句话 按照上面配置 logback.xml 在 com.example.demo.controller 下的类执行会打印log.info日志么?

@RestController
@RequestMapping
@Slf4j
public class DemoController {
    @RequestMapping("/test")
    public String test(){
        log.info("sad");
        return "success";
    }
}

嗯嗯 这么一实验 没打印啊

有人可能问了,那把2个logger 顺序反过来? 不用试了,也不行

这一看 com.example.demo的warn生效了啊,debug/info 都没打印出来,那为什么呢?

先看一个图

下面就要看下 这个children 当时怎么赋值的了 其实就是从 最底下 往上找,在这里找到了 com.example.demo 的配置并且应用,是因为 logger类中

int h;
do {
    h = LoggerNameUtil.getSeparatorIndexOf(name, i);
    String childName;
    if (h == -1) {
        childName = name;
    } else {
        childName = name.substring(0, h);
    }
    i = h + 1;
    synchronized(logger) {
        childLogger = logger.getChildByName(childName);
        if (childLogger == null) {
            childLogger = logger.createChildByName(childName);
            this.loggerCache.put(childName, childLogger);
            this.incSize();
        }
    }
    logger = childLogger;
} while(h != -1);

一直找到最后,返回的就是最后/最靠近 目标类的logger 配置

小结

logger 配置不是按照pom.xml的那种优先顺序,而是包名匹配 最多的生效,如果你发现 日志打印和你想的不一样,你可以去看下 LoggerContext 类中 loggerCache 属性的值,检查下

如果是一个业务系统,可能是一种logback.xml模板,如果你是中间件/组件,就需要对logback.xml 进行改动了,因为中间件可能是 binlog监听等等 大数据量的,如果按照业务系统那种搞法 有的日志是没必要,根据你的业务 请自由配置

说回来 lombok 到底有没有自动加if的插件啊

lombok @Sl4j 是没有了,百度下吧

好吧,这也什么都没有,官网看看,哎 也没有,按道理应该有啊,也不难。。。

我突然在想是不是这个优化 也不像我们想的那么有优化效果,肯定还是有必要的

log isDebug 判断的必要性

错误案例

现象描述:发现某些服务器的pv数不高,但服务器的load却不低,高于平均水平

错误分析

分析过程: 通过内存监控发现,GC的动作比较频繁,但无法找到原因,一次PLA偶然的发现了大量如log.debug(“memberId:” + member.getMemberId())代码

原因分析

在代码中发现如下代码段很多: log.debug(“memberId:” + member.getMemberId())

以上代码执行时,分两步:

  • 先执行的是括号中的字符串相”+”的动作,而每次”+”运算都会导致新字符串的生成,这样就产生了很多“中间字符串”,在极大次数被调用时,这种字符串被创建和销毁的数量非常庞大,从而造成了jvm gc频繁执行,进而影响了性能。
  • 再执行log.debug()函数,在生产环境log level一般大于info,所以实际不会打印debug信息综上所述,这些代码在生产环境不会产生日志,但会执行字符串”+”运算,而这些运算是无意义的,所以需要先判断日志的优先级,方式是log.isXXXEnabled() { log.XXX(……); }

Log Level的级别: Fatal->error->warn->info->debug,级别从高到低 一般我们生成环境的log level都是error,所以对于Error以上级别的日志,不用判断;对于error以下级别的都要加上判断。

总结

is 判断还是有必要的,目前没什么别的办法,我在写一个idea 插件,来一个按钮/快捷键 自动添加log if判断,正好玩玩

后续

行吧,既然说了做一个idea 插件,搞起来,周末花了几个小时搞了一版,提交了idea 审核 ,等待审核中 起名叫java-tools 开发会用的功能 我会迭代进去,有什么是你们需要的可以评论下,我会排下优先级 开发

简单效果:

@Slf4j
public class A {
    public void a(){
        log.info("21") ;
    }
}

点击 ctrl + 8 一起按 或者 右键

变为

@Slf4j
public class A {
    public void a(){
        if(log. isInfoEnabled()){
        log. info("21");
        }
    }
}

以上就是java log is判断引发的一系列事件解析的详细内容,更多关于log is判断引发事件的资料请关注我们其它相关文章!

(0)

相关推荐

  • java使用stream判断两个list元素的属性并输出方式

    目录 使用stream判断两个list元素的属性并输出 stream判断列表是否包含某几个元素/重复元素 代码SHOW Java stream判断列表是否包含重复元素 使用stream判断两个list元素的属性并输出 /** * 使用stream判断两个list中元素不同的item */ @Test public void test1(){ List<Param> stringList1 = new LinkedList<Param>(){{ add(new Param(1,&qu

  • java isInterrupted()判断线程的实例讲解

    1.说明 isInterrupted()可以判断当前线程是否被中断,仅仅是对interrupt()标识的一个判断,并不会影响标识发生任何改变(因为调用interrupt()的时候会设置内部的一个叫interrupt flag的标识). 2.实例 public static void main(String[] args) throws InterruptedException{ Thread thread = new Thread(()->{ while (true){} }); thread.

  • java 判断list是否为空过程解析

    问题: 之前用 list!=null 来判断list是否为空,但发现,定义一个list后,即使里面并没有加入任何元素,返回的结果仍旧是 true, 其实,本意是希望在没有任何元素时,返回 false,下面是关于判断逻辑的详细解析: 1.如果想判断list是否为空,可以这么判断: if(list == null || list.size() ==0 ){ //为空的情况 }else{ //不为空的情况 } 2.list.isEmpty() 和 list.size()==0 的区别 答案:没有区别

  • java判断list不为空的实现,和限制条数不要在一起写

    场景 很多情况下,查单条记录也用通用查询接口,但是输入的条件却能确定唯一性.如果我们要确定list中只有一条记录,如下写法: // 记录不为空 && 只有一条 才继续 if(!CollectionUtils.isEmpty(list) && 1!=list.size()){ return "记录条数不是1"; } Object object = list.get(0); 上面代码对么,貌似正确啊.后来报错了,被打脸了. 其实相当于 >0 &

  • Java判断2个List集合是否相等(不考虑元素的顺序)

    现在有两个对象,他们的一个属性是list,很明显两个对象的list里面的对象,都是相等的,只是这2个list里面的顺序不一致,导致这2个对象被判断为不相等啦,这就是问题,现在要解决这个问题. 问题图如下: 可以看到这2个对象的呢个list属性里面数据,咱看起来是一样的,但是经过equals之后,返回的是false. 所以,需要自己重写equals方法和hashcode方法,这2个方法一般是一起重写的. 然后,问题的关键就在于,怎么判断2个list集合是否相等.不考虑顺序. 看代码: 先是这2个对

  • Java应该在哪里判断List是否为空

    目录 前言 一个问题 解决方案 更好的方案 总结 前言 在新的一年,我又重新回到了Java技术栈(我肯定是疯了!).有句诗说得好,不识庐山真面目,只缘身在此山中.我仍然喜欢函数式编程,但我现在需要离它远一点,这样才能更好地理解它. 在这篇博客中,我会分享一个在项目中遇到的问题,看看能不能有更好的解决方案. 一个问题 我们有一个函数,返回的是一个Panel List public Optional<List<Panel>> generatePanels() { ... return

  • java log is判断引发的一系列事件解析

    目录 序 log 自动加上if判断 调研 思考 这个topic干什么的啊? 思考 小结 说回来 lombok 到底有没有自动加if的插件啊 错误案例 错误分析 原因分析 log isDebug 判断的必要性 总结 后续 序 首先来源是 老大code Review的时候 说到日志,让我从 log.debug 加上一个if 判断,log.isDebug ,这一听就想到是 为了防止debug 日志不打印,导致的String拼接等 没必要的损耗 嗯嗯 老大说的确实有道理,改吧 我靠,这一查几百个 log

  • 详解记录Java Log的几种方式

    在Java中记录日志的方式有如下几种: 一.System.out.println(最简单) 1.输出到控制台:System.out.println("XXX"); 2.输出到指定文件: import java.io.PrintStream; PrintStream ps = new PrintStream("D:\\test.txt"); System.setOut(ps); System.out.println("XXX"); 二.java.u

  • Java中高效判断数组中是否包含某个元素的几种方法

    目录 检查数组是否包含某个值的方法 使用List 使用Set 使用循环判断 使用Arrays.binarySearch() 时间复杂度 使用一个长度为1k的数组 使用一个长度为10k的数组 总结 补充 使用ArrayUtils 完整测试代码 长字符串数据 如何检查一个数组(无序)是否包含一个特定的值?这是一个在Java中经常用到的并且非常有用的操作.同时,这个问题在Stack Overflow中也是一个非常热门的问题.在投票比较高的几个答案中给出了几种不同的方法,但是他们的时间复杂度也是各不相同

  • Java中如何判断线程池任务已执行完成

    目录 不判断的问题 方法1:isTerminated 缺点分析 扩展:线程池的所有状态 方法2:getCompletedTaskCount 方法说明 优缺点分析 方法3:CountDownLatch 优缺点分析 方法4:CyclicBarrier 方法说明 优缺点分析 总结 前言: 很多场景下,我们需要等待线程池的所有任务都执行完,然后再进行下一步操作.对于线程 Thread 来说,很好实现,加一个 join 方法就解决了,然而对于线程池的判断就比较麻烦了. 我们本文提供 4 种判断线程池任务是

  • java使用正则表达式判断邮箱格式是否正确的方法

    本文实例讲述了java使用正则表达式判断邮箱格式是否正确的方法.分享给大家供大家参考.具体如下: import java.io.*; public class CheckEmail { public static boolean checkEmail(String email) {// 验证邮箱的正则表达式 String format = "\\p{Alpha}\\w{2,15}[@][a-z0-9]{3,}[.]\\p{Lower}{2,}"; //p{Alpha}:内容是必选的,和

  • java使用正则表达式判断手机号的方法示例

    本文实例讲述了java使用正则表达式判断手机号的方法.分享给大家供大家参考,具体如下: 要更加准确的匹配手机号码只匹配11位数字是不够的,比如说就没有以144开始的号码段, 故先要整清楚现在已经开放了多少个号码段,国家号码段分配如下: 移动:134.135.136.137.138.139.150.151.157(TD).158.159.187.188 联通:130.131.132.152.155.156.185.186 电信:133.153.180.189.(1349卫通) 那么现在就可以正则匹

  • Java使用正则表达式判断字符串是否以字符开始

    Java 正则表达式判断字符串是否以字符开始: public static boolean startWithChar(String s) { if (s != null && s.length() > 0) { String start = s.trim().substring(0, 1); Pattern pattern = Pattern.compile("^[A-Za-z]+$"); return pattern.matcher(start).matche

  • PYTHON 中使用 GLOBAL引发的一系列问题

    哪里出问题了 python 中,使用 global 会将全局变量设为本函数可用.同时,在函数内部访问变量会先本地再全局. 在嵌套函数中,使用 global 会产生不合常理的行为. 上代码: In [96]: def x(): b = 12 def y(): global a,b a = 1 b = 2 y() print "b =",b ....: In [97]: a = 111 In [98]: del b In [99]: x() b = 12 In [100]: a Out[1

  • 针对distinct疑问引发的一系列思考

    有人提出了这样一个问题,整理出来给大家也参考一下 假设有如下这样一张表格: 这里的数据,具有如下的特征:在一个DepartmentId中,可能会有多个Name,反之也是一样.就是说Name和DepartmentId是多对多的关系. 现在想实现这样一个查询:按照DepartmentID排完序之后(第一步),再获取Name列的不重复值(第二步),而且要保留在第一步后的相对顺序.以本例而言,应该返回三个值依次是:ACB 我们首先会想到下面这样一个写法 select distinct name from

  • java中添加按钮并添加响应事件的方法(推荐)

    关于Java容器,面板等自行百度学一下吧 </pre><pre name="code" class="java">private Button LogInbtn = new Button("登陆"); final static JFrame buyerpagemain = new JFrame(); final Container contentPane = buyerpagemain.getContentPane();

随机推荐