(ELK/EFK)之Fluentd日誌過濾解析與客戶端IP地址地理位置處理
1 背景與說明
日誌收集我們主要採用 ELK/EFK 方案,具體為什麼採用這種方案本篇不進行更多闡述;本篇主要針對把業務日誌進行解析並相關處理後推送到 Elasticsearch
中更方便進行檢索與資料統計檢視,本篇日誌推送源來自於 Docker
的 Fluentd Log Driver
,非 Docker
環境操作的僅作為參考。
2 目的效果圖
3 主要三樣外掛
3.1 內建 Parser
外掛
這個外掛在最新的 Fluentd
中已經內建了,直接使用即可。參考地址。
3.2 Elasticsearch
外掛
把 Fluentd
收集到的日誌資訊推到 ES
進行儲存,
3.3 地理位置外掛
根據客戶端 IP 地址獲取到更多地理相關的資訊,這樣可以在 kibana
上使用地圖與位置的統計圖方式更直觀檢視資訊,參考地址。
4 開始
4.1 解析日誌資料到對應屬性
4.1.1 日誌原始資料
以下是 Docker
的輸出標準日誌資料格式內容。
2017-03-03T10:46:21+08:00 1806d6c91569 {"log":"2017-03-03 10:46:21 HKT INFO AccessInterceptor:80 - {time=1488509181152, method=POST, action=/nakedhub/adminx/auth/welcome, locale=zh_CN, cost=4, userId=185713, user-agent=null, header-security-token=null, clientIp=139.196.12.22, clientType=null, params={password=111111, username=maomao}, status=200, paramsOfJson=null}" ,"container_id":"1806d6c91569612cdd746651eeb808591e0176befe565820a339294fc2a9ea0d","container_name":"/nhbackend-st.1.d7r1qsa35zwfxtsmyh5np61ft","source":"stdout"}
4.1.2 核心解析格式配置
<filter **>
@type parser
time_format %Y-%m-%d %H:%M:%S %Z
key_name log
suppress_parse_error_log true
reserve_data true
format /.*(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} \w+?).+AccessInterceptor(.+time=(?<requesttime>.+?),)(.+method=(?<method>.+?),)(.+action=(?<action>.+?),)(.*locale=(?<locale>.+?),)(.+cost=(?<cost>.+?),)(.*userId=(?<userId>.*?),)(.*agent=(?<user-agent>.*?),)(.+token=(?<token>.*?),)(.+clientIp=(?<clientIp>.+?),)(.+clientType=(?<clientType>.+?),)(.*params={(?<params>.*?)})(.+status=(?<status>.*?),)(.*Json=(?<paramsOfJson>.*?)})/
types cost:integer,status:integer
</filter>
這裡我採用 Fluentd
中的 filter
對資料進行過濾處理,主要的格式化配置都在 format
這段配置中,主要採用正則表示式拆分資料到自定義的以 <>
包圍起來的屬性中,測試表達式格式可以點開線上格式解析表示式,測試完畢後再把表示式配置就好了;另外值得注意的是 time
這個屬性值,這個值解析器會自動識別為時間型別,會按照 time_format
配置定義的格式轉換至時間型別;key_name
配置在官方文件中並沒有提及(但這個配置是必須的),我得出來的結論是這個配置會把外層 JSON
的 log
內容拿出來後再去做解析;types
則是把自定義的屬性進行型別指定,推送到 Elasticsearch
中也是相應型別(否則通過 kibana
做統計計算的時候由於不是 Number
型別會有問題);reserve_data
配置則表示原始 log
的內容是否保留到輸出項中。
4.1.3 最後日誌輸出項
2017-03-03T10:46:21+08:00 1806d6c91569 {"log":"2017-03-03 10:46:21 HKT INFO AccessInterceptor:80 - {time=1488509181152, method=POST, action=/nakedhub/adminx/auth/welcome, locale=zh_CN, cost=4, userId=185713, user-agent=null, header-security-token=null, clientIp=139.196.12.22, clientType=null, params={password=111111, username=maomao}, status=200, paramsOfJson=null}","container_id":"1806d6c91569612cdd746651eeb808591e0176befe565820a339294fc2a9ea0d","container_name":"/nhbackend-st.1.d7r1qsa35zwfxtsmyh5np61ft","source":"stdout","requesttime":"1488509181152","method":"POST","action":"/nakedhub/adminx/auth/welcome","locale":"zh_CN","cost":4,"userId":"185713","user-agent":"null","token":"null","clientIp":"139.196.12.22","clientType":"null","params":"password=111111, username=maomao","status":200,"paramsOfJson":"null"}
4.2 推送到 ElasticSearch
核心配置
<match>
@type elasticsearch
host 10.47.121.12
port 9200
user elastic
password 123456
scheme http
index_name fluentd
type_name fluentd
logstash_format true
logstash_prefix docker
reload_connections false
</match>
由於我的 ES
安裝了 XPACK
所以我使用了賬號與密碼項配置內容,另外注意 password
這裡不用使用特殊字元,否則會出現 Fluentd
連線 ElasticSearch
的時候字元編碼不對導致認為賬戶與密碼不對的錯誤問題。
4.3 客戶端 IP
地理位置處理
4.3.1 注意
這個 filter
的配置項必須要在以上日誌解析的配置項下面,要先解析到了 clientIp
屬性,我們才能方便配置從而讓外掛獲取客戶端IP地址處理地理位置屬性。
4.3.2 核心配置
<filter **>
type geoip
geoip_lookup_key clientIp
geoip_database /home/fluent/GeoLiteCity.dat
<record>
latitude ${latitude["clientIp"]}
longitude ${longitude["clientIp"]}
country_code3 ${country_code3["clientIp"]}
country ${country_code["clientIp"]}
country_name ${country_name["clientIp"]}
dma ${dma_code["clientIp"]}
area ${area_code["clientIp"]}
region ${region["clientIp"]}
city ${city["clientIp"]}
location '[${longitude["clientIp"]},${latitude["clientIp"]}]'
</record>
skip_adding_null_record true
log_level info
flush_interval 1s
</filter>
GeoLiteCity.dat
參考GITHUB專案地址去下載,location
會自動轉換為 geo_point
型別。
4.3.3 Kibana
型別 geo_point
問題
No Compatible Fields: The "xxx" index pattern does not contain any of the following field types: geo_point
當 location
屬性值已經存在ES中了就算配置後依然無法自動轉成 geo_point
型別,我們需要手動進行處理了,先刪除相關的所以索引,然後手動建立型別模板定義 location
的型別,然後建立測試索引檢視。
4.3.3.1 建立模板型別
開啟 Shell
控制檯建立檔案 json
,檔案內容為以下。
{
"template": "docker-*",
"mappings": {
"_default_": {
"properties" : {
"location": { "type": "geo_point"}
}
}
}
}
curl -u elastic:123456 -XPUT 'http://10.47.121.12:9200/_template/docker' -d @json
4.3.3.2 建立測試索引
curl -u elastic:123456 -XPUT 'http://10.47.121.12:9200/docker-test/fluentd/2' -d '{"host":"8.8.8.8","location":[1.23,4.56]}'
4.3.3.3 檢視索引屬性型別
curl -u elastic:123456 -XGET http://10.47.121.12:9200/docker-test/fluentd/_mapping?pretty
4.3.3.4 原始問題參考地址
4.3.4 最後日誌輸出內容
2017-03-03T10:46:21+08:00 1806d6c91569 {"log":"2017-03-03 10:46:21 HKT INFO AccessInterceptor:80 - {time=1488509181152, method=POST, action=/nakedhub/adminx/auth/welcome, locale=zh_CN, cost=4, userId=185713, user-agent=null, header-security-token=null, clientIp=139.196.12.22, clientType=null, params={password=111111, username=maomao}, status=200, paramsOfJson=null}","container_id":"1806d6c91569612cdd746651eeb808591e0176befe565820a339294fc2a9ea0d","container_name":"/nhbackend-st.1.d7r1qsa35zwfxtsmyh5np61ft","source":"stdout","requesttime":"1488509181152","method":"POST","action":"/nakedhub/adminx/auth/welcome","locale":"zh_CN","cost":4,"userId":"185713","user-agent":"null","token":"null","clientIp":"139.196.12.22","clientType":"null","params":"password=111111, username=maomao","status":200,"paramsOfJson":"null","latitude":30.29360008239746,"longitude":120.1613998413086,"country_code3":"CHN","country":"CN","country_name":"China","dma":null,"area":null,"region":"02","city":"Hangzhou","location":[120.1613998413086,30.29360008239746]}
5 最後
本篇相關的內容到這裡就結束了,有什麼問題的話給我留言,我會盡量回復,如果有不正確的地方還望不吝賜教,我會作出相應的改進,避免誤導更多人,謝謝。