如何使用混合分隔符(即方括号、空格和双引号)来解析日志( nginx/apache access.log )?并可选择转换为 json

GLK*_*GLK 9 regex apache awk sed nginx

nginx 访问.log。它由 1) 空格 2) [ ] 和 3) 双引号分隔。

::1 - - [12/Oct/2021:15:26:25 +0530] "GET / HTTP/1.1" 200 1717 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"
::1 - - [12/Oct/2021:15:26:25 +0530] "GET /css/custom.css HTTP/1.1" 200 202664 "https://localhost/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"
Run Code Online (Sandbox Code Playgroud)

解析后它应该看起来像

$1 = ::1

$4 = [12/Oct/2021:15:26:25 +0530] or 12/Oct/2021:15:26:25 +0530

$5 = "GET / HTTP/1.1"

$6 = 200

$7 = 1717

$8 = "-"

$9 = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"

我尝试了一些选项,例如awk -F'[],] *' awk -f [][{}] ,但它们不适用于全线。

这里分享的nginx access.log只是一个例子。我试图了解如何混合使用此类分隔符来解析其他复杂日志中的用法。

The*_*ird 7

如果您可以使用gnu-awkFPAT指定列数据:

awk -v FPAT='\\[[^][]*]|"[^"]*"|\\S+' '{
  for(i=1; i<=NF; i++) {
    print "$"i" = ", $i
  }
}' file
Run Code Online (Sandbox Code Playgroud)

模式匹配:

  • \\[[^][]*]使用否定字符类从开头[到结尾进行匹配]
  • |或者
  • "[^"]*"从开始到结束双引号的匹配
  • |或者
  • \\S+1 个或多个非空白字符

输出

$1 =  ::1
$2 =  -
$3 =  -
$4 =  [12/Oct/2021:15:26:25 +0530]
$5 =  "GET / HTTP/1.1"
$6 =  200
$7 =  1717
$8 =  "-"
$9 =  "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"
Run Code Online (Sandbox Code Playgroud)


Rav*_*h13 5

由于这些是 nginx 日志,因此它们的格式将相同(或者有一些设置可以使日志保持相同,谈论当前版本)。我们可以利用此功能,而且我们可以专注于仅获取所需的部分,因此我在这里使用正则表达式来仅获取匹配的值,并保留不需要的值简单。通过遵循这一点,我们不需要对字段编号进行硬编码,使用正则表达式就可以解决这个问题。

这应该适用于任何awk版本。

awk '
{
  while(match($0,/^::[0-9]+|\[?[0-9]{1,2}\/[a-zA-Z]{3}\/[0-9]{4}(:[0-9]{2}){3}\s+\+[0-9]{4}\]?|"[^"]*"|\s[0-9]{3}\s|[0-9]+\s/)){
    val=substr($0,RSTART,RLENGTH)
    gsub(/^[[:space:]]+|[[:space:]]+$/,"",val)
    print val
    $0=substr($0,RSTART+RLENGTH)
  }
}'  Input_file
Run Code Online (Sandbox Code Playgroud)