logstash報錯現象
Trouble parsing json {:source=>"message", :raw=>"{\"@timestamp\":\"2016-05-30T14:51:27+08:00\",\"host\":\"10.139.48.166\",\"clientip\":\"180.109.110.203\",\"request_method\":\"GET\",\"size\":4286,\"responsetime\":0.000,\"upstreamtime\":\"-\",\"upstreamhost\":\"-\",\"http_host\":\"www.xxxx.com\",\"url\":\"/favicon.ico\",\"complete_url\":\"http://www.xxxx.com/favicon.ico\",\"referer\":\"-\",\"agent\":\"\\xE7\\x99\\xBE\\xE5\\xBA\\xA6HD 4.4.1 rv:4.4.1.2 (iPad; iPhone OS 8.3; zh_CN)\",\"status\":\"200\"}", :exception=>#<LogStash::Json::ParserError: Unrecognized character escape 'x' (code 120)報錯信息說明:Unrecognized character escape 'x'
意思:無法識別的字符轉義 'x'
搜索這條信息:\"agent\":\"\\xE7\\x99\\xBE\\xE5\\xBA\\x
發現是URL鏈接包含中文後,json的時候對於字符串\\xE7,把x當做需要轉義的字符,問題是,\\不是雙重轉義麼,奇怪!
問題解決過程
交代環境
centos 6.7
logstash 1.5
nginx日誌數據定義
log_format json '{"@timestamp":"$time_iso8601",'
'"host":"$server_addr",'
'"clientip":"$remote_addr",'
'"request_method":"$request_method",'
'"size":$body_bytes_sent,'
'"responsetime":$request_time,'
'"upstreamtime":"$upstream_response_time",'
'"upstreamhost":"$upstream_addr",'
'"http_host":"$host",'
'"url":"$uri",'
'"complete_url":"$scheme://$host$request_uri",'
'"referer":"$http_referer",'
'"agent":"$http_user_agent",'
'"status":"$status"}';
logstash定義
input {
syslog {
port => "12210"
}
}
filter {
json {
source => "message"
}
geoip {
source => "clientip"
}
}
output{
elasticsearch { host => "127.0.0.1"
index => "nginx-logs-%{+YYYY.MM.dd}"
index_type => "logs"
}
}
解決無法識別的字符轉義 'x'方法
使用mutte對\\x字符串進行替換,在json化之前
抽取logstash配置文件中filter片段
filter {
mutate {
gsub => ["message", "\\x", "\\\x"]
}
json {
source => "message"
}
geoip {
source => "clientip"
}
}
解釋
gsub => ["message", "\\x", "\\\x"]
將message字段中,"\\x"字符串替換爲"\\\x"
結果展示
logstash不再輸出錯誤信息,complete_url展示的url鏈接中中文正常,url沒有解析出來
分析爲使用mutte處理前相同url日誌
Trouble parsing json {:source=>"message", :raw=>"{\"@timestamp\":\"2016-05-30T18:21:35+08:00\",\"host\":\"10.139.48.166\",\"clientip\":\"58.250.164.208\",\"request_method\":\"GET\",\"size\":1338,\"responsetime\":0.008,\"upstreamtime\":\"0.008\",\"upstreamhost\":\"10.139.39.45:8801\",\"http_host\":\"www.qhfax.com\",\"url\":\"/aaa/\\xE6\\x88\\x91\\xE6\\x98\\xAF\\xE4\\xB8\\x80\\xE4\\xB8\\xAA\\xE4\\xBA\\xBA\",\"complete_url\":\"https://www.qhfax.com/aaa/%E6%88%91%E6%98%AF%E4%B8%80%E4%B8%AA%E4%BA%BA\",\"referer\":\"-\",\"agent\":\"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36\",\"status\":\"404\"}", :exception=>#<LogStash::Json::ParserError: Unrecognized character escape 'x' (code 120)
發現:
\"complete_url\":\"https://www.qhfax.com/aaa/%E6%88%91%E6%98%AF%E4%B8%80%E4%B8%AA%E4%BA%BA\"
\"url\":\"/aaa/\\xE6\\x88\\x91\\xE6\\x98\\xAF\\xE4\\xB8\\x80\\xE4\\xB8\\xAA\\xE4\\xBA\\xBA\"
居然兩條語句輸出的結果都是不一致
分析nginx配置片段
'"url":"$uri",'
'"complete_url":"$scheme://$host$request_uri",'
解釋:
$uri請求中的當前URI(不帶請求參數,參數位於$args),不同於瀏覽器傳遞的$request_uri的值,它可以通過內部重定向,或者使用index指令進行修改。不包括協議和主機名,例如/foo/bar.html
$request_uri 這個變量等於包含一些客戶端請求參數的原始URI,它無法修改,請查看$uri更改或重寫URI。
也就是說:$request_uri是原始請求URL,$uri則是經過nginx處理請求後剔除參數的URL,所以會將漢字表現爲union。
坑點:
使用$uri 可以在nginx對URL進行更改或重寫,但是用於日誌輸出可以使用$request_uri代替,如無特殊業務需求,完全可以替換