全部產品
Search
文件中心

Simple Log Service:解析Nginx日誌

更新時間:Jul 21, 2024

Nginx訪問日誌記錄了使用者訪問的詳細資料,解析Nginx訪問日誌對業務營運具有重要意義。本文介紹如何使用Regex函數或GROK函數解析Nginx訪問日誌。

解析方案簡介

Log Service支援通過資料加工的Regex和GROK解析Nginx日誌,兩種方案對比如下:

  • Regex方案

    對不擅長Regex的分析人員,使用Regex解析日誌時會存在使用難度高、加工效率低、學習成本高和靈活性不足的問題。不推薦優先使用。詳情請參見Regex

  • GROK方案(推薦)

    GROK學習成本低,只需要瞭解不同模式所代表的欄位類型,就可以輕鬆解析日誌內容。從靈活性、高效性、低成本、學習曲線等方面對比,GROK都要比直接使用Regex有優勢。當前SLS資料加工已經提供了四百種模式,建議優先使用GROK模式。詳情請參見GROK模式參考

說明
  • GROK模式的本質是Regex,在有需要的情況下,可以組合使用GROK與Regex。

  • 自訂的Nginx日誌格式,可以通過Regex或GROK方案的調整實現解析。

使用Regex解析Nginx成功訪問日誌

現以一條Nginx成功訪問日誌為例,介紹如何使用Regex解析Nginx成功訪問日誌。

  • 原始日誌

    __source__:  192.168.0.1
    __tag__:__client_ip__:  192.168.254.254
    __tag__:__receive_time__:  1563443076
    content: 192.168.0.2 - - [04/Jan/2019:16:06:38 +0800] "GET http://example.aliyundoc.com/_astats?application=&inf.name=eth0 HTTP/1.1" 200 273932 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.example.com/bot.html)"
  • 解析需求

    • 需求1:從Nginx日誌中提取出codeipdatetimeprotocolrequestsendbytesrefereruseragentverb資訊。

    • 需求2:對request進行再提取,提取出uri_protouri_domainuri_param資訊。

    • 需求3:對解析出來的uri_param進行再提取,提取出uri_pathuri_query資訊。

  • SLS DSL編排

    • 總編排

      """第一步:初步解析Nginx日誌"""
      e_regex("content",r'(?P<ip>\d+\.\d+\.\d+\.\d+)( - - \[)(?P<datetime>[\s\S]+)\] \"(?P<verb>[A-Z]+) (?P<request>[\S]*) (?P<protocol>[\S]+)["] (?P<code>\d+) (?P<sendbytes>\d+) ["](?P<refere>[\S]*)["] ["](?P<useragent>[\S\s]+)["]')
      """第二步:解析第一步得到的request"""
      e_regex('request',r'(?P<uri_proto>(\w+)):\/\/(?P<uri_domain>[a-z0-9.]*[^\/])(?P<uri_param>(.+)$)')
      """第三步:解析第二步得到的uri_param參數"""
      e_regex('uri_param',r'(?P<uri_path>\/\_[a-z]+[^?])\?(?<uri_query>(.+)$)')
    • 細分編排及對應加工結果

      • 針對需求1的加工編排如下。

        e_regex("content",r'(?P<ip>\d+\.\d+\.\d+\.\d+)( - - \[)(?P<datetime>[\s\S]+)\] \"(?P<verb>[A-Z]+) (?P<request>[\S]*) (?P<protocol>[\S]+)["] (?P<code>\d+) (?P<sendbytes>\d+) ["](?P<refere>[\S]*)["] ["](?P<useragent>[\S\s]+)["]')

        對應加工結果:

        __source__:192.168.0.1
        __tag__:__receive_time__:  1563443076
        code:200
        content:192.168.0.2 - - [04/Jan/2019:16:06:38 +0800] "GET http://example.aliyundoc.com/_astats?application=&amp;inf.name=eth0 HTTP/1.1" 200 273932 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.example.com/bot.html)"httpversion:1.1
        datetime:04/Jan/2019:16:06:38 +0800
        ip:192.168.0.2
        protocol:HTTP/1.1
        refere:-
        request:http://example.aliyundoc.com/_astats?application=&amp;inf.name=eth0
        sendbytes:273932
        useragent:Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.example.com/bot.html)
        verb:GET
      • 針對需求2解析request,加工編排如下。

        e_regex('request',r'(?P<uri_proto>(\w+)):\/\/(?P<uri_domain>[a-z0-9.]*[^\/])(?P<uri_param>(.+)$)')

        對應加工結果:

        uri_param: /_astats?application=&inf.name=eth0
        uri_domain: example.aliyundoc.com
        uri_proto: http
      • 針對需求3解析uri_param,加工編排如下。

        e_regex('uri_param',r'(?P<uri_path>\/\_[a-z]+[^?])\?(?<uri_query>(.+)$)')

        對應加工結果:

        uri_path: /_astats
        uri_query: application=&inf.name=eth0
  • 加工結果

    __source__:192.168.0.1
    __tag__:__receive_time__:  1563443076
    code:200
    content:192.168.0.2 - - [04/Jan/2019:16:06:38 +0800] "GET http://example.aliyundoc.com/_astats?application=&amp;inf.name=eth0 HTTP/1.1" 200 273932 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.example.com/bot.html)"httpversion:1.1
    datetime:04/Jan/2019:16:06:38 +0800
    ip:192.168.0.2
    protocol:HTTP/1.1
    refere:-
    request:http://example.aliyundoc.com/_astats?application=&amp;inf.name=eth0
    sendbytes:273932
    uri_domain:example.aliyundoc.com
    uri_proto:http
    uri_param: /_astats?application=&inf.name=eth0
    uri_path: /_astats 
    uri_query: application=&inf.name=eth0
    useragent:Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.example.com/bot.html)
    verb:GET

