本文是《提升你的 Python 项目代码健壮性和性能》系列的第五篇文章。

讲的是日志系统 ELKFA 的搭建

# 0x00 前言

什么是 ELKFA?

这五个字母分别代表着五个开源软件

  • E - ElasticSearch
  • L - Logstash
  • K - Kibana
  • F - FileBeat
  • A - APM-Server

利用这五个软件的组合,我们可以在比较短的时间打造两个系统:

  1. 日志系统,分析 Nginx 日志,Gunicorn 日志,Flask 日志,Django 日志
  2. APM 系统,解决两个问题
    2.1 Metric 分析:Flask 是否正常运行,接口请求信息定期发送到 APMServer 这边,方便我观察服务是否正常,接口和业务逻辑的执行的时间是否在预期范围内。
    2.2 Trouble Shooting: 如果程序报了异常,我想把需要报的异常堆栈信息打出。方便我快速的 Trouble Shooting

# 0x01 任务 1: 分析 Nginx 日志

Nginx 众所周知,Nginx 日志是个宝库,所以本文选取了 Nginx 作为日志分析的案例。

对于 Nginx 日志,可以采用 FileBeat 上传到 Logstash, 由 Logstash 对文件进行解析,并存储到 ElasticSearch

然后从 Kibana 进行分析。

# 第一步:配置 Nginx

首先,让 Nginx 的配置输出的日志符合某种模式,方便软件进行解析。

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
							'$status $body_bytes_sent "$http_referer" '
							'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

然后重启 nginx

# 第二步:拉取 Nginx 日志

一天后,从 Nginx 服务器上拉一下 access.log 放到

elastic-labs/logs/prod/nginx 下

# 第三步:开启 ELFKA

git clone git@github.com:twocucao/elastic-labs.git
cd elastic-labs
docker-compose up

啥、? 不会搭 Docker? 见文末
啥、? 不知道 ElasticSearch 怎么用、? 见文末

如果运行正常,终端应该是这样的

打开 kibana 进行观察

http://localhost:5601/

# 第四步:日志探秘

默认情况下,每一天的 Nginx 日志会在 ES 里创建一个 Index, 所以,你需要用 Index Pattern 来进行统计

来看看我们可以得到哪些内容

  1. 用户 IP 以及通过 GeoIP 得到的大致地理位置。
  2. OS 的类型 (Win/Mac/Linux/IOS/Android)
  3. 客户端的类型,浏览器 / 小程序 / 客户端
  4. 访问的接口,类型,频率
  5. 访问服务的频率
  6. 还有很多其他可以深挖的地方,比如通过用户访问的次序推断用户的使用姿势和思考方式等等

对于第六点,有些人可能有些疑惑,这也能?

当然咯,假设用户在搜索引擎里面,先搜索了『美女』, 然后搜索了『雪白』, 然后又搜索了『白-洁』, 那基本上这个人搜索的三个词就具备一定的关联性,想搜索的这个雪白就不是『雪白』的意思 > 而是你懂的。

# 第五步:扩展思考,日志解决方案

上面四个步骤是为了解决分析 Nginx 日志的问题

一条日志从打印出来,到能在 Kibana 进行分析,需要经过如下的步骤:

  1. 按照某种日志格式写到文件里,然后被 FileBeat 接收,FB 判断为『 Nginx 模块的日志之后』上传到 Logstash
  2. Logstash 按照一个端口一个类型的方式接受该类型的日志。通过 filters 和插件进行匹配和修改,比如 grok 的 pattern 来匹配每一条日志(类似于正则匹配), 抽出需要独立成字段的部分。比如通过 geoip 进行地址匹配,比如对字段进行 convert
  3. 输出匹配结果到 ElasticSearch
  4. Kibana 通过更加边界的工具来查询 ElasticSearch

如果你想要自定义日志获得更加完美的解决方案,那就需要对这几个流程进行进行细化。

比如你想通过 Flask 的日志来达到更好的用户操作定位。这就需要读者自行依照自己的理解来 hack 了

# 0x02 任务 2: 监控 Flask App 的 APM

# 第一步:开启 ELFKA

同任务一的启动方式

# 第二步:开启 flask app

pip3 install poetry # 比 pip / pipenv 更好的依赖管理和构建工具
poetry install -vvv
poetry shell
flask run

写一个简单的管理和依赖工具

from flask import Flask
from elasticapm.contrib.flask import ElasticAPM

app = Flask(__name__)

app.config["ELASTIC_APM"] = {
    "SERVICE_NAME": "dev-flask",
    'SECRET_TOKEN': '',
}
apm = ElasticAPM(app)

@app.route("/")
def hello():
    return "Hello, World!"

@app.route("/home")
def home():
    return "home!"

@app.route("/<int:num>")
def hello_num(num):
    import random
    if random.randint(1, 100) > 95:
        raise Exception(f"num") # 有接近 1/5 的概率会故意抛出异常
    return f"Hello, {num}!"

随手写一个脚本 20 分钟内持续不断的访问接口

SECONDS=0
while [[ SECONDS -lt 1200 ]] ; do
	for (( i = 0; i < 20; i++ )); do
		curl "http://localhost:5000/$i"
		curl "http://localhost:5000/$i"
		curl "http://localhost:5000/$i"
		curl "http://localhost:5000/$i"
		curl "http://localhost:5000/$i"
		curl "http://localhost:5000/$i"
		curl "http://localhost:5000/$i" &
		curl "http://localhost:5000/$i" &
		curl "http://localhost:5000/$i" &
		curl "http://localhost:5000/$i" &
		curl "http://localhost:5000/$i" &
		curl "http://localhost:5000/$i" &
		curl "http://localhost:5000/$i" &
		curl "http://localhost:5000/$i" &
	done
done

# 第三步:APM 探秘

20 分钟过去了,我们可以获知到什么呢?

  1. Metric 分析:Flask 是否正常运行,接口请求信息定期发送到 APMServer 这边,方便我观察服务是否正常,接口和业务逻辑的执行的时间是否在预期范围内。
  2. Trouble Shooting: 如果程序报了异常,我想把需要报的异常堆栈信息打出。方便我快速的 Trouble Shooting

先设置时间为最近 30 分钟

在这里可以看到接口的访问情况

先看 Metric 分析

这里可以看到接口的稳定性,服务器的基本负载,以及 Error 的出现频次。

再看 Error

看到这里简直泪目 这就是 ELK 版本的 Sentry 啊

Time Saving && 防脱发利器

# 第四步:扩展思考

从 App 被监控到能在 Kibana 进行分析,需要经过如下的步骤:

  1. 在原有的 Flask App 里面进行添加 elastc-apm 的 agent (apm-client)
  2. agent 会定期将收集完毕的性能信息以及异常信息,发到 apm-server
  3. 输出结果到 ElasticSearch
  4. Kibana 通过更加边界的工具来查询 ElasticSearch

如果你想要自定义日志获得更加完美的解决方案,那就需要对这前两个流程进行进行细化。

比如公司用 Graphql 的接口,那么,在这种情况下,自带的 contrib 下的 flask 包的路由基本就是废掉的,你需要再 Hack 一下。

# 0xDD 结论

本来这篇文章打算写日志的最佳实践的,结果在查找资料的时候发现了一篇更好的文章

看完之后打消了这个念头,转而写如何使用 ELK 的系统落实这种日志分析系统

代码见 twocucao/elastic-labs

欢迎点赞 / 关注 /star 文明三连

# 0xEE 参考链接