本文檔介紹如何使用不同方案提取字符串鍵值對。
常用方案比較
字符串動態鍵值對提取分為關鍵字提取、值提取、關鍵字加工和值加工,常用方案為采用e_kv函數、e_kv_delimit函數和e_regex函數等。不同提取場景的三種方案如下:
方案 | 關鍵字提取 | 值提取 | 關鍵字加工 | 值加工 |
e_kv | 使用特定正則表達式 | 支持默認的字符集、特定分隔符或者帶(、)或(")分隔 | 支持前后綴 | 支持文本escape |
e_kv_delimit | 使用特定正則表達式 | 使用分隔符 | 支持前后綴 | 默認無 |
e_regex | 組合自定義正則表達式和默認字符集過濾 | 完全自定義 | 自定義 | 自定義 |
大部分鍵值對的提取使用e_kv
函數并配置特定參數就可以很好地滿足,尤其是帶括字符和反斜杠需要提取并轉義時。其他復雜或高級的場景可以用e_regex
函數來提取。部分特定場景下的鍵值對使用e_kv_delimit
函數會更簡單。
關鍵字提取
處理方法
e_kv
、e_kv_delimit
、e_regex
等函數在應用于關鍵字提取的時候都應遵循字段名提取約束。示例1
以
k1: q=asd&a=1&b=2&__1__=3
日志為例,如果要對該格式的日志作關鍵字和值提取,三種方案如下:e_kv函數
原始日志
k1: q=asd&a=1&b=2&__1__=3
加工規則
#默認以特定字符集提取關鍵字 e_kv("k1")
加工結果
k1: q=asd&a=1&b=2 q: asd a: 1 b: 2
說明沒有提取出關鍵字
__1__
是因為其不符合字段名提取約束。
e_kv_delimit函數
原始日志
k1: q=asd&a=1&b=2&__1__=3
加工規則
# 以&分隔鍵值后,用&分隔提取出關鍵字 e_kv_delimit("k1", pair_sep=r"&")
加工結果
k1: q=asd&a=1&b=2 q: asd a: 1 b: 2
e_regex函數
原始日志
k1: q=asd&a=1&b=2&__1__=3
加工規則
# 自行指定字符集提取關鍵字和值 e_regex("k1",r"(\w+)=([a-zA-Z0-9]+)",{r"\1": r"\2"})
加工結果
k1: q=asd&a=1&b=2 q: asd a: 1 b: 2
示例2
以
content:k1=v1&k2=v2?k3:v3
為例,需要特定正則提取關鍵字,三種方案如下:e_kv函數
原始日志
content:k1=v1&k2=v2?k3:v3
加工規則
e_kv("content",sep="(?:=|:)")
加工結果
content:k1=v1&k2=v2?k3:v3 k1: v1 k2: v2 k3: v3
說明給參數
pair_sep
、kv_sep
或者sep
傳遞字符集的時候,需要使用正則的不捕獲分組,形式如(?:字符集)
。
e_kv_delimit函數
原始日志
content:k1=v1&k2=v2?k3:v3
加工規則
e_kv_delimit("content",pair_sep=r"&?",kv_sep="(?:=|:)")
加工結果
content:k1=v1&k2=v2?k3:v3 k1: v1 k2: v2 k3: v3
e_regex函數
原始日志
content:k1=v1&k2=v2?k3:v3
加工規則
e_regex("content",r"([a-zA-Z0-9]+)[=|:]([a-zA-Z0-9]+)",{r"\1": r"\2"})
加工結果
content:k1=v1&k2=v2?k3:v3 k1: v1 k2: v2 k3: v3
示例3
對以下格式的復雜字符串,使用
e_regex
函數提取更方便。原始日志
content :"ak_id:"LTAiscW,"ak_key:"rsd7r8f
加工規則
如果要提取字符串的關鍵字前有(”)符號,需要使用
e_regex
函數來提取。e_regex("content", r"(\w+):\"(\w+)", {r"\1": r"\2"})
加工結果
經過DSL編排之后的日志格式:
content :"ak_id:"LTAiscW,"ak_key:"rsd7r8f ak_id: LTAiscW ak_key: rsd7r8f
值提取
動態鍵值對之間以及關鍵字與值之間有明確標識,如
a=b
或a="cxxx"
日志格式的,推薦用e_kv
函數,示例如下。原始日志
content1: k="helloworld",the change world, k2="good"
加工規則
這種情況下使用e_kv函數,提取內容不包括
the change world
:e_kv("content1") # e_kv_delimit函數寫法,特別注意k2前有空格,所以e_kv_delimit函數的pair_sep參數需要使用`,\s`才能正常解析,否則解析不出來k2。 e_kv_delimit("content1",kv_sep="=", pair_sep=",\s") # e_regex函數寫法 e_regex("str",r"(\w+)=(\"\w+)",{r"\1": r"\2"})
加工結果
提取后的日志為:
content1: k="helloworld",the change world, k2="good" k1: helloworld k2: good
對帶
"
的日志格式content:k1="v1=1"&k2=v2?k3=v3
,推薦使用e_kv
函數進行提取,例如:原始日志
content:k1="v1=1"&k2=v2?k3=v3
加工規則
e_kv("content",sep="=", quote="'")
加工結果
處理后日志為:
content: k1='v1=1'&k2=v2?k3=v3 k1: v1=1 k2:v2 k3:v3
如果使用
e_kv_delimit
函數提取,規則為e_kv_delimit("ctx", pair_sep=r"&?", kv_sep="=")
,只能解析出k2: v2
和k3: v3
,因為其中第一個提取的鍵值對中關鍵字是k1="v1
,不符合字段名提取約束會被丟棄。分隔符的鍵值對中,值包含特殊字符但沒有用特定字符包括。例如:
原始日志
content: rats eat rice, oil|chicks eat bugs, rice|kittens eat fish, mice|
加工規則(推薦)
使用e_kv_delimit函數比較合適。
e_kv_delimit("content", pair_sep="|", kv_sep=" eat ")
加工結果(推薦)
處理后日志為:
content: rats eat rice, oil|chicks eat bugs, rice|kittens eat fish, mice| kittens: fish, mice chicks: bugs, rice rats: rice, oil
加工規則(不推薦)
使用
e_kv
函數無法解析完整。e_kv("f1", sep="eat")
加工結果(不推薦)
處理后日志為:
content: rats eat rice, oil|chicks eat bugs, rice|kittens eat fish, mice| kittens: fish chicks: bugs rats: rice
關鍵字加工
e_kv
函數和e_kv_delimit
函數都可以通過prefix="", suffix=""
對關鍵字和值進行加工。原始日志
k1: q=asd&a=1&b=2
加工規則
e_kv("k1", sep="=", quote='"', prefix="start_", suffix="_end") e_kv_delimit("k1", pair_sep=r"&", kv_sep="=", prefix="start_", suffix="_end") e_regex("k1",r"(\w+)=([a-zA-Z0-9]+)",{r"start_\1_end": r"\2"})
加工結果
加工后的數據都是關鍵字加工形式,如下:
k1: q=asd&a=1&b=2 start_q_end: asd start_a_end: 1 start_b_end: 2
e_regex
函數對關鍵字加工的能力更強,例如:加工規則
e_regex("k1",r"(\w+)=([a-zA-Z0-9]+)",{r"\1_\1": r"\2"})
加工結果
加工后的數據都是關鍵字加工形式,如下:
k1: q=asd&a=1&b=2 q_q: asd a_a: 1 a_a: 2
值加工
日志格式為
k1:"v1\"abc"
形式, 同時值加工的內容存在有雙引號符號的情形,使用e_kv
函數可正常進行提取,其他兩種方式較難實現。原始日志
""" 這里的\只是普通的符號,不是轉義符 """ content2: k1:"v1\"abc", k2:"v2", k3: "v3"
加工規則1
e_kv("content2",sep=":", quote='"')
使用e_kv函數規則為:
加工結果1
提取后的日志為:
content2: k1:"v1\"abc", k2:"v2", k3: "v3" k1: v1\ k2: v2 k3: v3
加工規則2
e_kv
函數通過參數escape
支持對\
字符轉義。例如:e_kv("content2",sep=":", quote='"',escape=True)
加工結果2
提取后的日志為:
content2: k1:"v1\"abc", k2:"v2", k3: "v3" k1: v1"abc k2: v2 k3: v3
日志格式為
a='k1=k2\';k2=k3'
形式的日志,只有e_kv
函數可以正常提取出,其他兩種比較難以實現。原始日志
data: i=c10 a='k1=k2\';k2=k3'
加工規則1
默認情況下
e_kv
函數的escape=False
,結果為:e_kv("data", quote="'")
加工結果1
提取后的日志為:
a: k1=k2\ i: c10 k2: k3
加工規則2
e_kv
函數通過參數escape
支持對\
字符轉義。例如:e_kv("data", quote="'", escape=True)
加工結果2
提取后的日志為:
data: i=c10 a='k1=k2\';k2=k3' i: c10 a: k1=k2';k2=k3
鍵值的復雜加工。
原始日志
content: rats eat rice|chicks eat bugs|kittens eat fish|
加工規則
使用
e_regex
函數進行加工。e_regex("content", r"\b(\w+) eat ([^\|]+)", {r"\1": r"\2 by \1"})
加工結果
處理后日志為:
content: rats eat rice|chicks eat bugs|kittens eat fish| kittens: fish by kittens chicks: bugs by chicks rats: rice by rats
客戶案例
例如某網站日志中有一個URL數據,針對這條數據有提取需求,按照需求設計加工規則處理日志內容。
第一次加工
需求
需求1:對日志解析出
proto
、domain
、param
等內容。需求2:對
param
中的鍵值對做展開操作。
原始日志
__source__: 192.168.0.100 __tag__:__client_ip__: 192.168.0.200 __tag__:__receive_time__: 1563517113 __topic__: request: https://example.com/video/getlist/s?ver=3.2.3&app_type=supplier&os=Android8.1.0
加工方案
總規則
# 初步處理解析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}")) # 展開kv形式 e_kv("uri_query")
細分規則及對應的加工結果
使用GROK模式對字段
request
進行解析。e_regex('request',grok("%{URIPROTO:uri_proto}://(?:%{USER:user}(?::[^@]*)?@)?(?:%{URIHOST:uri_domain})?(?:%{URIPATHPARAM:uri_param})?"))
對應加工結果:
uri_domain: example.com uri_param: /video/getlist/s?ver=3.2.3&app_type=supplier&os=Android8.1.0 uri_proto: https
使用GROK模式對字段
uri_param
進行解析。e_regex('uri_param',grok("%{GREEDYDATA:uri_path}\?%{GREEDYDATA:uri_query}"))
對應加工結果:
uri_path: /video/getlist/s uri_query: ver=3.2.3&app_type=supplier&os=Android8.1.0
對
uri_param
進行字段提取,具體操作如下:e_kv("uri_query")
對應加工結果:
app_type: supplier os: Android8.1.0 ver: 3.2.3
加工結果
預覽處理后日志:
__source__: 192.168.0.100 __tag__:__client_ip__: 192.168.0.200 __tag__:__receive_time__: 1563517113 __topic__: request: https://example.com/video/getlist/s?ver=3.2.3&app_type=supplier&os=Android8.1.0 uri_domain: example.com uri_path: /video/getlist/s uri_proto: https uri_query: ver=3.2.3&app_type=supplier&os=Android8.1.0 app_type: supplier os: Android8.1.0 ver: 3.2.3
假如只有解析request需求,可以直接對字段
request
使用e_kv函數。例如:e_kv("request")
預覽處理后日志:
__source__: 192.168.0.100 __tag__:__client_ip__: 192.168.0.200 __tag__:__receive_time__: 1563517113 __topic__: request: https://example.com/video/getlist/s?ver=3.2.3&app_type=supplier&os=Android8.1.0 app_type: supplier os: Android8.1.0 ver: 3.2.3
進一步加工
客戶要提取其中動態字段
ver
、app_type
和os
等,加工規則如下。使用正則表達式
e_regex("url", r"\b(\w+)=([^=&]+)", {r"\1": r"\2"})
使用
e_kv_delmit
函數e_kv_delimit("url", pair_sep=r"?&")
方案總結
對于大部分URL函數形式,都可使用以上函數進行解析。但是針對原始日志中的URL形式,使用
e_kv
函數已經足夠,清晰明了而且形式簡單。