使用GROK解析Nginx成功訪問日誌

現以一條Nginx成功訪問日誌為例,介紹如何使用GROK解析Nginx成功訪問日誌。

  • 原始日誌

    __source__:  192.168.0.1
    __tag__:__client_ip__:  192.168.254.254
    __tag__:__receive_time__:  1563443076
    content: 192.168.0.2 - - [04/Jan/2019:16:06:38 +0800] "GET http://example.aliyundoc.com/_astats?application=&inf.name=eth0 HTTP/1.1" 200 273932 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.example.com/bot.html)"
  • 解析需求

    • 需求1:從Nginx日誌中提取出clientipbytesagentauthverbrequestident、timestamphttpversionresponsebytesreferrer資訊。

    • 需求2:對解析出來的request進行再提取,提取出uri_protouri_domainuri_param資訊。

    • 需求3:對解析出來的uri_param進行再提取,提取出uri_pathuri_query資訊。

  • SLS DSL編排

    • 總編排

      """第一步:初步解析Nginx日誌"""
      e_regex('content',grok('%{COMBINEDAPACHELOG}'))
      """第二步:解析第一步得到的request"""
      e_regex('request',grok("%{URIPROTO:uri_proto}://(?:%{USER:user}(?::[^@]*)?@)?(?:%{URIHOST:uri_domain})?(?:%{URIPATHPARAM:uri_param})?"))
      """第三步:解析第二步得到的uri_param參數"""
      e_regex('uri_param',grok("%{GREEDYDATA:uri_path}\?%{GREEDYDATA:uri_query}"))

      使用GROK模式解析Nginx正確訪問日誌,只需要COMBINEDAPACHELOG模式即可。

      模式

      規則

      說明

      COMMONAPACHELOG

      %{IPORHOST:clientip} %

      {HTTPDUSER:ident} %

      {USER:auth} \[%

      {HTTPDATE:timestamp}\] "(?:%

      {WORD:verb} %

      {NOTSPACE:request}(?: HTTP/%

      {NUMBER:httpversion})?|%

      {DATA:rawrequest})" %

      {NUMBER:response} (?:%

      {NUMBER:bytes}|-)

      解析出clientipidentauthtimestampverbrequesthttpversionresponsebytes資訊。

      COMBINEDAPACHELOG

      %{COMMONAPACHELOG} %

      {QS:referrer} %{QS:agent}

      解析出上一行中所有欄位,另外還解析出referreragent欄位。

    • 細分編排及對應加工結果

      • 針對需求1解析Nginx日誌的加工編排如下。

        e_regex('content',grok('%{COMBINEDAPACHELOG}'))

        對應加工結果:

        clientip: 192.168.0.1
        __tag__:__receive_time__:  1563443076
        agent:"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.example.com/bot.html)"
        auth:-
        bytes:273932
        clientip:192.168.0.2
        content:192.168.0.2 - - [04/Jan/2019:16:06:38 +0800] "GET http://example.aliyundoc.com/_astats?application=&amp;inf.name=eth0 HTTP/1.1" 200 273932 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.example.com/bot.html)"
        httpversion:1.1
        ident:-
        referrer:"-"
        request:http://example.aliyundoc.com/_astats?application=&amp;inf.name=eth0
        response:200
        timestamp:04/Jan/2019:16:06:38 +0800
        verb:GET
      • 針對需求2解析request,加工編排如下。

        e_regex('request',grok("%{URIPROTO:uri_proto}://(?:%{USER:user}(?::[^@]*)?@)?(?:%{URIHOST:uri_domain})?(?:%{URIPATHPARAM:uri_param})?"))

        對應加工結果:

        uri_proto: http
        uri_domain: example.aliyundoc.com
        uri_param: /_astats?application=&inf.name=eth0

        特別說明,只需要使用GROK的以下數種模式組合即可對request完成解析,如下表所示。

        模式

        規則

        說明

        URIPROTO

        [A-Za-z]+(\+[A-Za-z+]+)?

        匹配uri中的頭部分。例如http://hostname.domain.tld/_astats?application=&inf.name=eth0會匹配到http。

        USER

        [a-zA-Z0-9._-]+

        匹配字母、數字和符號(._-)組合。

        URIHOST

        %{IPORHOST}(?::%

        匹配IPORHOST和POSINT。

        URIPATHPARAM

        %{URIPATH}(?:%{URIPARAM})?

        匹配uri參數部分。

      • 針對需求3解析uri_param,加工編排如下。

        e_regex('uri_param',grok("%{GREEDYDATA:uri_path}\?%{GREEDYDATA:uri_query}"))

        對應加工結果:

        uri_path: /_astats
        uri_query: application=&inf.name=eth0

        使用GROK的以下模式即可完成對uri_param的解析,如下表所示。

        模式

        規則

        說明

        GREEDYDATA

        .*

        匹配任意或多個除分行符號。

  • 加工結果

    __source__:192.168.0.1
    __tag__:__receive_time__:  1563443076
    agent:"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.example.com/bot.html)"
    auth:-
    bytes:273932
    clientip:192.168.0.2
    content:192.168.0.2 - - [04/Jan/2019:16:06:38 +0800] "GET http://example.aliyundoc.com/_astats?application=&amp;inf.name=eth0 HTTP/1.1" 200 273932 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.example.com/bot.html)"
    httpversion:1.1
    ident:-
    referrer:"-"
    request:http://example.aliyundoc.com/_astats?application=&amp;inf.name=eth0
    response:200
    timestamp:04/Jan/2019:16:06:38 +0800
    uri_domain:example.aliyundoc.com
    uri_param:/_astats?application=&amp;inf.name=eth0
    uri_path:/_astats
    uri_proto:http
    uri_query:application=&amp;inf.name=eth0
    verb:GET

