关于开发中的日志信息

日志信息在开发和调试中是起到辅助作用,但是在线上环境,确实bug回归查询的关键手段。好的日志能很好的定位系统错误。关于日志,我整理了几个问题点。希望自己也能经常回来看看,把这些点记在脑海中来。

1、日志分为哪几种

(1) 调试开发日志

目的是开发期调试程序使用,这种日志量比较大,且没有什么实质性的意义,只应该出现在开发期,而不应该在项目上线之后输出。

(2) 用户行为日志

这种类型的日志,记录用户的操作行为,用于大数据分析,比如监控、风控、推荐等等。这种日志,一般是给其他团队分析使用,而且可能是多个团队,因此一般会有一定的格式要求,开发者应该按照这个格式来记录,便于其他团队的使用。当然,要记录哪些行为、操作,一般也是约定好的,因此,开发者主要是执行的角色。这种日志,又叫事件上报,或埋点。

(3)程序运行日志

记录程序的运行状况,特别是非预期的行为、异常情况,这种日志,主要是给开发、维护人员使用。什么时候记录,记录什么内容,完全取决于开发人员,开发者具有高度自主性。本文讨论的主要也是指这种类型的日志,因为作为一个服务端开发、运维人员,程序运行日志往往是解决线上问题的救命稻草。

(4)记录系统或者机器的状态

比如网络请求、系统CPU、内存、IO使用情况等等,这种日志主要是给运维人员使用,生成各种更直观的展现形式,在系统出问题的时候报警。

2、运行日志可以反馈哪些信息

(1) 通用信息

时间,日志类型,所在类等 。 (日志框架一般都带了)

(2) 进度信息

比如一个服务有5个步骤,是否开始这个服务。执行到了哪步等。

(3) 异常信息

log.error(“什么操作发生了异常,异常信息为: “+e.toString())

这里要 特别注意一点,如果记录了异常日志,不要继续抛出异常了。 否则可能多次记录日志,因为其他位置可能还会捕获并记录。

注: 该写error的日志,千万别写为info,因为error有个最重的功能就是传入e,会自动打印异常栈,而info必须显式的打印。

(4) 接口间的日志(传递唯一标识)

3、http://log.info 和String.format的对比

效果基本相同,log有些前缀信息。

http://log.info(“param1: {} , param2: {}, param3: {}”,111,222,333);

String format = String.format(“param1: %s , param2: %s, param3: %s”, 111, 222, 333);

4、 双object和objects的区别

objects会创建一个objects数组。会增加消耗。

但是双object的2个对象是独立的,性能更高。 这也是把性能发挥到极致了。

5、格式字符串(format)和直接字符串的区别

(1)格式字符串可以使用占位符

(2)format还有个优点,就是如果日志级别不支持,不会创建对象。

这里说的不是传入的object对象,而是logger.trace()对象。

例如,默认的级别是info,trace对象是不会创建的。可以还没想到如何验证。

6、性能提升方法

(1)尽量使用格式字符串。(可以减少低级别的日志对象创建,但是对入参object无效)

(2)能使用双object就不要用objects数组。(省略数组开销)

(3)使用logger.isErrorEnabled() 。 尤其在入参比较大的时候,这种方法性能很高。

7、为什么要日志优化

通常不会有这个问题,因为开发者只怕日志少,不怕日志多。

但是,如果经历过一天10G、甚至40G日志的场景,就能体会到了。

日志太大,即使一个简单的命令,捞数据效率也很慢,更别提复杂场景的数据捞取。

什么,拆分日志,40G的日志文件,即使1000M一个文件,也要拆分40个,要是100M一个,那要400个。 是不是很崩溃。所以日志肯定不是越多越好。

8、微服务中日志

解决方案

方案一:

仅依靠看日志效率还是有点低,一天出几个问题,就够受的了。 所以最好加入监控机制。

方案二:

其实springcloud中的slueth组件就是专门解决分布式日志的跟踪的。

requestId实现分布式的日志追踪

微服务中,经常用到不只一个rpc服务。通过requestId可以贯穿整个流程。

requestId可以放在入参父类中,自动生成。

继续调用其他rpc的时候requestId也传递出去。接收方先判断是否有requestId,如果存在,就直接使用,不存在则生成。

9、多线程日志如何打

单线程根本不用指定uuid,因为日志工具一般都自带。那么多线程为什么要打日志呢?

常用的两种方案。

方案一:final String sonUuid=“asldfjalkdjf”; 直接带过去。同理,其他参数也可以设置为final带过去。(线程中只允许直接带入final变量)

方案二:通过构造器带过去。

10、占位符和入参哪个少了会报错?

实测都不会报错。如果少了,打印不出来而已。

11、日志会影响效率吗

一般来说,单条日志的耗时是1ms级别甚至更少。

所以一个请求,有二三十条日志也不碍事。

只要日志打印的不是特别夸张的对象就行。例如一个超大的对象,几万行的json等。

12、traceId、spanId、parentSpanId的区别

分布式的日志概念

raceId : 在一个 链路 中 traceId 唯一

spanId : 同一个线程中唯一, 从0始,按照调用链路从0递增

parentSpanId : 在同一个线程的链路中,用来连接 span

segmentId : 同一个 线程链路中,这个值都是相同的,不同线程链路中 这个值不同

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注