您可以通過日志服務數據加工函數清洗您所采集的海量日志數據,實現數據格式標準化。本文介紹調用函數清洗數據的常見場景和相關操作。
場景1:過濾日志(e_keep函數和e_drop函數)
您可以使用e_drop函數或e_keep函數過濾日志,也可以使用e_if函數與DROP參數、e_if_else函數與DROP參數過濾日志。
常用規則如下所示:
e_keep(e_search(...) )
:滿足條件時保留,不滿足條件時丟棄。e_drop(e_search(...) )
:滿足條件時丟棄,不滿足條件時保留。e_if_else(e_search("..."), KEEP, DROP)
:滿足條件時保留,不滿足條件時丟棄。e_if(e_search("not ..."), DROP)
:滿足條件時丟棄,不滿足條件時保留。e_if(e_search("..."), KEEP)
:無意義的加工規則。
示例如下所示:
原始日志
#日志1 __source__: 192.168.0.1 __tag__:__client_ip__: 192.168.0.2 __tag__:__receive_time__: 1597214851 __topic__: app class: test_case id: 7992 test_string: <function test1 at 0x1027401e0> #日志2 __source__: 192.168.0.1 class: produce_case id: 7990 test_string: <function test1 at 0x1020401e0>
加工規則
丟棄沒有__topic__字段和__tag__:__receive_time__字段的日志。
e_if(e_not_has("__topic__"),e_drop()) e_if(e_not_has("__tag__:__receive_time__"),e_drop())
加工結果
__source__: 192.168.0.1 __tag__:__client_ip__: 192.168.0.2 __tag__:__receive_time__: 1597214851 __topic__: app class: test_case id: 7992 test_string: <function test1 at 0x1027401e0>
場景2:為日志空缺字段賦值(e_set函數)
您可以使用e_set函數為日志空缺字段賦值。
子場景1:原字段不存在或者為空時,為字段賦值。
e_set("result", "......value......", mode="fill")
mode參數取值請參見字段提取檢查與覆蓋模式。
示例如下所示:
原始日志
name:
加工規則
e_set("name", "aspara2.0", mode="fill")
加工結果
name: aspara2.0
子場景2:使用GROK函數簡化正則表達式,提取字段內容。
示例如下所示:
原始日志
content:"ip address: 192.168.1.1"
加工規則
使用GROK函數捕獲提取content字段中的IP地址。
e_regex("content", grok(r"(%{IP})"),"addr")
加工結果
addr: 192.168.1.1 content:"ip address: 192.168.1.1"
子場景3:為多個字段賦值。
e_set("k1", "v1", "k2", "v2", "k3", "v3", ......)
示例如下所示:
原始日志
__source__: 192.168.0.1 __topic__: __tag__: __receive_time__: id: 7990 test_string: <function test1 at 0x1020401e0>
加工規則
為__topic__字段、__tag__字段和__receive_time__字段賦值。
e_set("__topic__","app", "__tag__","stu","__receive_time__","1597214851")
加工結果
__source__: 192.168.0.1 __topic__: app __tag__: stu __receive_time__: 1597214851 id: 7990 test_string: <function test1 at 0x1020401e0>
場景3:通過判斷,刪除和重命名字段(e_search函數、e_rename函數和e_compose函數)
一般情況下,推薦您使用e_compose函數進行重復判斷和操作。
示例如下所示:
原始日志
content:123 age:23 name:twiss
加工規則
首先判斷content字段值是否為123,如果是,則刪除age和name字段,再將content字段重命名為ctx。
e_if(e_search("content==123"),e_compose(e_drop_fields("age|name"), e_rename("content", "ctx")))
加工結果
ctx: 123
場景4:轉換日志參數類型(v函數、cn_int函數和dt_totimestamp函數)
日志的字段和字段值在加工過程中,始終都是字符串形式,非字符串類型的數據會被自動轉化為字符串類型。因此在調用函數時,要注意各個函數能接收的參數類型。更多信息,請參見語法簡介。
子場景1:調用op_add函數進行字符拼接和數據相加。
op_add函數既可以接收字符串類型,也可以接受數值類型,因此不需要做參數類型轉換。
示例如下所示:
原始日志
a : 1 b : 2
加工規則
e_set("d",op_add(v("a"), v("b"))) e_set("e",op_add(ct_int(v("a")), ct_int(v("b"))))
加工結果
a:1 b:2 d:12 e:3
子場景2:運用字段操作函數和ct_int函數進行類型轉換并調用op_mul函數進行數據相乘。
示例如下所示:
原始日志
a:2 b:5
加工規則
因為v("a")和v("b")都是字符串類型,而op_mul函數的第二個參數只能接收數值類型,所以您需要通過ct_int函數將字符串轉化為整型,再傳遞給op_mul函數。
e_set("c",op_mul(ct_int(v("a")), ct_int(v("b")))) e_set("d",op_mul(v("a"), ct_int(v("b"))))
加工結果
a: 2 b: 5 c: 10 d: 22222
子場景3:調用dt_parse函數和dt_parsetimestamp函數將字符串或日期時間轉換為標準時間。
dt_totimestamp函數接收的參數類型為日期時間對象,不是字符串。因此需要調用dt_parse函數將time1的字符串值類型轉化為日期時間對象類型。您也可以直接使用dt_parsetimestamp函數,它既能接收日期時間對象,也能接收字符串。更多信息,請參見日期時間函數。
示例如下所示:
原始日志
time1: 2020-09-17 9:00:00
加工規則
將time1表示的日期時間轉化為Unix時間戳。
e_set("time1", "2019-06-03 2:41:26") e_set("time2", dt_totimestamp(dt_parse(v("time1")))) 或 e_set("time2", dt_parsetimestamp(v("time1")))
加工結果
time1: 2019-06-03 2:41:26 time2: 1559529686
場景5:為日志不存在的字段填充默認值(default傳參)
部分SLS DSL表達式函數對輸入的參數有一定要求,如果不滿足,數據加工窗口會報錯或返回默認值。當日志中存在必要而殘缺字段時,您可以在op_len函數中填充默認值。
傳遞默認值給后續的函數時可能會進一步報錯,因而需要及時處理函數返回的異常。
原始日志
data_len: 1024
加工規則
e_set("data_len", op_len(v("data", default="")))
加工結果
data: 0 data_len: 0
場景6:判斷日志并增加字段(e_if函數與e_switch函數)
推薦使用e_if函數或e_switch函數進行日志判斷。更多信息,請參見流程控制函數。
e_if函數
e_if(條件1, 操作1, 條件2, 操作2, 條件3, 操作3, ....)
e_switch函數
e_switch函數是條件與操作的配對組合。依次根據條件進行判斷,滿足條件的進行對應操作,然后直接返回操作結果。不滿足條件的不進行對應操作,直接進行下一個條件判斷。如果沒有滿足任一條件并且配置了default參數,則執行default配置的操作并返回。
e_switch(條件1, 操作1, 條件2, 操作2, 條件3, 操作3, ...., default=None)
示例如下所示:
原始日志
status1: 200 status2: 404
e_if函數
加工規則
e_if(e_match("status1", "200"), e_set("status1_info", "normal"), e_match("status2", "404"), e_set("status2_info", "error"))
加工結果
status1: 200 status2: 404 status1_info: normal status2_info: error
e_switch函數
加工規則
e_switch(e_match("status1", "200"), e_set("status1_info", "normal"), e_match("status2", "404"), e_set("status2_info", "error"))
加工結果
只要有一個條件滿足,就返回結果,不再進行后續條件判斷。
status1: 200 status2: 404 status1_info: normal
場景7:數據轉化納秒級的Unix時間戳
部分場景需要日志服務的數據加工能夠滿足納秒級精度時間戳的需求,當原始日志中存在Unix時間格式字段,您可以使用字段操作函數,將其解析成納秒精度的日志時間。
原始日志
{ "__source__": "1.2.3.4", "__time__": 1704983810, "__topic__": "test", "log_time_nano":"1705043680630940602" }
加工規則
e_set( "__time__", op_div_floor(ct_int(v("log_time_nano")), 1000000000), ) e_set( "__time_ns_part__", op_mod(ct_int(v("log_time_nano")), 1000000000), )
加工結果
{ "__source__": "1.2.3.4", "__time__": 1705043680, "__time_ns_part__": 630940602, "__topic__": "test", "log_time_nano":"1705043680630940602" }
場景8:數據轉化微秒級標準 ISO8601 時間戳
部分場景需要日志服務的數據加工滿足高精度時間戳的需求,當原始日志中存在標準 ISO8601時間格式的字段,您可以使用字段操作函數,將其解析成微秒精度的日志時間。
原始日志
{ "__source__": "1.2.3.4", "__time__": 1704983810, "__topic__": "test", "log_time":"2024-01-11 23:10:43.992847200" }
加工規則
e_set( "__time__", dt_parsetimestamp(v("log_time"), tz="Asia/Shanghai"), mode="overwrite", ) e_set("tmp_ms", dt_prop(v("log_time"), "microsecond")) e_set( "__time_ns_part__", op_mul(ct_int(v("tmp_ms")), 1000), )
加工結果
{ "__source__": "1.2.3.4", "__time__": 1704985843, "__time_ns_part__": 992847000, "__topic__": "test", "log_time": "2024-01-11 23:10:43.992847200", "tmp_ms": "992847" }