[英]Regex Issue when log format has multiple ip's
我有一個 fluentTd 日志解析器的問題。 當有 2 個 ip 時,以下配置工作正常。
expression /^(?<client_ip>[^ ]*)(?:, (?<lb_ip>[^ ]*))? (?<ident>[^ ]*) (?<user>[^ ]*) \[(?<time>[^ ]* [^ ]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) (?<protocol>[A-Z]{1,}[^ ]*)+\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)/
這匹配:
148.165.41.129, 10.25.1.120 - - [09/Dec/2019:16:22:23 +0000] "GET /comet_request/44109669162/F1551019433002Y5MYEP?F155101943300742PMLG=1551019433877&_=1575904426457 HTTP/1.1" 200 0 0 0
當有 3 個 ip 時,我收到模式不匹配警告。
這不匹配:
176.30.235.70, 165.225.70.200, 10.25.1.120 - - [09/Dec/2019:13:30:57 +0000] \"GET /comet_request/71142769981/F1551018730440IY5YNF?F1551018721447ZVKYZ4=1551018733078&_=1575898029473 HTTP/1.1\" 200 0 0 0
我嘗試了以下正則表達式,但不起作用。有人可以幫忙嗎?
expression /^(?<client_ip>[^ ]*)(?:, (?<proxy_ip>[^ ]*))? (?:, (?<lb_ip>[^ ]*))? (?<ident>[^ ]*) (?<user>[^ ]*) \[(?<time>[^ ]* [^ ]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) (?<protocol>[A-Z]{1,}[^ ]*)+\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)$/
您需要將 IP 與更具體的模式匹配,例如[\\d.]+
或[^, ]+
,並確保您還匹配最后兩個字段(您不匹配它們並且$
需要行尾/細繩)。
使用像這樣的模式
^(?<client_ip>[^ ,]+)(?:, +(?<proxy_ip>[^ ,]+))?(?:, +(?<lb_ip>[^ ,]+))? (?<ident>[^ ]+) (?<user>[^ ]+) \[(?<time>[^\]\[ ]* [^\]\[ ]*)\] "(?<method>\S+)(?: +(?<path>\S+) (?<protocol>[A-Z][^" ]*)[^"]*)?" (?<code>\S+) (?<size>\S+) \S+ \S+$
查看正則表達式演示
IP匹配部分為^(?<client_ip>[^ ,]+)(?:, +(?<proxy_ip>[^ ,]+))?(?:, +(?<lb_ip>[^ ,]+))?
,看到[^ ,]+
匹配 1+ 個字符而不是空格和,
並且\\S+ \\S+
添加在模式的末尾(如果這些是數字,您可以使用\\d+ \\d+
並在需要時捕獲它們) .
示例字符串
讓我們考慮一下您問題的縮寫版本,重點關注前四個命名范圍(因為處理其余命名范圍很簡單)。
str1 = "148.165.41.129, 10.25.1.120 - - [09/Dec/2019:16:22:23 +0000]"
str2 = "176.30.235.70, 165.225.70.200, 10.25.1.120 - - [09/Dec/2019:13:30:57 +0000]"
以自由間距模式編寫的正則表達式
如果字符串具有有效的結構,則可以使用以下正則表達式來提取命名范圍的內容。 請注意,它要求 IPv4 地址和日期時間字符串具有有效模式(而不僅僅是[^ ]+
和[^ ]+ [^ ]+
)。 我已經以自由間距模式編寫了正則表達式,以使其具有自文檔化功能。
r = /
\A # match the beginning of the string
(?<client_ip> # begin a capture group named client_ip
\g<user_ip> # evaluate the subexpression (capture group) named user_ip
) # end capture group client_ip
(?: # begin a non-capture group
,[ ] # match the string ', '
(?<lb_ip> # begin a capture group named lb_ip
\g<user_ip> # evaluate the subexpression (capture group) named user_ip
) # end capture group lb_ip
)? # end non-capture group and optionally execute it
(?: # begin a non-capture group
,[ ] # match the string ', '
(?<user_ip> # begin a capture group named user_ip
\d{1,3} # match 1-3 digits
(?: # begin a non-capture group
\.\d{1,3} # match a period followed by 1-3 digits
){3} # end the non-capture group and execute 3 times
) # end capture group user_id
) # end non-capture group
[ ]-[ ]-[ ]\[ # match the string ' - - ['
(?<time> # begin a capture group named time
\d{2}\/\p{L}{3}\/\d{4}:\d{2}:\d{2}:\d{2}[ ]\+\d{4}
# match a time string
) # end capture group time
\] # match string ']'
\z # match end of string
/x # free-spacing regex definition mode
將字符串與正則表達式匹配
我們現在確認兩個字符串匹配這個正則表達式並提取捕獲組的內容。
m1 = str1.match(r)
m1.named_captures
#=> {"client_ip"=>"148.165.41.129",
# "lb_ip"=>nil,
# "user_ip"=>"10.25.1.120",
# "time"=>"09/Dec/2019:16:22:23 +0000"}
m2 = str2.match(r)
m2.named_captures
#=> {"client_ip"=>"176.30.235.70",
# "lb_ip"=>"165.225.70.200",
# "user_ip"=>"10.25.1.120",
# "time"=>"09/Dec/2019:13:30:57 +0000"}
子表達式調用
我沒有為前兩個命名捕獲組中的每一個復制捕獲組user_ip
的內容,而是簡單地使用了\\g<user_ip>
,實際上,它告訴正則表達式引擎評估捕獲組(子表達式) user_ip
在引用\\g<user_ip>
的位置。 在Regexp的文檔中搜索“子表達式調用”。
請注意,子表達式調用是前瞻性的。 假設我們改為寫:
r = /
\A
(?<client_ip>\d{1,3}(?:\.\d{1,3}){3})
(?:,[ ](?<lb_ip>\g<client_ip>))?
(?:,[ ](?<user_ip>\g<client_ip>))
[ ]-[ ]-[ ]\[
(?<time>\d{2}\/\p{L}{3}\/\d{4}:\d{2}:\d{2}:\d{2}[ ]\+\d{4})
\]
\z
/x
然后
m1 = str1.match(r)
m1.named_captures
#=> {"client_ip"=>"10.25.1.120",
# "lb_ip"=>nil,
# "user_ip"=>"10.25.1.120",
# "time"=>"09/Dec/2019:16:22:23 +0000"}
m2 = str2.match(r)
m2.named_captures
#=> {"client_ip"=>"10.25.1.120",
# "lb_ip"=>"165.225.70.200",
# "user_ip"=>"10.25.1.120",
# "time"=>"09/Dec/2019:13:30:57 +0000"}
正如所見,捕獲組client_ip
的內容設置為等於user_ip
的內容。 此處解釋了這種行為的原因(查找“在 PCRE 但不是 Perl,一個有趣的轉折是...”以及該文檔的其他參考部分)。
常規編寫的正則表達式
正則表達式通常寫成如下:
/\A(?<client_ip>\g<user_ip>)(?:, (?<lb_ip>\g<user_ip>))?(?:, (?<user_ip>\d{1,3}(?:\.\d{1,3}){3})) - - \[(?<time>\d{2}\/\p{L}{3}\/\d{4}:\d{2}:\d{2}:\d{2} \+\d{4})\]\z/
請注意,當以自由間距模式編寫正則表達式時,上面有空格的字符類包含單個空格。 這是必要的,因為在自由間距模式下,在解析表達式之前會刪除不受保護的空格。 保護空格的另一種方法是將它們轉義 ( \\
)。 如果希望使用空格而不是空格,可以使用\\s
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.