ELK-LogStash案例
1、需求解析
1.1、需求解析
对数据进行分析的方式无非就是图和表,所谓表的分析,就是将数据统计后,按照顺序排列起来,比如我们平常所说的TOPn、排名前5客户端IP、排名前5用户访问页面等。如果我们想看看我们的网站在全国各地的
分布热度,表虽然能够在一定程度上分析,但是理解起来不太方面,不能做到一目了然,而图就可以达到对应的效果。
接下来我们就需要实现将我们项目的客户端IP在全国地图展示出来,这个功能我们就需要一个IP数据库来识别客户端IP所在的地理位置。
1.2、IP地址数据库
GeoLite2(https://dev.maxmind.com/geoip/geoip2/geolite2/)是一个解压直接使用的城市IP地理位置数据库,支持IPv4和IPv6两种地址,GeoLite2的免费和收费版本,仅仅是精确度的差别,我们
教学用的就是最新的免费版本。据说每周二都会更新IP地址数据。
GeoIP根据经度和纬度生成 [geoip][location] 格式数据。该字段以GeoJSON格式存储。借助于Elasticsearch模板输出该格式字段添加到Elasticsearch索引的geo_point(GeoJSON格式即geoip),从而为其他应用程序提供GeoJSON的地理区域服务。
1.3、GeoJSON
GeoJSON格式示例:http://geojson.org/geojson-spec.html { "type": "GeometryCollection", "geometries": [ { "type": "Point", "coordinates": [100.0, 0.0] }, { "type": "LineString", "coordinates": [ [101.0, 0.0], [102.0, 1.0] ] } ] }
也就是说: 我们es中存储的数据是是json格式,属性值是单字符串格式,而IP数据库中的解析出来的经纬度也是浮 点型数字,而地图的位置标识以数组格式存在的,所以我们将输入到es之前,还需要对logstash接收的数据 进行定制修改,这就涉及到logstash的filter组件定制数据格式[数据类型(浮点型)+数据组合(数组)]。 es模板示例: https://www.elastic.co/guide/en/logstash/current/plugins-outputselasticsearch.html
1.4、安装插件
logstash-plugin install logstash-filter-geoip logstash-plugin install logstash-filter-mutate logstash-plugin install logstash-filter-useragent logstash对于IP数据库的识别主要靠如下几个插件的功能 # logstash-plugin list --verbose | egrep 'geoip|mutate|useragent' logstash-filter-geoip (7.2.2) logstash-filter-mutate (3.5.2) logstash-filter-useragent (3.3.1)
插件解析: useragent 从数据中获取用户相关属性信息 geoip 根据用户IP信息,获取具体地理位置信息 mutate 对数据进行格式转换
1.5、数据格式
# 定制数据格式 filter { geoip { source => "客户端IP字段名" # 根据用户行为数据获取客户端IP地址 add_field => { "新字段名称" => "属性值" } # 增加扩展字段,主要是数组格式的经纬度数据 } mutate { convert => [ "属性", "数据格式"] # 将普通字符串数据,转换为特点浮点类型 } }
2、实践-IP地址解析所属地域名字
2.1、需求分析
默认情况下,logstash已经加载了三种插件,所以我们可以直接对定制的json格式nginx日志数据进行改造,根据我们对geoip的了解,需要从以下几个方面来考虑: 在geoip使用source来指定客户端IP的获取字段名称,http_x_real_ip|http_x_forwarded_for source => "http_x_real_ip" geoip需要借助于IP数据库文件来进行IP地址与经纬度的对应关系database => "path/to/GeoLite2数据库文件" geoip的经纬度默认保存在:geoip.longitude和geoip.latitude属性中,以字符串的形式单独存在,
我们需要将其改造为一条数组格式的扩展属性,便于在地图上定位IP地理位置。 样式1: add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ] add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}" ]
样式2: add_field => [ "[coordinates]", "%{[geoip][latitude]},%{[geoip][longitude]}" ]
IP地理位置的经纬度数值以浮点形式存在,所以需要进行扩展字段数据类型转换 mutate { convert => [ "[geoip][coordinates]", "float"] }
2.2、准备地址数据库
root@logstash:~# dpkg -L logstash | grep mmdb /usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-filter-geoip-7.2.11-java/vendor/GeoLite2-ASN.mmdb /usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-filter-geoip-7.2.11-java/vendor/GeoLite2-City.mmdb # 当然,我们还可以自己去官方网站去下载最新的ip地址数据库,不过软件安装的基本上就是我们想要的了,复制到指定的目录下 cp /usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-filter-geoip-7.2.11-java/vendor/GeoLite2-City.mmdb /etc/logstash/GeoLite2-City.mmdb
2.3、logstash+filebeat+nginx模拟信息调试
2.3.1、logstash的配置
cat << 'CAT_END' > /etc/logstash/conf.d/my_nginx_geoip.conf input { beats { port => 5044 codec => json } } filter { if [log_type] == "access" { geoip { source => "http_x_real_ip" target => "geoip" database => "/etc/logstash/GeoLite2-City.mmdb" add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ] add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}" ] } mutate { convert => [ "[geoip][coordinates]", "float"] } } } output { stdout { codec => rubydebug } } CAT_END # 属性解析:因为只有access的日志才有http_x_real_ip,所以我们需要结合if语句来获取正常的访问日志
2.3.2、启动logstash
logstash -f my_nginx_geoip.conf
2.3.3、配置filebeat并且启动
cat << 'CAT_END' > /etc/filebeat/my_nginx_json.yml filebeat.inputs: - type: log id: nginx_access_json enabled: true paths: - /var/log/nginx/access_json.log fields: log_type: "access" fields_under_root: true json.keys_under_root: true json.overwrite_keys: true - type: log id: nginx_error enabled: true paths: - /var/log/nginx/error.log fields: log_type: "error" fields_under_root: true setup.template.settings: index.number_of_shards: 5 index.number_of_replicas: 1 output.logstash: hosts: ["192.168.10.28:5044"] CAT_END filebeat -f /etc/filebeat/my_nginx_json.yml
2.3.4、访问nginx
# 中国广东深圳 curl http://192.168.10.30/ -H "X-Forwarded-For: 223.74.107.250" -H "X-Real-IP: 223.74.107.250"
2.3.5、查看logstash输出日志
{ "log_type" => "access", "@version" => "1", "http_x_forwarded_for" => "223.74.107.250", "host" => { "name" => "filebeat" }, ... "tags" => [ [0] "beats_input_raw_event" ], "remote_user" => "-", "geoip" => { "continent_code" => "AS", "country_code3" => "CN", "region_name" => "Guangdong", "latitude" => 22.5333, "location" => { "lon" => 114.1333, "lat" => 22.5333 }, "ip" => "223.74.107.250", "country_name" => "China", "longitude" => 114.1333, "coordinates" => [ [0] 114.1333, [1] 22.5333 ], "country_code2" => "CN", "city_name" => "Shenzhen", "region_code" => "GD", "timezone" => "Asia/Shanghai" }, ... }
结果显示:我们根据IP地址,的确从IP数据库中获取到了地理位置的经纬度,而且在扩展字段coordinates中组合起来了
注意:如果是内网IP的话,会显示如下信息:[0] "_geoip_lookup_failure"、"geoip" => {}
2.4、改造logstash配置
2.4.1、配置logstash
cat << 'CAT_END' > /etc/logstash/conf.d/my_nginx_geoip.conf input { beats { port => 5044 codec => json } } filter { if [log_type] == "access" { geoip { source => "http_x_real_ip" target => "geoip" database => "/etc/logstash/GeoLite2-City.mmdb" add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ] add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}" ] } mutate { convert => [ "[geoip][coordinates]", "float"] } } } output { if [log_type] == "access"{ elasticsearch { hosts => ["192.168.10.25:9200"] index => "logstash-nginx-geo-access-%{+yyyy.MM.dd}" } } if [log_type] == "error"{ elasticsearch { hosts => ["192.168.10.25:9200"] index => "logstash-nginx-error-%{+yyyy.MM.dd}" } } } CAT_END # 注意: # 为了避免在后续kibana中绘图发生如下报错,我需要将索引名称设置为"logstash-*"开头样式 # The index pattern xx does not contain any of the following compatible field types: geo_point
2.4.2、启动服务
systemctl start logstash
2.4.3、检查端口是否开启
root@logstash:~# ss -tunlp | grep 5044 tcp LISTEN 0 4096 *:5044 *:* users:(("java",pid=3293,fd=108))
2.4.4、编写shell脚本访问nginx
ip.txt文件下载:https://files.cnblogs.com/files/ygbh/ip.zip?t=1686206987&download=true
cat << 'CAT_END' > access_nginx_url.sh #!/bin/bash cat ip.txt | while read ip do num=$(echo $ip|cut -d"." -f 4) for i in $(seq ${num}) do curl http://192.168.10.30 -s -I -H "X-Forwarded-For: ${ip}" -H "X-Real-IP: ${ip}" >>/dev/null curl http://192.168.10.25/${num}/ -s >>/dev/null done sleep 1 done CAT_END
2.4.5、查询效果