Logstash使用grok過濾nginx日志(二)


  在生產環境中,nginx日志格式往往使用的是自定義的格式,我們需要把logstash中的message結構化后再存儲,方便kibana的搜索和統計,因此需要對message進行解析。

  本文采用grok過濾器,使用match正則表達式解析,根據自己的log_format定制。

1、nginx日志格式

  log_format配置如下:

log_format  main  '$remote_addr - $remote_user [$time_local] $http_host $request_method "$uri" "$query_string" '
                  '$status $body_bytes_sent "$http_referer" $upstream_status $upstream_addr $request_time $upstream_response_time '
                  '"$http_user_agent" "$http_x_forwarded_for"' ;

  對應的日志如下:

1.1.1.1 - - [06/Jun/2016:00:00:01 +0800] www.test.com GET "/api/index" "?cms=0&rnd=1692442321" 200 4 "http://www.test.com/?cp=sfwefsc" 200 192.168.0.122:80 0.004 0.004 "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36" "-"

2、編寫正則表達式

  logstash中默認存在一部分正則讓我們來使用,可以訪問Grok Debugger來查看,可以在 $logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-4.0.0/patterns/ 目錄里面查看。

  基本定義在grok-patterns中,我們可以使用其中的正則,當然並不是所有的都適合nginx字段,這時就需要我們自定義正則,然后通過指定patterns_dir來調用。

  同時在寫正則的時候可以使用Grok Debugger或者Grok Comstructor工具來幫助我們更快的調試。在不知道如何使用logstash中的正則的時候也可使用Grok Debugger的Descover來自動匹配。

  1)nginx標准日志格式

    logstash自帶的grok正則中有Apache的標准日志格式:

COMMONAPACHELOG %{IPORHOST:clientip} %{HTTPDUSER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})" %{NUMBER:response} (?:%{NUMBER:bytes}|-)
COMBINEDAPACHELOG %{COMMONAPACHELOG} %{QS:referrer} %{QS:agent}

    對於nginx標准日志格式,可以發現只是最后多了一個 $http_x_forwarded_for 變量。則nginx標准日志的grok正則定義為:

MAINNGINXLOG %{COMBINEDAPACHELOG} %{QS:x_forwarded_for}

  2)自定義格式

    通過log_format來匹配對應的正則如下:

%{IPV4:remote_addr} - (%{USERNAME:user}|-) \[%{HTTPDATE:log_timestamp}\] (%{HOSTNAME1:http_host}|-) (%{WORD:request_method}|-) \"(%{URIPATH1:uri}|-|)\" \"(%{URIPARM1:param}|-)\" %{STATUS:http_status} (?:%{BASE10NUM:body_bytes_sent}|-) \"(?:%{GREEDYDATA:http_referrer}|-)\" (%{STATUS:upstream_status}|-) (?:%{HOSTPORT1:upstream_addr}|-) (%{BASE16FLOAT:upstream_response_time}|-) (%{STATUS:request_time}|-) \"(%{GREEDYDATA:user_agent}|-)\" \"(%{FORWORD:x_forword_for}|-)\"

    這里面有幾個是我自定義的正則:

