前言
程序猿和运维几乎每天都需要和日志打交道,不同维度下可以区分多类日志。
如windows操作系统会将收集到的日志在
【计算机管理】→【系统工具】→【事件查看器】→【windows日志】。
Linux操作系统则通过syslog服务采集内核日志与非内核日志,一般存储在/var/log目录下。
上面都是系统层面的日志,我们自身研发后的各项服务最终投产后都会产生日志,在单体应用场景下日志查看很方便也很直接,可以存储到指定的目录下,出现问题直接到该目录打开日志通过关键字定位进行问题排查(当然关键日志也可以存储到数据库,后续通过sql方式排查)。
但是在分布式服务环境下,每个服务的日志都在各自的目录下甚至是直接在容器内,如果还是采取单体应用的方式进行日志检索的话效率太低了。这个时候就需要引入一个或N个中间件来解决这些烦恼了。
下图是我随意画的一张微服务场景下的日志管理流程图。
s1、s2、s3是日志的生产者(即我们的服务应用),logCenter是一个抽象化的持久层,可以是一个文件夹目录,也可以是Redis、ElasticSearch等任何能接收数据的中间件或数据库,它们用于存储采集后的日志,view则是日志的展示层,它负责从locCenter提取数据展示。如果需要对日志进行进一步的处理可以在logCenter采集到数据后先推送到数据处理中间件然后再推送到持久层(Logstash就是起这个作用),当然目前版本的beatfile其实已经具备了日志处理的能力,所以我下面的例子也是直接使用beatfile对日志进行处理后推送到持久层。
分布式系统日志管理方案
常见的分布式日志管理方案有下面几种
ElasticSearch + Logstash + Kibana
ElasticSearch + Fluentd + Kibana
ElasticSearch + Filebeat + Kibana
Loki + Promtail +Grafana
上面的方案均提供开源版本,其中有三种都是依赖了ElasticSearch(ES)作为日志的持久层。其中Logstash、Fluentd、Filebeat、Promtail均用于采集日志。对于日志的采集Filebeat可以说是里面性价比最高的组件(除Promtail外,Promtail不熟悉不妄下定论),资源消耗小,完善的配置,特别适合云服务器租不起的同志们~
本篇博客主要对filebeat进行讲解,下面就步入正题!
filebeat介绍
filebeat工作流程如下(摘自官网)
fillebeat由以下几个重要组件组成
input
harvester
processors
output
我们通过filebeat.yml配置文件可以对以上组件进行配置,filebeat启动后通过读取filebeat.yml配置文件制定日志采集流程。
input
input是filebeat的输入层,input支持多种类型,如log、docker、container、mqtt、filestream ...
filebeat.yml配置文件中通过filebeat.inputs配置项进行inpu的配置, 配置方式如下:
filebeat.inputs:
- type: log
paths:
- usr/local/src/efk/*.log
如上面配置filebeat的输入类型为log,paths接收多个需采集日志的目录。比如下面的配置,表示从多个目录进行日志采集:
filebeat.inputs:
- type: log
paths:
- usr/local/src/efk/*.log
- usr/local/src/srv/*.log
filebeat也支持多个输入类型,如下配置:
filebeat.inputs:
- type: log
paths:
- usr/local/src/efk/*.log
- usr/local/src/efk/*/*.log
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
如果想对当前目录下以及子目录下所有日志进行采集需要如下配置:
filebeat.inputs:
- type: log
paths:
- usr/local/src/efk/**/*.log
filebeat 将会把 `/**/` 翻译成 8 层的子目录,
假如指定了 /home/data/**/my*.log 那么等同的效果如下:
/home/data/my*.log
/home/data/*/my*.log
/home/data/*/*/my*.log
/home/data/*/*/*/my*.log
/home/data/*/*/*/*/my*.log
/home/data/*/*/*/*/*/my*.log
/home/data/*/*/*/*/*/*/my*.log
/home/data/*/*/*/*/*/*/*/my*.log
/home/data/*/*/*/*/*/*/*/*/my*.log
so,我们最终的配置如下:
filebeat.inputs:
- type: log
paths:
- usr/local/src/efk/**/*.log
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
tips
注意上面input的type有container、docker两个类型, 我第一次见就傻傻分不清楚,不知道使用哪一个type才可以对容器的日志进行采集。
答案是都可以,只是两者处理方式有所不同。
container 是需要我们显示的提供容器的日志文件目录
docker 是通过提供容器本身的反方式给filebeat。
docker类型的input配置如下所示,
## 采集指定的docker容器日志
filebeat.inputs:
- type: docker
containers.ids:
- '8b6fe7dc9e067b58476dc57d6986dd96d7100430c5de3b109a99cd56ac655347'
## 采集所有的docker容器日志
filebeat.inputs:
- type: docker
containers.ids:
- '*'
containers.ids是一个非空配置项,允许提供多个容器ID,也可以通过传入 * 表示所有容器。
docker类型下的其他可选配置(部分关键的配置):
配置项名
| 配置说明 |
containers.path | docker日志所在的基本路径。 默认值是/var/lib/docker/containers |
containers.paths | 容器日志路径列表,如有些docker容器我们人为变更了他们的日志存储地址则需要在此处声明,该参数为一个集合,与上面的containers.path配置同时存在时containers.path配置会被忽略 |
exclude_linesedit | 使用正则表达式过滤不需要采集的日志信息 |
include_linesedit | 使用正则表达式约定需要采集的日志信息 |
harvester
harvester是filebeat在读取配置后对日志实施采集时启动的一个服务,该服务工作范畴就是日志采集。filebeat读取filebeat.yml配置文件后根据inputs启动harvester,harvester对日志文件进行逐行读取,读取的内容会放置缓冲区,后续通过processors执行完毕后推送给输出方。
processors
processors负责对采集的日志进行过滤、和加工。也是通过在filebeat.yml配置文件中预先设定processors的过滤规则,也是得益于processors的存在我才可以不需要引入Logstash。
processors允许加入多个处理器,处理流程如下:
event -> processor 1 -> event1 -> processor 2 -> event2 ...
以下配置示例将删除所有调试消息。
processors:
- drop_event:
when:
regexp:
message: "^DBG:"
output
output为输出,filebeat提供多个输出方式:
Console
Log
ElasticSearch
Redis
Kafka
Logstash
其他不常用的组件
控制台输出配置:
# 控制台输出
output.console:
pretty: true
Log输出配置:
output.file:
path: "/tmp/filebeat"
filename: filebeat
ElasticSearch输出配置:
output.elasticsearch:
hosts: ["https://myEShost:9200"]
这里需要注意的是output不像input可以定义多个,output只能在配置文件定义一次,如果需要对同一日志输出到不同的数据源则引入kafka或redis进行分发。
常见问题
问:filebeat如何处理多行日志(将多行日志合并成一行)
答:使用multiline相关配置项对日志信息进行格式化。假设日志样例数据如下
[2015-08-24 11:49:14,389] [INFO] [MESSAGE]
可以使用下面的配置对日志进行格式化:
multiline.pattern: '^\[[0-9]{4}-[0-9]{2}-[0-9]{2}'
multiline.negate: true
multiline.match: after
需注意!multiline相关配置项需放置filebeat.inputs配置下
如:
filebeat.inputs:
- type: log
paths:
- usr/local/src/efk/**/*.log
multiline.pattern: '^\[[0-9]{4}-[0-9]{2}-[0-9]{2}'
multiline.negate: true
multiline.match: after
测试
目标:在配置为4G内存双核CPU的CentOS7.0版本的Linux操作系统上使用docker部署ElasticSearch + Filebeat + Kibana,将下面日志输出到ElasticSearch并在Kibana上展示出来。
样例日志内容如下:
[2021-04-22 19:26:24.585] [INFO] [http-nio-8100-exec-8-63] [serviceDemo] [1] [api.service.service.impl.CollectServiceImpl,collect] [日志信息={"remark":"这是测试数据"}
过程:
1、编写docker-compose.ym
version: "3"
services:
elasticsearch:
image: "docker.elastic.co/elasticsearch/elasticsearch:7.12.0"
hostname: "elasticsearch"
container_name: "elasticsearch"
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- "discovery.type=single-node"
restart: unless-stopped
privileged: true
ports:
- "9200:9200"
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
- /usr/local/src/efk/elasticsearch/conf/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
networks:
hy-net:
ipv4_address: 172.16.238.111
kibana:
image: "docker.elastic.co/kibana/kibana:7.12.0"
hostname: "kibana"
container_name: "kibana"
restart: unless-stopped
privileged: true
ports:
- "5601:5601"
volumes:
- /usr/local/src/efk/kibana/conf/kibana.yml:/usr/share/kibana/config/kibana.yml
networks:
hy-net:
ipv4_address: 172.16.238.112
filebeat:
image: "docker.elastic.co/beats/filebeat:7.12.0"
hostname: "filebeat"
container_name: "filebeat"
restart: unless-stopped
privileged: true
user: root
volumes:
- /usr/local/src/efk/filebeat/conf/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
- /usr/local/src/efk/filebeat/logs:/usr/share/filebeat/logs
- /var/lib/docker:/var/lib/docker:ro
- /var/run/docker.sock:/var/run/docker.sock
- /usr/local/src/efk/:/usr/local/src/efk/
networks:
hy-net:
ipv4_address: 172.16.238.114
volumes:
elasticsearch_data:
networks:
hy-net:
external:
name: hy-net
需注意!上面的hy-net网络是本人之前已经提前创建好的docker自定义网络。
2、创建filebeat.yml,路径是上面filebeat的数据卷信息 /usr/local/src/efk/filebeat/conf/filebeat.yml
filebeat.inputs:
- type: log
paths:
- /usr/local/src/efk/**/*.log
multiline.pattern: '^\[[0-9]{4}-[0-9]{2}-[0-9]{2}'
multiline.negate: true
multiline.match: after
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
processors:
- add_docker_metadata:
host: "unix:///var/run/docker.sock"
- decode_json_fields:
fields: ["message"]
target: "json"
overwrite_keys: true
output.elasticsearch:
hosts: ["elasticsearch:9200"]
index: "filebeat-%{+yyyy.MM.dd}"
indices:
- index: "filebeat-%{+yyyy.MM.dd}"
setup.template.name: "filebeat-"
setup.template.pattern: "filebeat-*"
setup.dashboards.enabled: true
setup.kibana:
host: "kibana:5601"
3、创建数据卷相关路径以及测试用的日志文件;
4、在docker-compose.yml路径下执行命令
打开kibana查看日志结果如下:
ok,至此已经在目标服务器上使用Docker部署了一套日志平台,接下来修饰下相关字段,调整下日志格式基本上就OK了,当然线上环境还需要增加ElasticSearch的认证配置。