• 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 (?:[0-9A-Za-z_-][0-9A-Za-z-_-]{0,62})(?:.(?:[0-9A-Za-z_-][0-9A-Za-z-:-_]{0,62}))*(.?|)
    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 (?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(.?|) 

     HOSTNAME1 (?:[0-9A-Za-z_-][0-9A-Za-z-_-]{0,62})(?:.(?:[0-9A-Za-z_-][0-9A-Za-z-:-_]{0,62}))*(.?|) 添加匹配 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中。

  • 相关阅读:
    【python35小工具】b站弹幕保存
    w7 python35 输出中文乱码解决
    【python】版本35 正则-非库-爬虫-读写xlw文件
    【python小工具】我在bilibili个人资料里控制家里的电脑
    【python小工具】linux 低权限密码记录 提权小套路
    [学习交流]博客园 cnblog 添加github链接和自定义美化学习
    cp2102 驱动 win7x64 -2018
    基于Vue实现可以拖拽的树形表格(原创)
    不起眼的 z-index 却能牵扯出这么大的学问
    彻底搞懂CSS伪类选择器:is、not
  • 原文地址:https://www.cnblogs.com/Orgliny/p/5592186.html
Copyright © 2020-2023  润新知