使用GROK解析Nginx失敗訪問日誌

以下以一條Nginx失敗訪問日誌為例,介紹如何使用GROK解析Nginx失敗訪問日誌。

  • 原始日誌

    __source__:  192.168.0.1
    __tag__:__client_ip__:  192.168.254.254
    __tag__:__receive_time__:  1563443076
    content: 2019/08/07 16:05:17 [error] 1234#1234: *1234567 attempt to send data on a closed socket: u:111111ddd, c:0000000000000000, ft:0 eof:0, client: 1.2.3.4, server: sls.aliyun.com, request: "GET /favicon.ico HTTP/1.1", host: "sls.aliyun.com", referrer: "https://sls.aliyun.com/question/answer/123.html?from=singlemessage"
  • 解析需求

    content中解析出錯誤訪問日誌hosthttp_versionlog_levelpidreferrer、requestrequest_timeserververb資訊。

  • SLS DSL編排

    e_regex('content',grok('%{DATESTAMP:request_time} \[%{LOGLEVEL:log_level}\] %{POSINT:pid}#%{NUMBER}: %{GREEDYDATA:errormessage}(?:, client: (?<client>%{IP}|%{HOSTNAME}))(?:, server: %{IPORHOST:server})(?:, request: "%{WORD:verb} %{NOTSPACE:request}( HTTP/%{NUMBER:http_version})")(?:, host: "%{HOSTNAME:host}")?(?:, referrer: "%{NOTSPACE:referrer}")?'))
  • 加工結果

    ___source__:  192.168.0.1
    __tag__:__client_ip__:  192.168.254.254
    __tag__:__receive_time__:  1563443076
    content:2019/08/07 16:05:17 [error] 1234#1234: *1234567 attempt to send data on a closed socket: u:111111ddd, c:0000000000000000, ft:0 eof:0, client: 1.2.3.4, server: sls.aliyun.com, request: "GET /favicon.ico HTTP/1.1", host: "sls.aliyun.com", referrer: "https://sls.aliyun.com/question/answer/123.html?
    host: sls.aliyun.com
    http_version: 1.1
    log_level: error
    pid: 1234
    referrer: https://sls.aliyun.com/question/answer/123.html?from=singlemessage
    request: /favicon.ico
    request_time:19/08/07 16:05:17
    server: sls.aliyun.com
    verb: GET