聊聊日志这件小事情

大数据

文|yubang

写应用不写日志,只会在撞板后也不知道为何撞板。线上的问题永远不会知道为何会发生,只会出现事故之后身处茫然之中。

哪怕用print也要输出关键数据

新手会经常在调试的时候使用print,不论这种方式的优劣,反正关键位置数据哪怕用print输出都比没有好。在linux系统,nohup启动进程的时候,可以把print输出的内容导到一个文件。只要有print,就多了一条路子来定位数据。

记录日志请用成熟的框架

真心不推荐用print来记录日志,为什么呢?因为成熟的框架往往可以设置日志的存储方式和随意控制存储哪种级别日志内容。

我们记录日志,大部分时候是不会翻阅的,但是我们很多时候又需要从日志挖掘一些数据。例如每天请求某个接口多少次,然后有哪些接口请求耗时超过1秒的等诸如此类。

如果日志需要用于分析,我们存在于文本,就需要编写繁琐的代码来获取结果。假如我们用了mysql或者mongodb等数据库存储日志,我们就可以简单调用API来统计数据。

我们再看看这些主流的日志框架(例如java的log4j,python的标准库logging),他们往往提供若干个记录日志的方法。例如debug,info,warn,error等。为什么日志要分等级呢?当我们在开发过程中,我们往往想看每一个中间的运算过程的结果,但是在线上环境我们却无需关注中间结果。如果我们有一个开关决定记录哪种等级日志,不是不用繁琐修改代码么。再者,各种等级日志默认有一个标识字符串,方便我们随时查阅各种级别的日志,例如我们关注error而很多时候忽视warning。

日志分割

我们总不能把日志只存储在一个文件或者一个数据表里面,一个原因是一些日志时间久了就可以丢弃,以便节省存储空间。另一个原因是,单文件单表在数据量不断加大的情况下,查询效率会不断下降。

分割日志,我们往往会采用两种分割方法。

  • 按时间分割
  • 当数据量达到一定量的时候分割

当然,两种方案都有自己的好处。不过个人比较推崇使用第一种分割方式,这种方法在统计的时候,处理难度相对较少。

我的日志应该存放在哪里?

让我们来看看,一般日志的存储方式。

  • 文件
  • mysql
  • mongodb
  • hbase
  • PostgreSQL

除了上面那些存储方案,还有很多,无法一一列出。

在应用的萌芽阶段,用文件存储日志是利大于弊的。一者,使用简单,无需复杂的配置,也无需额外的依赖。再者,一开始查错都可以用linux的命令直接定位所需要的信息。

随着应用的不断发展,我们一个应用可能运行在多台服务器上。如果我们依旧采用文件这种日志存储方案,我们想查阅日志,还得一个一个服务器的找呢。这个时候,采用mysql这种存储方案就很有必要性了。因为可以把日志统一存在一个mysql数据库里面。

但是mysql没法方便应对日志数据项不断变更的情况下,而mongodb由于是非关系型数据库,数据结构可以随时变动,并且写效率比较高。

hbase在很多日志分析框架中都作为存储,应对海量数据还是不错的,由于没怎么用过,就不好评论了。

我们需要一个统一的日志平台

当我们手头有几个应用在线上的时候,如果我们为每一个应用开一个数据库来存储,那么还需要开若干个日志分析面板来翻阅日志呢。

这个时候,我们需要一个统一的接口,一个平台来管理所有应用的日志。当然,我也自己造了一个轮子,代码开源放在https://github.com/yubang/ilog

实时日志分析ELK平台

这里不是讲解这套流行的日志分析平台的使用,而是看看它的工作原理。ELK其实是三个软件,其中一个用于收集各台服务器上的数据,然后一个是提供搜索分析服务的,一个就是可视化展示。

我们来看看收集日志的东西:logstash,它是实时增量的把日志同步到elasticsearch。对于收集日志来说,难点就在增量和实时这两个点。我所想到的方法是,记录上一次读取到的日志行数,再次读取用seek直接定位位置。实时可以监听文件变化而触发,系统有对应的API。

业务日志

上面说的日志都是用于线上发现BUG或者异常,用于系统分析。还有一类日志,就是记录一些特别的业务信息。例如一个用户的余额系统,我们要记录用户什么时候,在哪里,用什么途径,充值了多少金额,充值前余额是多少,充值后余额是多少等。用户在消费的时候同样要记录一堆信息。

日志与代码耦合问题

日志的好处说了一大堆,但是当我们为应用添加日志的时候,往往需要在代码里面添加一行又一行的代码串。就像整洁光滑的墙壁,嵌入一颗一颗钉子,画面没有一丝违和感。

两种可行的解决方案:

  • 使用钩子函数
  • 无埋点日志

使用钩子函数很容易理解,以flask框架为例,可以挂载函数在一个请求前执行,也可以挂载函数在请求后执行。

无埋点日志就比较复杂了,代码不能直接写在代码里面,那么就是要在代码运行的时候注入记录日志的代码。一些现有的技术,例如百度统计的js,只需引入一个js就可以拿到一堆数据用于分析网站。