生产环境的来源IP有很多类,各种有CDN和没CDN的,所以日志里面存在下面各种形式获取的IP:
- $http_x_real_ip
- $http_x_forwarded_for
- $remote_addr
不同情况下真实IP的变量不一样,想要通过elk来做日志分析的话,可以使用Painless脚本字段来判断索引的字段内容来新增字段。 先列脚本内容:
if( doc['http_x_real_ip.keyword'].size() > 0 && doc['http_x_real_ip.keyword'].value != null ){
return doc['http_baidu_cdn_real_ip.keyword'].value;
}else if ( doc['http_x_forwarded_for.keyword'].size() > 0 && doc['http_x_forwarded_for.keyword'].value != null ){
return doc['http_x_forwarded_for.keyword'].value;
}else{
return doc['remote_addr.keyword'].value;
}
坑一:
用来判断的字段不存在的时候会报错,比如http_x_real_ip.keyword不存在,那么es会报错,解决方案,先加一层判断:
doc['http_x_real_ip.keyword'].size() > 0
坑二:
logstash传的值,如果事先预配了的话,grok的match不应该如下写:
(?:(%{IPORHOST:http_x_real_ip}|%{DATA:http_x_real_ip}))
这样写的话,用null是匹配不到的,可以手动指定值为'-',如下:
(?:(%{IPORHOST:http_x_real_ip}|-))
更新:
不需要从es上面的脚本字段处理,直接从logstash上面处理即可(由于日志逻辑做了个改变,舍弃了x_forward)
# 设置 real_ip 的值,如果 http_x_real_ip 不为空,则使用它;否则,使用 remote_addr 的值
if [http_x_real_ip] {
mutate {
add_field => { "real_ip" => "%{http_x_real_ip}" }
}
} else {
mutate {
add_field => { "real_ip" => "%{remote_addr}" }
}
}
评论区