说在前面
nginx由于优异的性能表现,被很多系统拿来做前端部署、负载均衡等功能。其中nginx自带的access日志记录的访问日志也是相当值得拿来分析的,本篇文章将对如何使用filebeat采集nginx日志进行介绍,并针对标准日志接入和非标准日志格式接入展开说明,希望对各位读者有所帮助。
常见采集access.log 日志的工具有2个:logstash和filebeat,后者相对来说更加轻量级,对内存更为友好,因此我们此处选择用filebeat来进行演示。access.log作为常规且常用的访问日志文件,filebeat推出后ES官方就专门为nginx做了十分轻便的标准化解决方案,以便开发人员可以用很小的代价来实现日志接入ES。
方案一、filebeat最简化采集nginx
filebeat默认自带nginx module(支持nginx应用access.log日志格式化),但是这个模块默认为非启用状态,需要我们手动启用,下面我们来介绍如何使用
(一)启用nginx mudule
# 启用
./filebeat modules enable nginx
# 如果需要恢复禁用,则执行
./filebeat modules disable nginx
启动nginx模块后,会在$filebeat_home/modules.d 目录下看到原先nginx.yml.disable文件变成了nginx.yml,说明激活成功了
(二)配置filebeat
-
$filebeat_home/modules.d/nginx.yml核心配置
主要配置项有2个:access.enabled开关打开,var.paths路径指定nginx日志文件的路径
- module: nginx
# Access logs
access:
enabled: true
var.paths:
- /usr/local/nginx/logs/access_log.log
# Error logs
error:
enabled: false
#var.paths:
ingress_controller:
enabled: false
在$filebeat_home/nginx.yml文件中已经默认有了如下配置,这样只要我们配置了nginx.yml文件,就可以自动导入到filebeat.yml配置文件中了
filebeat.config.modules:
# Glob pattern for configuration loading
path: ${path.config}/modules.d/*.yml
# Set to true to enable config reloading
reload.enabled: true
# Period on which files under path should be checked for changes
reload.period: 10s
因此,当我们完成nginx.yml文件的配置后,只需要启动filebeat,就可以依赖filebeat自带的nginx模块来实现nginx日志json格式化的解析。
需要注意,这种情况下默认还是用的filebeat-xxx的索引名,虽然开箱即用,但是并不好用,后期维护起来比较麻烦。
方案二、filebeat格式化采集nginx(推荐)
方案二不直接依赖filebeat封装好的nginx模块,而是自己利用filebeat的内置函数,来实现
# 正常配置日志数据源
- type: log
id: demo-nginx
enabled: true
paths:
- /usr/local/nginx/logs/access.log
# 引入标签,方便和其他应用日志源做区分
tags: ["demo-nginx-access"]
定义ES源,并根据tag来创建索引
output.elasticsearch:
# Array of hosts to connect to.
hosts: ["10.10.10.10:9200"]
protocol: "http"
username: "xxxx"
password: "xxxx"
indices:
- index: "demo_nginx_%{+yyyy.MM.dd}"
when.contains:
tags: "demo-nginx-access"
核心逻辑,定义处理器,用来做nginx access日志文本转json的逻辑
这里简单做一下介绍,首先是判断是否包含指定的标签,有的话才走处理器的逻辑,否则就正常输出到ES。
接着我们选择dissect处理器,定义好分词的规则,这里的tokenizer看着复杂,其实就是把nginx目前已有的日志格式放上去而已,nginx会自动根据你定义的占位符去做解析和赋值给占位符的变量。
默认情况下,解析出来的文本可能是text类型,如果我们希望转成数值类型的话,可以在convert属性下单独定义字段类型的转换,其实也不难。剩下的就是一些可选的配置项了
processors:
- if:
has_fields: ["tags"]
and:
- contains:
tags: "demo-nginx-access"
then:
- dissect:
tokenizer: "%{remote_addr} - %{remote_user} [%{time_local}] \"%{request_method} %{request_url} %{request_proto}\" %{status} %{request_length} %{body_bytes_sent} \"%{http_cookie}\" \"%{http_user_agent}\" %{request_time} %{upstream_addr} %{nginx_host} \"%{http_x_forwarded_for}\""
field: "message"
target_prefix: ""
- convert:
fields:
- {from: "status", to: "status", type: "integer"}
- {from: "request_length", to: "request_length", type: "integer"}
- {from: "body_bytes_sent", to: "body_bytes_sent", type: "integer"}
- {from: "request_time", to: "request_time", type: "float"}
ignore_missing: true
ignore_failure: true
- drop_fields:
fields: ["message", "ecs"]
ignore_missing: true
配置完成后,filebeat就会在采集日志后按照要求顺便做处理,我们就可以直接在es上面做采集到的信息做查询了
方案三、nginx日志层面转json再采集
(一)nginx配置json格式日志
从前两种方案我们可以发现,这两种方案核心思想就是把access的文本数据转json后,格式化存储到es中,这样es那边才能实现根据不同的字段来进行筛选等其他处理。还有另外一种方式就是直接将nginx日志输出为json文本,filebeat直接解析json文本,这样filebeat层面就不需要再承接格式转换的工作了。
http {
log_format nginx_json '{"@timestamp":"$time_iso8601",'
'"host":"$server_addr",'
'"clientip":"$remote_addr",'
'"request_length":$request_length,'
'"body_bytes_sent":$body_bytes_sent,'
'"responsetime":$request_time,'
'"status":"$status",'
'"request_method":"$request_method",'
'"uri":"$uri",'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"http_x_forwarded_for":"$http_x_forwarded_for"}';
access_log /var/log/nginx/access.log nginx_json;
}
修改完成后,nginx的输出就已经是json字符串了,我们现在需要做的就是让filebeat采集并按照json格式去解析,不然filebeat默认还是会按照普通文本去处理,最后整串文本都含在message字段里面。
(二)filebeat配置采集
-
/etc/filebeat/filebeat.yml核心配置
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
fields: #类似于标签
index: nginx
json.keys_under_root: true
json.overwrite_keys: true
output.elasticsearch:
hosts: ["10.10.10.10:9200"]
indices: #定义索引名
- index: "elk-nginx-%{+yyyy.MM.dd}"
when.equals: #与那个标签关联
fields:
index: "nginx"
修改完成后,重启/启动filebeat即可完成采集
这种方案确实可行的方案,不过如果依然想要保留原先的日志格式的话,相当于是同时维护两套格式不同的日志文件,对磁盘的压力会有点大,需要按照每个项目的实际情况来考虑。由于笔者不希望直接变更现有运行的日志格式,所以没有直接采用这种方案,但不可否认这个方案落地的可行性挺不错的。
说在最后
按照ES官方的推荐,filebeat主要做采集,logstash主要做数据转换,还有一种模式是filebeat采集日志后,再由logstash处理,最后在存储到ES中,不过就nginx日志采集这件事情来说,个人会觉得链路太长了,成本有点高。
从实际应用出发,笔者个人更加推荐方案二,其次是方案三,因为方案一虽然轻便,但是要求nginx格式不做变更,同一个filebeat实例不支持采集多个不同的数据源,不太适用于实际业务场景,如果只针对大规模的流量统一初略采集,那么为了追求方便方案一还是有可取之处的。
参考文章:
官方文档:https://www.elastic.co/docs/reference/beats/filebeat/filebeat-module-nginx