范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

切记,这样打日志定位Bug又快又准

  概述
  日常工作中,程序员需要经常处理线上的各种大小故障,如果业务代码没打印日志或者日志打印的不好,会极大的加大了定位问题的难度,使得解决bug的时间变长了。对于那种影响比较大的bug,处理时间是分秒必争的,慢几秒处理完,可能GMV就哗啦啦的掉了很多。
  一个程序员是否优秀,其中一个判断维度就是:处理线上问题是否快狠准,而其中日志是帮我们快速定位问题的绝佳手段。
  下面分享一下笔者平时在业务系统里记日志的一些手法和习惯,希望对大家有一些帮助。 请统一日志格式
  日志格式最好是统一的,即方便查看定位问题又方便统计收集。我一般喜欢定义一个LogObject对象,里面定义日志的各个字段。例如: import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty;  public class LogObject {     @JsonProperty(index = 1)     private String eventName;      @JsonProperty(index = 2)     private String traceId;      @JsonProperty(index = 3)     private String msg;      @JsonProperty(index = 4)     private long costTime;      @JsonProperty(index = 6)     private Integer userId;      @JsonProperty(index = 7)     private Object others;      @JsonProperty(index = 8)     private Object request;      @JsonProperty(index = 9)     private Object response;       public String getEventName() {         return eventName;     }      public LogObject setEventName(String eventName) {         this.eventName = eventName;         return this;     }      public Object getRequest() {         return request;     }      public LogObject setRequest(Object request) {         this.request = request;         return this;     }      public Object getResponse() {         return response;     }      public LogObject setResponse(Object response) {         this.response = response;         return this;     }      public String getMsg() {         return msg;     }      public LogObject setMsg(String msg) {         this.msg = msg;         return this;     }        public long getCostTime() {         return costTime;     }      public LogObject setCostTime(long costTime) {         this.costTime = costTime;         return this;     }       public Integer getUserId() {         return userId;     }      public LogObject setUserId(Integer userId) {         this.userId = userId;         return this;     }      public Object getOthers() {         return others;     }      public LogObject setOthers(Object others) {         this.others = others;         return this;     }      public String getTraceId() {         return traceId;     }      public LogObject setTraceId(String traceId) {         this.traceId = traceId;         return this;     }
  traceId: 调用链id
  eventName: 事件名称,一般就是业务方法名称
  userId: C端用户id
  msg: 结果消息
  costTime: 接口响应时间
  request: 接口请求入参
  response: 接口返回值
  others: 其他业务参数
  使用链式的风格,方便设置字段的值: long endTime = System.currentTimeMillis(); LogObject logObject = new LogObject(); logObject.setEventName(methodName)          .setMsg(msg)          .setTraceId(traceId)          .setUserId(backendId)          .setRequest(liveRoomPushOrderReqDto)          .setResponse(response)          .setCostTime((endTime - beginTime));  LOGGER.info(JSON.toJSONString(logObject));
  当然最好还是封装出一个工具类出来,例如叫:LogTemplate,作为一个统一的入口。另外可以使用JsonProperty注解,指定字段的顺序,例如通过index=1,将eventName放置在最前面。 @JsonProperty(index = 1) private String eventName;将request和response放置在一起
  将请求和返回值,放置在同一条日志里,有个好处,就是非常方便查看上下文日志。如果打印成两条,返回值那条可能被冲到很后面,而且也得再做一次grep操作,影响效率。
  具体的日志如下: {    "eventName":"createOrder",    "traceId":"createOrder_1574923602015",    "msg":"success",    "costTime":317,    "request":{       "uId":111111111,       "skuList":[          {             "skuId":22222222,             "buyNum":1,             "buyPrice":8800,          }       ]    },    "response":{       "code":0,       "message":"操作成功",       "data":{          "bigOrderId":"BIG2019",          "m2LOrderIds":{             "MID2019":{                "22222222":"LIT2019"             }          }       }    } }
  为了能拼成一条,有两种方案,一种是比较low的,直接在代码里使用try catch finally,例如:  @PostMapping(value = "/createOrder")     public JsonResult createOrder(@RequestBody Object request) throws Exception {         String methodName = "/createOrder";         Integer backendId = null;         String msg = "success";         long beginTime = System.currentTimeMillis();         String traceId = "createOrder_"+beginTime;         JsonResult response = null;         try {             OrderCreateRsp orderCreateRsp = orderOperateService.createOrder(request, traceId);             response = JsonResult.success(orderCreateRsp);         }         catch (Exception e) {             msg = e.getMessage();             LOGGER.error(methodName+",userId:"+backendId+",request:"+ JsonHelper.toJson(request),e);             throw new BizException(0,"下单失败");         }         finally {             long endTime = System.currentTimeMillis();             LogObject logObject = new LogObject();             logObject.setEventName(methodName)                      .setMsg(msg)                      .setTraceId(traceId)                      .setUserId(backendId)                      .setRequest(request)                      .setResponse(response)                      .setCostTime((endTime - beginTime));              LOGGER.info(JSON.toJSONString(logObject));         }          return response;     }
  这种方案呢,有个缺点,就是每个业务方法都得处理日志,更好的方案是使用aop加thread local的方式,将请求统一拦截且将返回值和请求参数串起来,这个网络上的方案很多,这里就不阐述了。
  对于对性能要求比较高的应用,反而推荐第一种方案,因为使用aop,有一些性能损耗。像我之前在唯品会参与的商品聚合服务,用的就是第一种方案,毕竟每一秒要处理上百万的请求。另外,附送学习资源:Java进阶视频资源 日志里加入traceId
  如果应用中已经使用了统一调用链监控方案,且能根据调用链id查询接口情况的,可以不用在代码里手动加入traceId。如果应用还没接入调用链系统,建议加一下traceId,尤其是针对聚合服务,需要调用中台各种微服务接口的。像聚合层下单业务,需要调用的微服务就有如下这么些: 营销系统 订单系统 支付系统
  下单业务调用这些接口的时候,如果没有使用traceId进行跟踪的话,当下单失败的时候,到底是哪个微服务接口失败了,就比较难找。下面以小程序端,调用聚合层下单接口的例子作为展示: //营销系统 {    "eventName":"pms/getInfo",    "traceId":"createOrder_1575270928956",    "msg":"success",    "costTime":2,    "userId":1111111111,    "request":{       "userId":1111111111,       "skuList":[          {             "skuId":2222,             "skuPrice":65900,             "buyNum":1,             "activityType":0,             "activityId":0,          }       ],    },    "response":{       "result":1,       "msg":"success",       "data":{          "realPayFee":100,       }    } }//订单系统 {    "eventName":"orderservice/createOrder",    "traceId":"createOrder_1575270928956",    "msg":"success",    "costTime":29,    "userId":null,    "request":{       "skuList":[          {             "skuId":2222,             "buyNum":1,             "buyPrice":65900,          }       ],    },    "response":{       "result":"200",       "msg":"调用成功",       "data":{          "bigOrderId":"BIG2019",          "m2LOrderIds":{             "MID2019":{                "88258135":"LIT2019"             }          }       }    } }//支付系统  {    "eventName":"payservice/pay",    "traceId":"createOrder_1575270928956",    "msg":"success",    "costTime":301,    "request":{       "orderId":"BIG2019",       "paySubject":"测试",       "totalFee":65900,    },    "response":{       "requestId":"test",       "code":0,       "message":"操作成功",       "data":{          "payId":123,          "orderId":"BIG2019",          "tradeType":"JSAPI",          "perpayId":"test",          "nonceStr":"test",          "appId":"test",          "signType":"MD5",          "sign":"test",          "timeStamp":"1575270929"       }    } }
  可以看到聚合层需要调用营销、订单和支付三个应用的接口,调用的过程中,使用traceId为createOrder_1575270928956的串了起来,这样我们只需要grep这个traceId就可以把所有相关的调用和上下文找出来。
  traceId如何生成呢,一种简单的做法是,使用System.currentTimeMillis() 加上业务接口名字,如:  long beginTime = System.currentTimeMillis();  String traceId = "createOrder_"+beginTime; 加traceId会侵入到业务方法里,比如说:  public void createOrder(Object obj) {   long beginTime = System.currentTimeMillis();    String traceId = "createOrder_"+beginTime;    pmsService.getInfo(obj,traceId);    orderService.createOrder(obj,traceId);    payService.getPrepayId(obj,traceId); }
  像pmsService这些内部的service方法,都需要加一个traceId字段,目前我觉得还好,要是觉得入侵了,也可以考虑thread local的方式,处理请求的时候,为当前线程存储一下traceId,然后在业务方法里,再从当前线程里拿出来,避免接口方法里的traceId满天飞。

老大哥在看着你!盟国丹麦为何逃不过美国国安局的监视?奥威尔小说1984中有一句令人惊悚的名言,老大哥在看着你!其中老大哥是奥威尔小说中大洋国和英社的首领,他几乎无处不在,始终监视着大洋国人民的一举一动,让人不得不如履薄冰,他所代表的美国上流社会种的蓝血贵族WASP指的是什么?美国是一个新兴的国家,历史非常短暂,当五月花号达到北美大陆时,中国已经是大明时代了。这就有一个特点,那就是美国缺乏欧洲那么历经非常多代的贵族文化,但是在短短的数百年间,美国人也搞出顶级科学家李浚秀领衔,恒大电池研发原来这么强关系到新能源汽车最重要的续航里程与电池安全问题,车载电池对于新能源汽车来说称得上是重中之重。今天,恒大董事局主席许家印视察了位于深圳的恒大全球电池研究院,不同于之前网上风传恒大造车连放大招恒大汽车实力演绎要做就做最好恒大汽车作为跨界造车的代表,其未来发展也备受关注,我们看看它换道之后,超车的概率有多大?恒驰1路跑就在本周,恒大汽车连放大招,既发布了恒驰1的路跑和内饰视频,也首次公开了科研团队。李雪琴自爆去Redmi发布会,不是因为自己,竟是为了她爸爸?11月26日的RedmiNote9的发布会,按照以往的经验,一般都是在白天召开,但是这次专门为了三剑客的新品发布,特意把时间调整到了晚上的八点。其实更重要的原因就是小米集团副总裁卢外贸订单迎来大回流,中国制造备受追捧,这一次意大利也坐不住了最近,随着全球经济不断复苏,中国制造迎来一股订单回流的热潮。数据显示,从4月开始,中国纺织服装品的出口量就持续增长,到8月份,全国纺织品的出口额达到147。2亿美元,同比增长了47屏幕里的你,还是那个真实的你吗?你的眼中希望看到的是真实还是虚幻?是美艳还是还原?当一切发生在你身边,当故事的主角变成你前几天突然看到一条新闻,说是某某网红突然素颜,打赏的某位男士立马删号,姑且不论是不是炒作或者Mate30加持下的随手拍生活没上榜照样强自从手机有了拍照功能,随手来一张的习惯就没有停过,原来的时候一直没有感觉拍了多少照片,可能是因为原来的手机,内存小,运行慢,拍照差,其实找来找去,还是自己的原因,现在可好,因为工作从一件囧事说特点Mate30的那些小不同Mate30到手一月有余,因为接近年底,工作上比较忙碌,现在基本是52白加黑模式,压根连个周末都没有了,今天写这篇帖子,也是忙里偷闲,过了这么长时间大家其实也都对Mate30很了解让摄影充满乐趣与不同初识大疆灵眸OSMOMobile3云台平时都是拿着手机随手拍,左拍拍右拍拍的,固定位拍照,还要靠着自己的麒麟臂,静态照片还好说,摄像这样坚持着就难了,再来回的跑动,操作手机变焦,拍出来的视频问题就多了,曾经也看过很多的自己动手丰衣足食,这么做可以省一百多大毛荣耀智慧屏壁挂安装开始之前,先说两个事情第一喇叭数量的那点事儿主要是看到网上有人在质疑荣耀智慧屏Pro六个喇叭的事情,本来我想拆了后盖,然后看看到底是几个喇叭,看看鸿鹄的芯片到底长什么样子,结果遇到
联想本月20号将就改制情况通报,网上盛传是真是假?耍尽花招柳传志反正就是不把国家的钱交出来。一会儿这样一会儿那样都是为了钱呲牙捂脸建议交回中科院管理,中科院与柳有利益挂勾的,必须干掉,否则,与党与国与民皆不利!自己发布已经毫无意义特斯拉汽车发生致命车祸,法国一家出租车公司全面停用Model3报道截图据路透社15日报道,在上周末一辆特斯拉Model3型汽车发生致命事故后,欧洲出租车平台G7宣布,该公司已暂停在其车队中使用该型号汽车。法国媒体报道称,这辆特斯拉汽车在行驶过剑指iPhone14!华为P60Pro或将首次实现全机国产化,令人动容作为一个普通消费者,很难想象2021年,一台4G手机可以卖到8000元以上,华为P50Pro典藏版就做到了,网友戏称史上最贵4G手机。玩笑归玩笑,但是华为P50Pro的销量还是挺好新能源汽车保险专属保险来了!自燃充电桩损失都可理赔来源人民网原创稿一图读懂新能源汽车专属保险人民网北京12月14日电(记者张文婷)新能源汽车专属保险来了!近日,中国保险行业协会(以下简称保险业协会)发布新能源汽车商业保险专属条款(助听器通道是什么意思?通多数越多越好?看真相在选择助听器的时候,提前了解过助听器的朋友大多都会问这款助听器的通道数是多少?通道数经常被当作初步评估助听器好与不好的关键因素,甚至是最重要的指标。尤其是在选择价位不同的助听器之间雷军退出多家关联公司,小米王化回应正常变更12月14日,一则雷军退出多家小米关联公司的话题冲上热搜。据话题词介绍,近日,雷军接连退出多家小米关联公司法定代表人执行董事或董事长职务,包括广东小米科技有限责任公司广州小米通讯技元宇宙概念股集体爆发,互联网巨头争相入局元宇宙概念股集体爆发,互联网巨头争相入局房产之后元宇宙又盯上会议自元宇宙概念走红以来,热度持续居高不下。红星资本局注意到,12月13日的A股,涨停板几乎被元宇宙概念霸屏。截至收盘,双碳时代,谁在重写数字金融?正如车的器官化之说,绿色一词似乎从未像今天这般被重新切割及深刻理解,因为它所涵盖的范畴已不再是单一维度的生产生活制造等高耗能产业,还包含了数据算法以及创新的科技应用等。当新定义下的南瑞集团成果亮相2021世界智能制造大会12月12日获悉,由江苏省人民政府工业和信息化部中国工程院中国科学技术协会共同主办的2021世界智能制造大会在南京国际博览会议中心举办。在本届大会上,南瑞集团带来了在全力支撑国家电报告续航和充电仍是新能源车主购车最大顾虑来源人民网原创稿人民网北京12月14日电(记者车柯蒙)中国汽车工业协会日前发布的数据显示,今年111月,新能源汽车产销分别完成302。3万辆和299万辆,同比均增长1。7倍。当前,对联想对司马南质疑联想2009年29国资出售国资流失回应的再质疑怎么看联想回应司马南关于司马南质疑联想2009年出售29国资?想当年科学院成立联想集团,就像科学院给了一些人一座别墅,让这些人经营别墅里产品,别墅里的人经过操作得到了别墅一些产权,