程序员学习每一门语言都是从打印“hello world”开始的,日志也是新手程序员学习、调试程序的一大利器。当项目上线之后,也会有各种各样的日志,比如记录用户的行为、服务器的状态、异常情况等等。打印日志似乎是一件很简单、不值得一提的事情。但是,当看到线上项目居然有这样的日志的时候,不禁想问问我们真的会打印日志吗?
***********************************
Error Happened, F*ck
User xxx can not login
在我看来,打印日志是一门艺术,而且长期被程序员所忽视,本文尝试回答以下几个问题,分享我对打印日志的一些思考:
(1) why or when to log
(2) what to log
(3) how to log and tips
注意:本文中会用“打印”日志来统一表示日志的输出,但不是我们狭义理解的输出到终端或者stdout、stderr, 而是泛指将日志内容输出到任何目标,包括但不限于终端、文件、网络传输。
本文地址:http://www.cnblogs.com/xybaby/p/7954610.html
why or when to log
为什么时候要打印日志,或者什么时候打印日志,在我看来是同一个问题,那就是打印日志的目的。不同的目的,决定了日志内容的格式,输出的频度,输出的目的地。那可能有哪些打印日志的原因?
(1)调试开发
目的是开发期调试程序使用,这种日志量比较大,且没有什么实质性的意义,只应该出现在开发期,而不应该在项目上线之后输出。如何控制这种类型的日志是否输出,后面也会详细讨论。
(2)用户行为日志
这种类型的日志,记录用户的操作行为,用于大数据分析,比如监控、风控、推荐等等。这种日志,一般是给其他团队分析使用,而且可能是多个团队,因此一般会有一定的格式要求,开发者应该按照这个格式来记录,便于其他团队的使用。当然,要记录哪些行为、操作,一般也是约定好的,因此,开发者主要是执行的角色。
(3)程序运行日志
记录程序的运行状况,特别是非预期的行为、异常情况,这种日志,主要是给开发、维护人员使用。什么时候记录,记录什么内容,完全取决于开发人员,开发者具有高度自主性。本文讨论的主要也是指这种类型的日志,因为作为一个服务端开发、运维人员,程序运行日志往往是解决线上问题的救命稻草。
(4)记录系统或者机器的状态
比如网络请求、系统CPU、内存、IO使用情况等等,这种日志主要是给运维人员使用,生成各种更直观的展现形式,在系统出问题的时候报警。
what to log
一条日志要包含哪些内容,我觉的应该包含 when、where、how、what、who、context,具体含义会在下面一个小节介绍。
我们要记录日志,总是要在某个时机,比如用户的某个请求、某个网络调用、或者内部状态发生了改变。在后文中,统称为事件(event),即日志内容是对某个事件的描述。
when: the time event happens
when,就是我们打印日志的时间(时间戳),注意这里的时间指的是日志记录的事件的发生时间,而不是日志被最终输出的时间。比如如果日志的输出目标是文件,那么这里的when不是写入到文件的时间,因为往往有延迟。
时间的重要性,在《Distributed systems for fun and profit》中有很好的讲述。
首先,时间可以被解读(Interpretaion)成具体的、现实的日期,让我们可以知道事件发生时的时间环境,比如出问题的时候是不是有什么活动、结合系统日志分析当时服务器的网络、CPU、IO是怎么样。具体的时间点也可以帮助我们分析事件的发生是不是存在某种规律,比如是不是每天、每周、每月的固定时间点都会出问题。
其次,时间可以表示一个(一组)事件的持续时间(duration)。比如,可以监控处一段代码的执行时间,也可以记录一个网络请求的耗时。这个时间差也能给出我们很多信息,比如根据经验预判当时程序的运行状态,是否比较‘卡’。
最后,时间代表了事件发生的顺序(order),我们将多个日志按照时间排序,这个顺序能帮助我们debug到底问题是怎么产生的,是按照什么样的时序。这对于多进程(多线程)、异步、分布式程序而言非常重要。虽然我们知道在分布式系统维护全局的时间(global clock)是很复杂的一件事情,但我们使用NTP协议,基本上能解决大部分的问题。
where: where the event happens
where,就是指日志是在哪里的被记录的,本质上来说,是事件的产生地点。根据情况,可以具体到是哪个模块、哪个文件,甚至是哪一个函数、哪一行代码。实践告知,至少应该包含模块信息。
where的意义在于能够让自己或者其他程序员一眼就看出这条日志是在哪里产生的,这样就能大致定位问题处在哪里,而不用从日志内容全局grep代码
how:how importance of the event
how important,代表了事件的重要性,我们会打印很多各种类型的日志,但是不同的日志的重要性是不一样的。比如,调试日志是最不重要的,是不应该出现在线上项目的,但是程序运行报错日志却需要认真对待,因为代表程序已经出现了异常。即使是程序的报错日志,也有不同的紧急程度,一次网络请求超时跟子进程异常退出份量完全不一样。
因此,每一条日志都应该有log level,log level代表了日志的重要性、紧急程度。不同的语言、框架的level细分有一定的差异,但都会包括debug,info,warn,error,fatal(critical)。其重要程度从名字就可以看出。
当然,有时候,warn与error,或者error与fatal之间的界限不那么明显,这个需要在团队之间达成共识。在我们的线上项目,对于error、fatal级别的日志都会报警,如果出现了error日志,那么最迟需要第二天去处理,如果是fatal日志,即使是在大半夜,也得立刻起来分析、处理。
what:what is the log message
what是日志的主体内容,应该简明扼要的描述发生的什么事情。要求可以通过日志本身,而不是重新阅读产生日志的代码,来大致搞清楚发生了什么事情。所以,下面这个日志是不合格的:
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。