ELK03 Logstash安装插件使用和综合案例 ubuntu使用
logstash一般用来处理数据,不用于采集日志等信息 (除非刚好采集安装的机器本机的日志)
4.1 Logstash 介绍
Logstash 能够从多个来源采集数据,转换数据,然后将数据发 送到您最喜欢的一个或多个“存储库”中 (支持多路输入, 多路输出)
支持各种数据处理插件
Logstash 基于 Java 和 Ruby 语言开发
Logstash 架构: 1.输入 Input:用于日志收集,常见插件: Stdin、File、Kafka、Redis、Filebeat、Http 2.过滤 Filter:日志过滤和转换,常用插件: grok、date、geoip、mutate、useragent 3.输出 Output:将过滤转换过的日志输出, 常见插件: File,Stdout,Elasticsearch,MySQL,Redis,Kafka
4.2.2 包安装 Logstash
包里内嵌了java(所以包会大些)
Logstash 官方下载链接: https://www.elastic.co/cn/downloads/logstash 镜像网站下载链接: https://mirrors.tuna.tsinghua.edu.cn/elasticstack/ [root@ubuntu ~]#wget https://mirrors.tuna.tsinghua.edu.cn/elasticstack/8.x/apt/pool/main/l/logstash/logstash-8.12.2-amd64.deb [root@ubuntu ~]#dpkg -i logstash-8.12.2-amd64.deb #减小内存消耗(自己测试环境快扛不住了) [root@ubuntu ~]#vim /etc/logstash/jvm.options -Xms256m -Xmx256m #如要采集日志要把启动用户改为root,否则其他日志可能无法读取 [root@ubuntu ~]#vim /lib/systemd/system/logstash.service [Service] #User=logstash #Group=logstash #先不启动 [root@logstash ~]#systemctl enable --now logstash.service #未来配置写在子配置文件里(日志加工规则) #查看子配置文件路径:/etc/logstash/conf.d/*.conf [root@logstash ~]#cat /etc/logstash/pipelines.yml - pipeline.id: main path.config: "/etc/logstash/conf.d/*.conf"
docker run --rm -it -v ~/pipeline/:/usr/share/logstash/pipeline/ docker.elastic.co/logstash/logstash:7.17.12
4.3 Logstash 使用
#范例: 查看帮助 [root@logstash ~]#/usr/share/logstash/bin/logstash --help #常用选项 -e 指定配置内容 -f 指定配置文件,支持绝对路径,如果用相对路径,是相对于/usr/share/logstash/的路径 -t 语法检查 -r 修改配置文件后自动加载生效,注意:有时候修改配置还需要重新启动生效 #服务方式启动,由于默认没有配置文件,所以7.X无法启动,8.X可以启动 [root@logstash ~]#systemctl start logstash
各种插件帮助
https://www.elastic.co/guide/en/logstash/current/index.html #有些插件默认安装了,有些需要后期自己安装 #范例: 列出所有插件 [root@logstash ~]#/usr/share/logstash/bin/logstash-plugin list #Github logstash插件链接 https://github.com/logstash-plugins
官方链接
https://www.elastic.co/guide/en/logstash/7.6/input-plugins.html
4.3.2.1 标准输入
#标准输入和输出,codec => rubydebug指输出格式,是默认值,可以省略,也支持设为json,以json格式输出 [root@ubuntu ~]#/usr/share/logstash/bin/logstash -e 'input { stdin{} } output { stdout{}}' [root@ubuntu ~]#/usr/share/logstash/bin/logstash -e 'input { stdin{} } output { stdout{ codec => rubydebug }}' hello,world #输入信息 (输入json依然在message字段中) { "@version" => "1", "@timestamp" => 2024-10-18T05:45:17.311856453Z, "event" => { "original" => "hello,world" }, "message" => "hello,world", "host" => { "hostname" => "ubuntu" } } #通过添加stdin{ codec => "json"} 识别json格式,输入json可以识别出来 [root@ubuntu ~]#/usr/share/logstash/bin/logstash -e 'input { stdin{ codec => "json"} } output { stdout{}}' {"name":"peter","age":44} #输入信息 { "name" => "peter", "@timestamp" => 2024-10-18T06:08:42.817158457Z, "age" => 44, "@version" => "1", "event" => { "original" => "{\"name\":\"peter\",\"age\":44}\n" }, "host" => { "hostname" => "ubuntu" } } #加入标签,type和tags,用于判断数据来源,分类用 [root@ubuntu ~]#/usr/share/logstash/bin/logstash -e 'input { stdin{ tags => "stdin_tag" type => "stdin_type" codec => "json" } } output { stdout{}}' hello #输入信息 { "@timestamp" => 2024-10-18T06:22:47.371264597Z, "type" => "stdin_type", #字符串 "@version" => "1", "message" => "hello", "tags" => [ #数组 [0] "_jsonparsefailure", #开头会自动加一个 [1] "stdin_tag" ], "host" => { "hostname" => "ubuntu" }, "event" => { "original" => "hello\n" } } #启动程序加入软链接,后面就不用写路径了 [root@ubuntu ~]#ln -s /usr/share/logstash/bin/logstash /usr/local/bin/
范例: 以配置文件实现标准输入
#配置文件 [root@logstash ~]#vim /etc/logstash/conf.d/stdin_to_stdout.conf input { stdin { type => "stdin_type" #自定义事件类型,可用于后续判断 tags => "stdin_tag" #自定义事件tag,可用于后续判断 codec => "json" #指定Json 格式 } } output { stdout { codec => "rubydebug" #输出格式,此为默认值,可省略 } } #执行logstash,配置文件路径默认查找/usr/share/logstash/,文件放在此路径下时可省略 [root@logstash ~]#/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/stdin_to_stdout.conf #通过-r执行logstash,选项-r表示动态加载配置(不用停服务,会自动读取变更配置,但有些配置变更无法读取) [root@logstash ~]#/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/stdin_to_stdout.conf -r
Logstash 会记录每个文件的读取位置,下次自动从此位置继续向后读取
每个文件的读取位置记录在下面对应的文件中
#新版:8.11.1 /usr/share/logstash/data/plugins/inputs/file/.sincedb_f5fdf6ea0ea92860c6a6b2b354bfcbbc #旧版 /var/lib/logstash/plugins/inputs/file/.sincedb_xxxx
#配置文件 [root@ubuntu ~]#vim /etc/logstash/conf.d/file_to_stdout.conf input { file { path => "/tmp/wang.*" type => "wanglog" #添加自定义的type字段,可以用于条件判断,和filebeat中tag功能相似 exclude => "*.txt" #排除不采集数据的文件,使用通配符glob匹配语法 start_position => "beginning" #第一次从头开始读取文件,可以取值为:beginning和end,默认为end,即只从最后尾部读取日志(如果文件有旧数据,旧数据也想采集就从头读取)会记录上次采集的位置到一个文件中 stat_interval => "3" #定时检查文件是否更新,默认1s codec => json #如果文件是Json格式,需要指定此项才能解析,如果不是Json格式而添加此行也不会影响结果 } file { path => "/var/log/syslog" type => "syslog" start_position => "beginning" stat_interval => "3" } } output { stdout { codec => "rubydebug" #输出格式,此为默认值,可省略 } } [root@ubuntu ~]#logstash -f /etc/logstash/conf.d/file_to_stdout.conf #测试,这里3秒刷新等待下 [root@ubuntu ~]#echo hello,m56 >> /tmp/wang.log [root@ubuntu ~]#echo '{"name":"lu","age":"18"}' >> /tmp/wang.log #后面是通过systemctl启动的,如要采集日志要把启动用户改为root,否则其他日志可能无法读取 [root@ubuntu ~]#vim /lib/systemd/system/logstash.service [Service] #User=logstash #Group=logstash [root@ubuntu ~]#systemctl daemon-reload
接受通过http发过来的数据
#配置文件 [root@ubuntu ~]#vim /etc/logstash/conf.d/http_to_stdout.conf input { http { port => 6666 #监听端口 codec => json } } output { stdout { codec => rubydebug } } #注意:浏览器会屏蔽6666端口,他认为有安全风险 [root@ubuntu ~]#/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/http_to_stdout.conf #post请求提交数据测试 [root@ubuntu ~]#curl -XPOST -d'test log message' http://10.0.0.155:6666 [root@ubuntu ~]#curl -XPOST -d'{ "name":"wang","age":"18" }' http://10.0.0.155:6666 #这里可以使用Apifox在线发送请求,相当于postman, 也可以安装Insomnia发送请求
4.3.2.4 从 Filebeat 读取数据
#filebeat机器上 #修改filebeat配置 [root@ubuntu ~]#vim /etc/filebeat/filebeat.yml filebeat.inputs: - type: log enabled: true #开启日志 paths: - /var/log/nginx/access_json.log #指定收集的日志文件 json.keys_under_root: true tags: ["nginx-access"] - type: log enabled: true #开启日志 paths: - /var/log/syslog #指定收集的日志文件 fields: logtype: "syslog" #添加自定义字段logtype output.logstash: hosts: ["10.0.0.155:5044"] #指定Logstash服务器的地址和端口 #logstash机器上 [root@ubuntu ~]#vim /etc/logstash/conf.d/filebeat_to_stdout.conf input { beats { port => 5044 } } output { stdout { codec => rubydebug } } [root@ubuntu ~]#/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/filebeat_to_stdout.conf #filebeat机器上 [root@ubuntu ~]#systemctl restart filebeat
4.3.2.5 从 Redis 中读取数据
#范例: [root@logstash ~]#cat /etc/logstash/conf.d/redis_to_stdout.conf input { redis { host => '10.0.0.154' port => "6379" password => "123456" db => "0" data_type => 'list' #可以不写 key => "nginx-accesslog" } } output { stdout { codec => rubydebug } } [root@logstash ~]#/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/redis_to_stdout.conf
4.3.2.6 从 Kafka 中读取数据
#范例: #logstash会读取kafka最新生成的消息数据,原有的消息不会读取 [root@logstash ~]#cat /etc/logstash/conf.d/kakfa_to_stdout.conf input { kafka { bootstrap_servers => "10.0.0.201:9092,10.0.0.202:9092,10.0.0.203:9092" group_id => "logstash" #多个logstash的group_id如果不同,将实现消息共享(发布者/订阅者模式),如果相同(建议使用),则消息独占(生产者/消费者模式) topics => ["nginx-accesslog","nginx-errorlog"] codec => "json" consumer_threads => 8 #开多少个线程,提速 } } output { stdout { codec => rubydebug } } [root@logstash ~]#/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/kakfa_to_stdout.conf
常见的 Filter 插件: 1.利用 Grok 从非结构化数据中转化为结构数据 2.利用 GEOIP 根据 IP 地址找出对应的地理位置坐标 3.利用 useragent 从请求中分析操作系统、设备类型 4.利用 Mutate 从请求中整理字段
把不是json格式的内容转成json格式
#比如下面行: 2016-09-19T18:19:00 [8.8.8.8:prd] DEBUG this is an example log message #使用 Grok 插件可以基于正则表达式技术利用其内置的正则表达式的别名来表示和匹配上面的日志,如下效果 %{TIMESTAMP_ISO8601:timestamp} \[%{IPV4:ip};%{WORD:environment}\] %{LOGLEVEL:log_level} %{GREEDYDATA:message} #最终转换为以下格式 { "timestamp": "2016-09-19T18:19:00", "ip": "8.8.8.8", "environment": "prd", "log_level": "DEBUG", "message": "this is an example log message" } 参考网站 https://www.elastic.co/cn/blog/do-you-grok-grok
范例: 基于Docker 部署 grokdebugger
[root@ubuntu2204 ~]#docker run --name grokdebugger -p 80:80 epurs/grokdebugger
上面方法还是不太方便,可以在kibana中获取
左侧management下点开发工具,会看到Grok Debugger,点击 #范例: Nginx 访问日志 #cat /var/log/nginx/access.log 10.0.0.100 - - [03/Aug/2022:16:34:17 +0800] "GET / HTTP/1.1" 200 612 "-" "curl/7.68.0" 把该内容输入到kibana上的样例数据中 下面Grok模式需要填入: (相当于正则表达式的别名) %{COMBINEDAPACHELOG} 点击模拟出现转化后的json
4.3.3.1.2 范例:使用 grok pattern 将 Nginx 日志格式化为 json 格式
#安装nginx [root@ubuntu ~]#apt update && apt install nginx [root@ubuntu ~]#curl 10.0.0.155 [root@ubuntu ~]#tail /var/log/nginx/access.log 10.0.0.155 - - [18/Oct/2024:13:13:28 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.81.0" [root@logstash ~]#vim /etc/logstash/conf.d/http_grok_stdout.conf input { http { port =>6666 } } filter { #将nginx日志格式化为json格式 grok { match => { "message" => "%{COMBINEDAPACHELOG}" #将message字段转化为指定的Json格式 } } } output { stdout { codec => rubydebug } } [root@logstash ~]#logstash -f /etc/logstash/conf.d/http_grok_stdout.conf #使用curl 或 insomnia 等工具将nginx日志发送http请求至logstash,可以看到下面的输出信息 [root@ubuntu2004 ~]#curl -XPOST -d '10.0.0.155 - - [18/Oct/2024:13:13:28 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.81.0"' http://10.0.0.155:6666/
范例: filebeat采集nginx的访问日志, logstash转化为Json格式
#filebeat机器 [root@ubuntu ~]#vim /etc/filebeat/filebeat.yml filebeat.inputs: - type: log enabled: true #开启日志 paths: - /var/log/nginx/access.log #指定收集的日志文件 json.keys_under_root: true tags: ["nginx-access"] output.logstash: hosts: ["10.0.0.155:5044"] #指定Logstash服务器的地址和端口 #logstash机器 [root@ubuntu ~]#vim /etc/logstash/conf.d/filebeat_grok_stdout.conf input { beats { port => 5044 } } filter { #将nginx日志格式化为json格式 grok { match => { "message" => "%{COMBINEDAPACHELOG}" #将message字段转化为指定的Json格式 } } } output { stdout { codec => rubydebug } } [root@ubuntu ~]#logstash -f /etc/logstash/conf.d/filebeat_grok_stdout.conf #filebeat机器 [root@ubuntu ~]#systemctl restart filebeat
定义客户端ip来源
logstash安装时默认安装了一个数据库, 文件mmdb记录了每个ip地址和城市的对应关系
/usr/share/logstash/vendor/bundle/jruby/3.1.0/gems/logstash-filter-geoip-7.2.13-
java/vendor/GeoLite2-City.mmdb
geoip 根据 ip 地址提供的对应地域信息,比如:经纬度,国家,城市名等,以方便进行地理数据分析
#范例: [root@logstash ~]#vim /etc/logstash/conf.d/http_geoip_stdout.conf input { #beats { #获取filebeat的数据 # port => 5044 #} http { port =>6666 codec => "json" } } filter { #将nginx日志格式化为json格式(如果本身是json格式就不用转了,把grok注释了) grok { match => { "message" => "%{COMBINEDAPACHELOG}" } } #以上面提取clientip字段为源,获取地域信息 geoip { #source => "clientip" #7.X版本指定源IP的所在字段(在clientip字段下) source => "[source][address]" #8.X版本变化,结合grok插件(在source字段下的address字段) target => "geoip" #生成新字段 } } output { stdout { codec => rubydebug } } #启动 [root@logstash ~]#/usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/http_geoip_stdout.conf #使用curl命令或insomnia等发送nginx日志给logstash可以看到下面信息 [root@ubuntu2004 ~]#curl -XPOST -d '23.101.180.204 - - [28/Jun/2021:03:09:01 +0800] "POST //xmlrpc.php HTTP/1.1" 200 412 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36" "-" ' http://10.0.0.155:6666/ #返回 "geoip" => { #多出ip解析内容 "mmdb" => { "dma_code" => 641 }, "geo" => { "country_iso_code" => "US", "city_name" => "San Antonio", "region_iso_code" => "US-TX", "region_name" => "Texas", "timezone" => "America/Chicago", "location" => { "lon" => -98.4927, "lat" => 29.4227 }, "postal_code" => "78288", "country_name" => "United States", "continent_code" => "NA" }, "source" => { #原分析内容 "address" => "23.101.180.204" },
范例: 只显示指定的geoip的字段信息
[root@logstash ~]#vim /etc/logstash/conf.d/http_geoip_field_stdout.conf input { http { port =>6666 } } filter { #将nginx日志格式化为json格式 grok { match => { "message" => "%{COMBINEDAPACHELOG}" } } #以上面提取clientip字段为源,获取地域信息,并指定只保留显示的字段 geoip { #source => "clientip" #7.X版本 source => "[source][address]" #8.X版本变化 target => "geoip" #挑字段来显示 fields => ["continent_code","country_name","city_name","timezone", "longitude","latitude"] } } output { stdout { codec => rubydebug } } [root@logstash ~]#logstash -f /etc/logstash/conf.d/http_geoip_field_stdout.conf
Date插件可以将日志中的指定的日期字符串对应的源字段生成新的目标字段。
然后替换@timestamp 字段(此字段默认为当前写入logstash的时间而非日志本身的时间)或指定的其他字段
match #类型为数组,用于指定需要使用的源字段名和对应的时间格式 target #类型为字符串,用于指定生成的目标字段名,默认是 @timestamp timezone #类型为字符串,用于指定时区域 #范例: 利用源字段timestamp生成新的字段名access_time [root@logstash ~]#vim /etc/logstash/conf.d/http_grok_date_stdout.conf input { http { port =>6666 } } filter { #将nginx日志格式化为json格式 grok { match => { "message" => "%{COMBINEDAPACHELOG}" } } #解析源字段timestamp的date日期格式: 14/Jul/2020:15:07:27 +0800 date { match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ] #要处理的时间戳字段timestamp,当前格式 target => "access_time" #将时间写入新生成的access_time字段,源字段仍保留 #target => "@timestamp" #将时间覆盖原有的@timestamp字段(一般生产中是覆盖) timezone => "Asia/Shanghai" } } output { stdout { codec => rubydebug } } [root@logstash ~]#logstash -f /etc/logstash/conf.d/http_grok_date_stdout.conf #用curl提交日志,可以看到上面输出信息 [root@kibana ~]#curl -XPOST -d '23.101.180.204 - - [28/Jun/2021:03:09:01 +0800] "POST //xmlrpc.php HTTP/1.1" 200 412 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36" "-" ' http://10.0.0.155:6666 #会看到logstash输出 ... "access_time" => 2020-07-14T07:07:27.000Z, #生成新的字段
useragent 插件可以根据请求中的 user-agent 字段,解析出浏览器设备、操作系统等信息, 以方便后续的分析使用
#范例: [root@logstash ~]#vim /etc/logstash/conf.d/http_grok_useragent_stdout.conf input { http { port =>6666 } } filter { #将nginx日志格式化为json格式 grok { match => { "message" => "%{COMBINEDAPACHELOG}" } } #解析date日期如: 10/Dec/2020:10:40:10 +0800 date { match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ] target => "@timestamp" #target => "access_time" timezone => "Asia/Shanghai" } #提取agent字段,进行解析 useragent { #source => "agent" #7,X指定从哪个字段获取数据 source => "message" #8.X指定从哪个字段获取数据(里面包含了所以可以识别) #source => "[user_agent][original]" #8.X指定从哪个字段获取数据,直接分析日志文件,curl或insomnia此方式不成功 #source => "[user_agent][original][1]" #8.X指定从哪个字段获取数据,如果利用insomnia此方式不成功工具发送http请求,需要加[1] target => "useragent" #指定生成新的字典类型的字段的名称,包括os,device等内容 } } output { stdout { codec => rubydebug } } #启动 [root@logstash ~]#logstash -f /etc/logstash/conf.d/http_grok_useragent_stdout.conf #用curl提交日志,可以看到上面输出信息 [root@ubuntu2004 ~]#curl -POST -d'112.13.112.30 - - [05/Jul/2023:19:48:03 +0000] "GET /wp-content/themes/dux/js/libs/ias.min.js?ver=THEME_VERSION HTTP/1.1" 200 1949 "https://www.wangxiaochun.com/" "Mozilla/5.0 (Linux; U; Android 11; zh-CN; Redmi K30 Pro Build/RKQ1.200826.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.108 Quark/5.4.9.201 Mobile Safari/537.36"' http://10.0.0.155:6666 #返回 "useragent" => { "name" => "Chrome Mobile WebView", "version" => "78.0.3904.108", "device" => { "name" => "XiaoMi Redmi K30 Pro" }, "os" => { "name" => "Android", "version" => "11", "full" => "Android 11" } },
Mutate 插件主要是对字段进行、类型转换、删除、替换、更新等操作,可以使用以下函数
remove_field #删除字段 split #字符串切割,相当于awk取列 add_field #添加字段 convert #类型转换,支持的数据类型:integer,integer_eu,float,float_eu, string,boolean gsub #字符串替换 rename #字符串改名 lowercase #转换字符串为小写
4.3.3.5.1 remove_field 删除字段
[root@logstash ~]#vim /etc/logstash/conf.d/http_grok_mutate_remove_field_stdout.conf input { http { port =>6666 } } filter { #将nginx日志格式化为json格式 grok { match => { "message" => "%{COMBINEDAPACHELOG}" } } #解析date日期如: 10/Dec/2020:10:40:10 +0800 date { match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ] target => "@timestamp" #target => "access_time" timezone => "Asia/Shanghai" } #mutate 删除指定字段的操作 mutate { #remove_field => ["headers","message", "agent"] #7.X remove_field => ["timestamp","message", "http"] #8.X } } output { stdout { codec => rubydebug } } [root@logstash ~]#logstash -f /etc/logstash/conf.d/http_grok_mutate_remove_field_stdout.conf
mutate 中的 split 字符串切割,指定字符做为分隔符,切割的结果用于生成新的列表元素
示例: 1000|提交订单|2020-01-08 09:10:21
范例: split 切割字符串取列
[root@logstash ~]#cat /etc/logstash/conf.d/http_grok_mutate_split_stdout.conf input { http { port =>6666 } } filter { #mutate 切割操作 mutate { #字段分隔符 split => { "message" => "|" } #将message字段按 | 分割成名称message列表中多个列表元素 } } output { stdout { codec => rubydebug } } #启动 [root@logstash ~]#logstash -f /etc/logstash/conf.d/http_grok_mutate_split_stdout.conf #用curl提交日志,可以看到上面输出信息 [root@ubuntu2004 ~]#curl -XPOST -d '1000|提交订单|2020-01-08 09:10:21' http://10.0.0.151:6666/
用指定源字段添加新的字段,添加完成后源字段还存在
[root@logstash ~]#cat /etc/logstash/conf.d/http_grok_mutate_add_field_stdout.conf input { http { port =>6666 } } filter { #mutate 切割操作 mutate { #字段分隔符 split => { "message" => "|" } #添加字段,将message的列表的第0个元素添加字段名user_id add_field => { "user_id" => "%{[message][0]}" "action" => "%{[message][1]}" "time" => "%{[message][2]}" } #添加字段做索引名 #add_field => {"[@metadata][target_index]" => "app-%{+YYY.MM.dd}"} #删除无用字段 remove_field => ["headers","message"] } } output { stdout { codec => rubydebug } }
mutate 中的 convert 可以实现数据类型的转换。 支持转换integer、float、string等类型
[root@logstash ~]#cat /etc/logstash/conf.d/http_grok_mutate_convert_stdout.conf input { http { port =>6666 } } filter { #mutate 切割操作 mutate { #字段分隔符 split => { "message" => "|" } #添加字段 add_field => { "user_id" => "%{[message][0]}" "action" => "%{[message][1]}" "time" => "%{[message][2]}" } #删除无用字段 remove_field => ["headers","message"] #对新添加字段进行格式转换 convert => { "user_id" => "integer" "action" => "string" "time" => "string" } #convert => ["excute_time","float] #此格式也可以支持 #convert => ["time","string" ] } } output { stdout { codec => rubydebug } }
5.5.3.5.5 gsub 替换
gsub 实现字符串的替换
filter { mutate { gsub=>["message","\n", " "] #将message字段中的换行替换为空格 } }
Filter 语句块中支持 if 条件判断功能
#vim /etc/filebeat/filebeat.yml filebeat.inputs: - type: log enabled: true paths: - /var/log/nginx/access.log tags: ["access"] - type: log enabled: true paths: - /var/log/nginx/error.log tags: ["error"] - type: log enabled: true paths: - /var/log/syslog tags: ["system"] output.logstash: hosts: ["10.0.0.155:5044"] #loadbalance: true #负载均衡 #worker: 2 #number of hosts * workers #开启多进程 #vim /etc/logstash/conf.d/filebeat_logstash_es.conf input { beats { port => 5044 } } filter { if "access" in [tags][0] { mutate { add_field => { "target_index" => "access-%{+YYYY.MM.dd}"} } } else if "error" in [tags][0] { mutate { add_field => { "target_index" => "error-%{+YYYY.MM.dd}"} } } else if "system" in [tags][0] { mutate { add_field => { "target_index" => "system-%{+YYYY.MM.dd}"} } } } output { elasticsearch { hosts =>["10.0.0.151:9200","10.0.0.152:9200","10.0.0.153:9200"] #一般写data地址 index => "%{[target_index]}" #使用字段target_index值做为索引名 template_overwrite => true #覆盖索引模板 } } #测试,触发nginx日志 [root@ubuntu ~]#curl 10.0.0.154
范例:
#vim /etc/filebeat/filebeat.yml filebeat.inputs: - type: log enabled: true paths: - /var/log/nginx/access.log fields: project: test-access env: test output.logstash: hosts: ["10.0.0.104:5044","10.0.0.105:5044",] #vim /etc/logstash/conf.d/filebeat_logstash_es.conf input { beats { port => 5044 } file { path => "/tmp/wang.log" type => wanglog #自定义的类型,可以用于条件判断 start_position => "beginning" stat_interval => "3" } } output { if [fields][env] == "test" { elasticsearch { hosts =>["10.0.0.101:9200","10.0.0.102:9200","10.0.0.103:9200"] index => "test-nginx-%{+YYYY.MM.dd}" } } if [type] == "wanglog" { stdout { codec => rubydebug } } }
4.3.4 Logstash 输出 Output 插件
4.3.4.1 Stdout 插件
stdout 插件将数据输出到屏幕终端,主要用于调试
4.3.4.2 File 插件
输出到文件,可以将分散在多个文件的数据统一存放到一个文件
示例: 将所有 web 机器的日志收集到一个文件中,从而方便统一管理
[root@ubuntu2204 ~]#cat /etc/logstash/conf.d/stdin_file.conf input { stdin {} } output { #同是打印到屏幕上和输出到文件中 stdout { codec => rubydebug } file { path => "/var/log/test.log" } }
当日志量较小时,可以按月或周生成索引,当日志量比较大时,会按天生成索引,以方便后续按天删除
output { elasticsearch { hosts =>["10.0.0.101:9200","10.0.0.102:9200","10.0.0.103:9200"] #一般写ES中data节点地址 index => "app-%{+YYYY.MM.dd}" #指定索引名称,建议加时间,按天建立索引 #index => "%{[@metadata][target_index]}" #使用字段[@metadata][target_index]值做为索引名 template_overwrite => true #覆盖索引模板,此项可选,默认值为false } }
范例: 将标准输入输出到 elasticsearch
[root@logstash ~]#/usr/share/logstash/bin/logstash -e 'input { stdin{ codec => json } } output { elasticsearch {hosts => ["10.0.0.151:9200"] index => "mytest-%{+YYYY.MM.dd}" }}'
Logstash 支持将日志转发至 Redis
#范例 [root@logstash ~]#cat /etc/logstash/conf.d/file_to_redis.conf input { file { path => "/var/log/nginx/access.log" type => 'nginx-accesslog' start_position => "beginning" stat_interval => "3" codec => json } stdin { } } output { if [type] == 'nginx-accesslog' { redis { host => 'Redis_IP' port => "6379" password => "123456" db => "0" data_type => 'list' key => "nginx-accesslog" } } stdout { codec => rubydebug } }
Logstash 支持将日志转发至 Kafka
#范例: [root@logstash ~]#cat /etc/logstash/conf.d/file_to_kafka.conf input { file { path => "/var/log/nginx/access.log" type => 'nginx-accesslog' start_position => "beginning" stat_interval => "3" codec => json } file { path => "/var/log/nginx/error.log" type => 'nginx-errorlog' start_position => "beginning" stat_interval => "3" } } output { #stdout {} if [type] == 'nginx-accesslog' { kafka { bootstrap_servers => '10.0.0.211:9092,10.0.0.212:9092,10.0.0.213:9092' topic_id => 'nginx-accesslog' codec => 'json' #如果是Json格式,需要标识的字段 } } if [type] == 'nginx-errorlog' { kafka { bootstrap_servers => '10.0.0.211:9092,10.0.0.212:9092,10.0.0.213:9092' topic_id => 'nginx-errorlog' codec => 'json' #为了保留logstash添加的字段,比如:type字段,也需要指定json格式,否则会丢失logstash添加的字段 } } }
实战使用systemctl启动logstash, 之前 logstash -f 配置文件主要用于测试
4.4.2 通过 Logstash 收集多个日志文件并输出至 Elasticsearch
#把文件测试的配置都切走,不然systemctl启动都是生效的 [root@ubuntu ~]#cd /etc/logstash/conf.d/ [root@ubuntu conf.d]#ls [root@ubuntu conf.d]#mkdir bak [root@ubuntu conf.d]#mv *.conf bak/ [root@ubuntu conf.d]#vim syslog-dpkg-to-es.conf input { file { path => "/var/log/syslog" start_position => "beginning" stat_interval => "3" type => "syslog" } file { path => "/var/log/dpkg.log" start_position => "beginning" stat_interval => "3" type => "dpkg" } } output { if [type] == "syslog" { #指定类型不同,写入不同索引 elasticsearch { hosts => ["10.0.0.151:9200"] index => "syslog-%{+YYYY.MM.dd}" } } if [type] == "dpkg" { elasticsearch { hosts => ["10.0.0.151:9200"] index => "dpkg-%{+YYYY.MM.dd}" } } } #启动 [root@ubuntu conf.d]#systemctl start logstash.service
[root@ubuntu ~]#apt install tomcat9 #访问:http://10.0.0.154:8080/ #Tomcat 日志转为 Json 格式 #访问日志转json了 [root@ubuntu ~]#cat /var/log/tomcat9/localhost_access_log.2024-10-20.txt #错误日志(不转json) [root@ubuntu ~]#cat /var/log/tomcat9/catalina.2024-10-20.log #把之前的配置文件移走,否则会生效 [root@ubuntu conf.d]#mv syslog-dpkg-to-es.conf bak [root@ubuntu ~]#vim /etc/systemd/system/logstash.service [Service] ... User=root #修改用户和组为root,让logstash访问日志文件 Group=root [root@ubuntu ~]#vim /etc/logstash/conf.d/tomcat-to-es.conf input { file { path => "/var/log/syslog" start_position => "beginning" stat_interval => "3" type => "syslog" } file { #path => "/apps/tomcat/logs/localhost_access_log.*.txt" #二进制安装 path => "/var/log/tomcat9/localhost_access_log.*.txt" #包安装 start_position => "end" stat_interval => "3" type => "tomcat-accesslog" codec => json } file { path => "/var/log/tomcat9/catalina.*.log" start_position => "end" stat_interval => "3" type => "tomcat-errorlog" codec => json } } output { if [type] == "syslog" { elasticsearch { hosts => ["10.0.0.151:9200"] index => "syslog-0.155-%{+YYYY.MM.dd}" #表示哪个机器上的日志 } } if [type] == "tomcat-accesslog" { elasticsearch { hosts => ["10.0.0.151:9200"] index => "myapp-accesslog-0.155-%{+YYYY.MM.dd}" #logstash-v8.11.1 版本不能使用tomcat-accesslog索引名 #index => "tomcat-accesslog-0.107-%{+YYYY.MM.dd}" #tomcat-accesslog为系统保留关键字 } file { #同时写入文件 path => "/tmp/tomcat-accesslog-0.107.log" } } if [type] == "tomcat-errorlog" { elasticsearch { hosts => ["10.0.0.151:9200"] index => "mytomcat-errorlog-0.155-%{+YYYY.MM.dd}" #logstash-v8.11.1 版本不能使用tomcat-accesslog索引名 #index => "tomcat-accesslog-0.1-%{+YYYY.MM.dd}" } } }
#nginx日志改为json格式(包安装) [root@ubuntu conf.d]#vim /etc/nginx/nginx.conf ... [root@ubuntu conf.d]#nginx -s reload #查看日志 [root@ubuntu conf.d]#cat /var/log/nginx/access_json.log [root@ubuntu conf.d]#vim /etc/filebeat/filebeat.yml filebeat.inputs: - type: log enabled: true paths: - /var/log/nginx/access_json.log tags: ["access"] - type: log enabled: true paths: - /var/log/nginx/error.log tags: ["error"] - type: log enabled: true paths: - /var/log/syslog tags: ["system"] output.logstash: hosts: ["10.0.0.155:5044"] #修改logstash配置 [root@ubuntu ~]#vim /etc/logstash/conf.d/filebeat_es.conf input { beats { port => 5044 } } output { stdout {} #在屏幕打印,可以观察输出是否异常,可以测试做调整 if "access" in [tags][0] { #in表示是否是里面包含的字符串 elasticsearch { hosts => ["10.0.0.151:9200"] #index => "nginx-accesslog-0.107-%{+YYYY.MM.dd}" #8.10.X 索引名不能为包含nginx index => "myapp-accesslog-0.154-%{+YYYY.MM.dd}" #8.10.X 索引名不能为包含nginx开头 } } if "error" in [tags][0] { elasticsearch { hosts => ["10.0.0.151:9200"] #index => "nginx-errorlog-0.107-%{+YYYY.MM.dd}" #8.10.X 索引名不能为包含nginx index => "myapp-errorlog-0.154-%{+YYYY.MM.dd}" #8.10.X 索引名不能为包含nginx } } } #先测试运行 [root@ubuntu ~]#logstash -f /etc/logstash/conf.d/filebeat_es.conf #重启filebeat生效 [root@ubuntu conf.d]#systemctl restart filebeat.service
#日志路径(在filebeat服务机器上) [root@web01 ~]#head /var/log/mall_app.log [INFO] 2018-06-28 08:08:12 [www.mall.com] - DAU|9136|加入收藏|2018-06-28 01:05:02 [INFO] 2018-06-28 08:08:14 [www.mall.com] - DAU|5035|搜索|2018-06-28 01:07:01 [INFO] 2018-06-28 08:08:15 [www.mall.com] - DAU|669|使用优惠券|2018-06-28 08:05:13 [INFO] 2018-06-28 08:08:19 [www.mall.com] - DAU|2564|搜索|2018-06-28 08:07:08 [root@web01 ~]#vim /etc/filebeat/filebeat.yml filebeat.inputs: - type: log enabled: true paths: - /var/log/mall_app.log output.logstash: hosts: ["10.0.0.155:6666"] #logstash把之前的配置挪走(以防干扰,没有就没事) [root@logstash conf.d]#mv filebeat_es.conf bak [root@logstash ~]#vim /etc/logstash/conf.d/app_filebeat_filter_es.conf input { beats { port =>6666 } } filter { #mutate 切割操作 mutate { #字段分隔符 split => { "message" => "|" } #添加字段 add_field => { "user_id" => "%{[message][1]}" "action" => "%{[message][2]}" "time" => "%{[message][3]}" #"[@metadata][target_index]" => "mall-app-%{+YYYY.MM.dd}" } #删除无用字段 remove_field => ["message"] #对新添加字段进行格式转换(本身是字符串的可以不转) convert => { "user_id" => "integer" "action" => "string" "time" => "string" } } date { #覆盖原来的@timestamp时间字段 match => ["time", "yyyy-MM-dd HH:mm:ss"] #把新添加的time进行匹配 target => "@timestamp" timezone => "Asia/Shanghai" } } output { stdout { #打印出来是为了效果,万一有问题可以及时发现 codec => rubydebug } elasticsearch { hosts => ["10.0.0.151:9200","10.0.0.152:9200","10.0.0.153:9200"] index => "mall-app-%{+YYYY.MM.dd}" #index => "[@metadata][target_index]" template_overwrite => true } } #启动,观察结果 [root@logstash ~]#logstash -f /etc/logstash/conf.d/app_filebeat_filter_es.conf -r [root@web01 ~]#systemctl restart filebeat.service #kibana添加数据视图,即可查看
让kibana展示的数据更好看写
kibana左侧分析下面visualize library, 点击创建可视化,点击基于聚合(相当于分组统计) 点击标签云图,点击对应数据源, #对哪个词进行统计 右侧点击存储桶标签,选择词(key),选action.keyword(action关键字),大小选20(表示前20个),点击更新 点击保存,输入标题,新建(保存的是地址,图不固定,会随着数据的变化而变化) 再点击保存,保存仪表盘,起个名字 继续点击左侧分析下面visualize library,点击基于聚合再创建其他图 点击垂直条形图,点击对应数据源, 右侧点击存储桶标签,x轴,聚合选词,选action.keyword,大小选20 点击保存,输入标题,添加到之前的仪表板里 继续点击左侧分析下面visualize library,点击基于聚合再创建其他图 点击饼图,右侧点击存储桶标签,拆分切片,选择词,选action.keyword,大小选20,右面选项可以选显示效果 点击保存,输入标题,添加到之前的仪表板里 左侧分析下仪表板可以看到保存的仪表板 点击右上角共享,点击获取链接,快照就是当前状态,短链就是短url,直接复制链接给别人访问即可 也可以点击嵌入代码,点击复制iFrame代码,然后在html页面贴如代码即可(可以调代码长宽)