URIPARM1 [A-Za-z0-9$.+!*'|(){},~@#%&/=:;^\\_<>`?\-\[\]]*
URIPATH1 (?:/[\\A-Za-z0-9$.+!*'(){},~:;=@#% \[\]_<>^\-&?]*)+
HOSTNAME1 \b(?:[0-9A-Za-z_\-][0-9A-Za-z-_\-]{0,62})(?:\.(?:[0-9A-Za-z_\-][0-9A-Za-z-:\-_]{0,62}))*(\.?|\b)
STATUS ([0-9.]{0,3}[, ]{0,2})+
HOSTPORT1 (%{IPV4}:%{POSINT}[, ]{0,2})+
FORWORD (?:%{IPV4}[,]?[ ]?)+|%{WORD}

  message是每段讀進來的日志,IPORHOST、USERNAME、HTTPDATE等都是patterns/grok-patterns中定義好的正則格式名稱,對照日志進行編寫。

  grok pattren的語法為:%{SYNTAX:semantic},":" 前面是grok-pattrens中定義的變量,后面可以自定義變量的名稱。(?:%{SYNTAX:semantic}|-)這種形式是條件判斷。

  如果有雙引號""或者中括號[],需要加 \ 進行轉義。

  詳解自定義正則:

 URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]<>]* 

 URIPARM1 [A-Za-z0-9$.+!*'|(){},~@#%&/=:;^\\_<>`?\-\[\]]* grok-patterns中正則表達式,可以看到grok-patterns中是以“?”開始的參數,在nginx的 $query_string 中已經把“?”去掉了,所以我們這里不再需要“?”。另外單獨加入日志中出現的  ^ \ _ < > ` 特殊符號 

 URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%&_\-]*)+ 

 URIPATH1 (?:/[\\A-Za-z0-9$.+!*'(){},~:;=@#% \[\]_<>^\-&?]*)+ grok-patterns中正則表達式,grok-patterns中的URIPATH不能匹配帶空格的URI,於是在中間加一個空格。另外還有 \ [ ] < > ^ 特殊符號。

 HOSTNAME \b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\.?|\b) 

 HOSTNAME1 \b(?:[0-9A-Za-z_\-][0-9A-Za-z-_\-]{0,62})(?:\.(?:[0-9A-Za-z_\-][0-9A-Za-z-:\-_]{0,62}))*(\.?|\b) 添加匹配 http_host 中帶有 "-" 的字符。

 HOSTPORT %{IPORHOST}:%{POSINT} 

 HOSTPORT1 (%{IPV4}:%{POSINT}[, ]{0,2})+ 在匹配 upstream_addr 字段時發現,會出現多個IP地址的情況出現,匹配多個IP地址。

 STATUS ([0-9.]{0,3}[, ]{0,2})+ 該字段是當出現多個 upstream_addr 字段時匹配多個 http_status 。

 FORWORD (?:%{IPV4}[,]?[ ]?)+|%{WORD} 當 x_forword_for 字段出現多個IP地址時匹配。

  nginx左右字段都定義完成,可以使用Grok Debugger或者Grok Comstructor工具來測試。添加自定義正則的時候,在Grok Debugger中可以勾選“Add custom patterns”。

  以上日志匹配結果為:

{
  "remote_addr": [
    "1.1.1.1"
  ],
  "user": [
    "-"
  ],
  "log_timestamp": [
    "06/Jun/2016:00:00:01 +0800"
  ],
  "http_host": [
    "www.test.com"
  ],
  "request_method": [
    "GET"
  ],
  "uri": [
    "/api/index"
  ],
  "param": [
    "?cms=0&rnd=1692442321"
  ],
  "http_status": [
    "200"
  ],
  "body_bytes_sent": [
    "4"
  ],
  "http_referrer": [
    "http://www.test.com/?cp=sfwefsc"
  ],
  "port": [
    null
  ],
  "upstream_status": [
    "200"
  ],
  "upstream_addr": [
    "192.168.0.122:80"
  ],
  "upstream_response_time": [
    "0.004"
  ],
  "request_time": [
    "0.004"
  ],
  "user_agent": [
    ""Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36""
  ],
  "client_ip": [
    "2.2.2.2"
  ],
  "x_forword_for": [
    null
  ]
}

3、logstash的配置文件

  創建自定義正則目錄

# mkdir -p /usr/local/logstash/patterns
# vi /usr/local/logstash/patterns/nginx

  然后寫入上面自定義的正則

URIPARM1 [A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]]*
URIPATH1 (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%&_\- ]*)+
URI1 (%{URIPROTO}://)?(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})?
NGINXACCESS %{IPORHOST:remote_addr} - (%{USERNAME:user}|-) \[%{HTTPDATE:log_timestamp}\] %{HOSTNAME:http_host} %{WORD:request_method} \"%{URIPATH1:uri}\" \"%{URIPARM1:param}\" %{BASE10NUM:http_status} (?:%{BASE10NUM:body_bytes_sent}|-) \"(?:%{URI1:http_referrer}|-)\" (%{BASE10NUM:upstream_status}|-) (?:%{HOSTPORT:upstream_addr}|-) (%{BASE16FLOAT:upstream_response_time}|-) (%{BASE16FLOAT:request_time}|-) (?:%{QUOTEDSTRING:user_agent}|-) \"(%{IPV4:client_ip}|-)\" \"(%{WORD:x_forword_for}|-)\"

  logstash.conf配置文件內容

input {
        file {
                path => "/data/nginx/logs/access.log"
                type => "nginx-access"
                start_position => "beginning"
                sincedb_path => "/usr/local/logstash/sincedb"
        }
}
filter {
        if [type] == "nginx-access" {
                grok {
                        patterns_dir => "/usr/local/logstash/patterns"        //設置自定義正則路徑
                        match => {
                                "message" => "%{NGINXACCESS}"
                        }
                }
                date {
                        match => [ "log_timestamp" , "dd/MMM/YYYY:HH:mm:ss Z" ]
                }
         urldecode {
                 all_fields => true
           }
         //把所有字段進行urldecode(顯示中文)
        }
}
output {
        if [type] == "nginx-access" {
                elasticsearch {
                        hosts => ["10.10.10.26:9200"]
                        manage_template => true
                        index => "logstash-nginx-access-%{+YYYY-MM}"
                }
        }

}

 

 

 4、啟動logstash,然后就可以查看日志是否寫入elasticsearch中。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM