日志服务数据加工最佳实践: 字符串动态键值对的提取

本文涉及的产品
对象存储 OSS,20GB 3个月
日志服务 SLS,月写入数据量 50GB 1个月
对象存储 OSS,内容安全 1000次 1年
简介: 日志服务数据加工最佳实践: 字符串动态键值对的提取, 详细讲解e_kv, e_kv_delimit与e_regex在各种场景下的用法与推荐.


本实践案例主要是从字符串专题进行展开,将从多方面讲解如何使用不同方案字符串,来解决用户需求。

一个快速案例: 解析URL中参数键值对

以下是一个url的数据,本文将会使用两种方案来展开这条日志内容:

request:  https://yz.m.sm.cn/s?ver=3.2.3&app_type=supplier&os=Android8.1.0

需求

1、对以上日志进行解析出proto, domain, param等内容
2、对param中的键值对值做展开操作

原始日志

比如在控制台上收集到的日志为:

__source__:  10.43.112.168
__tag__:__client_ip__:  12.120.75.130
__tag__:__receive_time__:  1563517113
__topic__:  
request:  https://yz.m.sm.cn/video/getlist/s?ver=3.2.3&app_type=supplier&os=Android8.1.0

LOG DSL编排

Grok模式+KV方式

1、首先是使用grok模式对字段request内容进行解析(也可使用正则,参考grok函数grok模式参考

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

预览处理日志:

uri_domain:  yz.m.sm.cn
uri_param:  /video/getlist/s?ver=3.2.3&app_type=supplier&os=Android8.1.0
uri_proto:  https

2、其次在使用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

3、第三步具体操作如下:

e_kv("uri_query")

预览处理后日志:

app_type:  supplier
os:  Android8.1.0
ver:  3.2.3

4、综上,LOG DSL规则可以如一下形式

# 初步处理解析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")

预览处理后日志:

__source__:  10.43.112.168
__tag__:__client_ip__:  12.120.75.130
__tag__:__receive_time__:  1563517113
__topic__:  
request:  https://yz.m.sm.cn/video/getlist/s?ver=3.2.3&app_type=supplier&os=Android8.1.0
uri_domain:  yz.m.sm.cn
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使用e_kv函数,就能展开kv数据(具体参考e_kv函数)。如下:

e_kv("request")

预览处理后日志:

__source__:  10.43.112.168
__tag__:__client_ip__:  12.120.75.130
__tag__:__receive_time__:  1563517113
__topic__:  
request:  https://yz.m.sm.cn/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

其他方案

都是以url: https://yz.m.sm.cn/video/getlist/s?ver=3.2.3&app_type=supplier&os=Android8.1.0为例, 如果要提取其中动态字段ver, app_typeos等, 其实还有多种方案, 如下:

使用正则

e_regex("url", r"\b(\w+)=([^=&]+)", {r"\1": r"\2"})

使用e_kv_delmit函数

e_kv_delimit("url", pair_sep=r"?&")

综上可知,对于大部分url函数形式,都可使用以上几种方式进行展开。但是针对以上url形式,其实使用e_kv函数已经足够,清晰明了,而且形式简单。

方案比较

方案 关键字提取 值提取 关键字加工 值加工
e_kv 使用特定正则 支持默认的字符集+特定分隔符或者带"分隔 支持前后缀 支持文本escape
e_kv_delimit 使用特定正则 通过分隔符 支持前后缀 默认没有
e_regex 自定义正则+默认字符集过滤 完全自定义 自由(例如重复, 中间加, 或者把value也放入key的都支持) 自由(如左)

关键字提取

e_kv、e_kv_delimit,e_regex在使用的关键字提取的时候都遵循字段名提取值约束,以下两个示例都可以使用这三种方法进行提取:

1、案例1

k1: q=asd&a=1&b=2&__1__=3为例,如果要对以上日志格式做关键字和值提取的话,三种方案如下

# 默认以特定字符集提取关键字
e_kv("k1")

# 以&分隔键值后, 用&分隔提取出关键字
e_kv_delimit("k1", pair_sep=r"&")

# 自行指定字符集提取关键字和值
e_regex("k1",r"(\w+)=([a-zA-Z0-9]+)",{r"\1": r"\2"})

经过以上DSL编排过后的日志格式为:

k1: q=asd&a=1&b=2
q: asd
a: 1
b: 2

注意到, 并没有提取出关键字__1__因为其不符合字段名提取值约束.

2、案例2
content:k1=v1&k2=v2?k3:v3为例, 有点特殊需要特定正则提取关键字,三种方案如下:

e_kv("content",sep="(?:=|:)")
e_kv_delimit("content",pair_sep=r"&?",kv_sep="(?:=|:)")
e_regex("content",r"([a-zA-Z0-9]+)[=|:]([a-zA-Z0-9]+)",{r"\1": r"\2"})

注意: 给参数pari_sepkv_sep或者sep传递字符集的时候, 需要使用正则的不捕获分组, 形式如(?:字符集)

经过DSL编排之后的日志格式是:

content:k1=v1&k2=v2?k3:v3
k1: v1
k2: v2
k3: v3

3、案例3
以下格式的字符串比较复杂,使用e_regex提取更方便。

content :"ak_id:"LTAiscW,"ak_key:"rsd7r8f

如果要提取的字符串的关键字前有"需要使用e_regex来提取。

e_regex("str",r'(\w+):(\"\w+)',{r"\1":r"\2"})

经过DSL编排语法后,日志为:

content :"ak_id:"LTAiscW,"ak_key:"rsd7r8f
ak_id: LTAiscW
ak_key: rsd7r8f

值提取

动态键值对之间以及关键字与值之间有明确标识如:

1、日志格式为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

但是对于不同的场景,以上三种有不同的合适使用场景。比如:

2、而以下形式的带"的日志格式content:k1="v1=1"&k2=v2?k3=v3,如果使用e_kv函数提取会比较容易,如下:

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,不符合关键字的规范会被丢弃。

3、比如以下分隔符的键值对中值包含了特殊字符但没有用特定字符括起来的时候,适合e_kv_delimit函数的数据形式. 例如:

content:  老鼠吃大米,油|小鸡吃虫子,稻子|小猫吃鱼,老鼠|

此时使用e_kv_delimit函数比较合适。

e_kv_delimit("content", pair_sep="|", kv_sep="吃")

处理后日志为

content:  老鼠吃大米,油|小鸡吃虫子,稻子|小猫吃鱼,老鼠|
小猫:  鱼,老鼠
小鸡:  虫子,稻子
老鼠:  大米,油

而使用e_kv解析会无法解析完整

e_kv("f1", sep="吃")

处理后日志为

content:  老鼠吃大米,油|小鸡吃虫子,稻子|小猫吃鱼,老鼠|
小猫:  鱼
小鸡:  虫子
老鼠:  大米

关键字加工

1、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

值加工

1、日志格式为k1:"v1\"abc",值内容有双引号的情况,只有e_kv可以正常提取出,并且使用escape参数。其他两种比较难实现

"""
这里的\只是普通的符号,不是转义符
"""
content2:  k1:"v1\"abc", k2:"v2", k3: "v3"

使用e_kv规则为:

e_kv("content2",sep=":", quote='"')

提取后的日志为:

content2:  k1:"v1\"abc", k2:"v2", k3: "v3"
k1: v1\
k2: v2
k3: v3

e_kv提供对于\字符的转义支持, 通过参数escape打开, 如下:

e_kv("content2",sep=":", quote='"',escape=True)

提取后的日志为:

content2:  k1:"v1\"abc", k2:"v2", k3: "v3"
k1: v1"abc
k2: v2
k3: v3

2、日志格式为a='k1=k2\';k2=k3'特殊形式的日志,只有e_kv正常提取出,其他两种比较难以实现

data: i=c10 a='k1=k2\';k2=k3'

默认情况下e_kv函数的escape=False,结果为:

e_kv("data", quote="'")

提取后的日志为:

a:  k1=k2\
i:  c10
k2:  k3

e_kv提供对于\字符的转义支持, 通过参数escape打开, 如下:

e_kv("data", quote="'", escape=True) 

提取后的日志为:

data: i=c10 a='k1=k2\';k2=k3'
i: c10
a: k1=k2';k2=k3

综上,对于e_regex,e_kv_delimit函数,提取出以上形式的日志格式比较困难。值加工推荐使用e_kv函数。

4、键值的复杂加工

content:  老鼠吃大米|小鸡吃虫子|小猫吃鱼|
e_regex("content", r"\b([\u4e00-\u9fa5\u0800-\u4e00\w]+)吃([^\|]+)", {r"\1": r"\2被\1吃"})

处理后日志为

content:  老鼠吃大米|小鸡吃虫子|小猫吃鱼|
小猫:  鱼被小猫吃
小鸡:  虫子被小鸡吃
老鼠:  大米被老鼠吃

结论

大部分键值对的提取使用e_kv并配置特定参数就可以很好满足, 尤其是带括字符和反斜杠需要提取并转义时. 其他复杂或高级的场景时, 可以用e_regex来提取. 某些特定场景下的键值对, 使用e_kv_delemit会跟简单.

进一步参考

欢迎扫码加入官方钉钉群获得实时更新与阿里云工程师的及时直接的支持:
image

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
1月前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
142 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
2月前
|
XML JSON 监控
告别简陋:Java日志系统的最佳实践
【10月更文挑战第19天】 在Java开发中,`System.out.println()` 是最基本的输出方法,但它在实际项目中往往被认为是不专业和不足够的。本文将探讨为什么在现代Java应用中应该避免使用 `System.out.println()`,并介绍几种更先进的日志解决方案。
61 1
|
1月前
|
SQL Oracle 关系型数据库
【赵渝强老师】Oracle的联机重做日志文件与数据写入过程
在Oracle数据库中,联机重做日志文件记录了数据库的变化,用于实例恢复。每个数据库有多组联机重做日志,每组建议至少有两个成员。通过SQL语句可查看日志文件信息。视频讲解和示意图进一步解释了这一过程。
|
2月前
|
数据采集 机器学习/深度学习 存储
使用 Python 清洗日志数据
使用 Python 清洗日志数据
47 2
|
3月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
55 2
|
3月前
|
开发者 Python
基于Python的日志管理与最佳实践
日志是开发和调试过程中的重要工具,然而,如何高效地管理和利用日志常常被忽略。本文通过Python中的logging模块,探讨如何使用日志来进行调试、分析与问题排查,并提出了一些实际应用中的优化建议和最佳实践。
|
3月前
|
SQL 人工智能 运维
在阿里云日志服务轻松落地您的AI模型服务——让您的数据更容易产生洞见和实现价值
您有大量的数据,数据的存储和管理消耗您大量的成本,您知道这些数据隐藏着巨大的价值,但是您总觉得还没有把数据的价值变现出来,对吗?来吧,我们用一系列的案例帮您轻松落地AI模型服务,实现数据价值的变现......
244 3
|
4月前
|
SQL 数据库 Java
Hibernate 日志记录竟藏着这些秘密?快来一探究竟,解锁调试与监控最佳实践
【8月更文挑战第31天】在软件开发中,日志记录对调试和监控至关重要。使用持久化框架 Hibernate 时,合理配置日志可帮助理解其内部机制并优化性能。首先,需选择合适的日志框架,如 Log4j 或 Logback,并配置日志级别;理解 Hibernate 的多级日志,如 DEBUG 和 ERROR,以适应不同开发阶段需求;利用 Hibernate 统计功能监测数据库交互情况;记录自定义日志以跟踪业务逻辑;定期审查和清理日志避免占用过多磁盘空间。综上,有效日志记录能显著提升 Hibernate 应用的性能和稳定性。
54 0
|
SQL 监控
日志服务数据加工最佳实践: 从RDS-MySQL拉取数据做富化
本篇覆盖日志服务数据加工最佳实践: 从RDS-MySQL拉取数据做富化的各种场景, 包括定期刷新拉取所有, 拉取部分数据, 拉取后再过滤数据, 调整返回表格结构等
1856 0
|
1月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
291 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板

相关产品

  • 日志服务