分类: 开发日志

  • 关于开发中的日志信息

    日志信息在开发和调试中是起到辅助作用,但是在线上环境,确实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 : 同一个 线程链路中,这个值都是相同的,不同线程链路中 这个值不同

  • 我眼中的日志到底是什么

    在讲日志之前先看2个问题:

    1、当用户在使用某个功能报错时,开发该如何排查问题?
    2、当出现某个接口返回数据很慢时,该如何优化?

    要想快速的解决已上2个问题,就依赖于日志了。

    日志是开发为了跟踪用户行为和代码异常而打的记录。

    当一个请求到来时,我们一般会登记以下几种日志:

    1、AccessLog:用户访问日志。一般会记录请求URL、请求参数、用户ID、行为发生时间、接口返回值等几个关键指标。

    2、Exception:代码异常。代码异常一般会记录报错信息、报错发生的代码是哪一行、报错发生时间等指标。代码异常日志是最重要也是经常要看的日志,根据报错可以快速定位到发生错误的原因,快速地修复问题。

    3、SqlLog:数据库查询日志。一般会记录SQL查询语句、数据库名表名、查询耗时等指标。

    4、第三方服务日志:调用第三方服务日志。如果后台调用了第三方服务,比如接入了公司内的统一登录服务,当调用该登录服务时,就记录这些行为。

    5、CronLog:定时任务日志。如果后台有定时任务,比如每天凌晨同步某个数据库到另一个仓库,则可以记录下该任务是否成功、成功耗时等。

    上面说的都是后台产生的日志,那么前端有没有错误日志呢?当然是有的,但是前端日志比后台就简单纯粹多了。前端一般只要记录发生错误的日志,上报到日志平台就可以了。

    如果没有用户向你投诉某个功能报错了,开发如何在用户发现错误之前避免这些错误?这时就需要给异常添加监控告警了。

    监控告警一般监控以下这些指标:

    1、流量异常:指的是pv相比于以前,猛然升高。可能存在有人在恶意刷页面

    2、服务崩溃:服务因为某种异常,导致的服务停止,不能正常访问。3、代码异常:代码发生错误。4、数据库查询过慢:可能因为查询人数过多、数据量过大、查询语句有问题导致的查询耗时过长。5、服务占用CPU/内存过高:可能因为访问人数过多或者代码有bug导致的内存泄漏/CPU占用高。