![f424ea088a37a17185717a4d61add7e7.png](https://img-blog.csdnimg.cn/img_convert/f424ea088a37a17185717a4d61add7e7.png)
数据加工服务简介
数据加工服务是阿里云SLS推出的面向日志ETL处理的服务,主要解决数据加工过程中转换、过滤、分发、富化等场景。
![8f2c8735a0a5c8ab210367d8d07d4a81.png](https://img-blog.csdnimg.cn/img_convert/8f2c8735a0a5c8ab210367d8d07d4a81.png)
接下来,我们以nginx日志解析为例, 帮助大家快速入门阿里云日志服务的数据加工。
用于实验的Nginx日志
假设我们通过极简模式采集了Nginx默认日志。默认的nginx 日志format如下
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
通过使用极简模式采集Nginx日志,样例如下:
![5b74faa4d2e5a818d02a73092cd21b76.png](https://img-blog.csdnimg.cn/img_convert/5b74faa4d2e5a818d02a73092cd21b76.png)
数据加工交互界面
点击 准备数据加工的Logstore,在查询栏的上方,有一个“数据加工”的开关,打开
![052dd1f6162385e288cc732d7f6534b7.png](https://img-blog.csdnimg.cn/img_convert/052dd1f6162385e288cc732d7f6534b7.png)
数据加工的代码编辑、预览、发布相关界面如下图:
![bae846c7a79339d431a5a82ab14ac1a2.png](https://img-blog.csdnimg.cn/img_convert/bae846c7a79339d431a5a82ab14ac1a2.png)
一般情况下,我们都可以使用快速预览模式,如果我们的数据加工涉及到使用mysql、oss等维表,可以使用高级预览做实际预览测试。
对Nginx日志进行数据加工 (Step by Step)
Step1. 使用正则抽取基础字段
对于极简模式采集的日志,内容都在一个字段叫content的字段里,不利于我们做分析。可以通过数据加工正则函数,抽取nginx日志里的字段,使用到的加工函数如下:
# 用于将源字段里的内容,通过正则捕获组抽取出对应的字段
e_regex("源字段", "正则或有命名捕获正则", "目标字段名或数组(可选)")
针对Nginx日志,使用以下语句进行正则抽取
# 通用字段抽取
e_regex("content",'(?<remote_addr>[0-9:.]*) - (?<remote_user>[a-zA-Z0-9-_]*) [(?<local_time>[a-zA-Z0-9/ :-+]*)] "(?<request>[^"]*)" (?<status>[0-9]*) (?<body_bytes_sent>[0-9-]*) "(?<refer>[^"]*)" "(?<http_user_agent>[^"]*)"')
通过正则抽取以后,可以看到日志的字段增加了refer、remote_addr、remote_user、request等字段。
![14a84684ab06c7654a64cce46e7ced52.png](https://img-blog.csdnimg.cn/img_convert/14a84684ab06c7654a64cce46e7ced52.png)
Step2. 处理时间字段
当前提取到的localtime不易读,我们把它解析成易读的格式,会用到的以下数据加工函数:
# 用于设置字段值
e_set("字段名", "固定值或表达式函数")
# 将时间字符串解析为日期时间对象
dt_strptime('值如v("字段名")', "格式化字符串")
# 将日期时间对象按照指定格式转换为字符串
dt_strftime(日期时间表达式, "格式化字符串")
实现思路,先通过 dt_strptime 将local_time的时间转化为日期时间对象,然后再通过dt_strftime将日期时间对象转化为标准的日期时间字符串。 针对Nginx local_time的转化,使用如下数据加工语句:
e_set("local_time", dt_strftime(dt_strptime(v("local_time"),"%d/%b/%Y:%H:%M:%S %z"),"%Y-%m-%d %H:%M:%S"))
实现效果如下:
![1b7cd3886e14d7e054597f8e08f3b951.png](https://img-blog.csdnimg.cn/img_convert/1b7cd3886e14d7e054597f8e08f3b951.png)
Step3. 解析request uri
可以看到request字段由 METHOD URI VERSION组成,我们希望对 requst字段进行抽取,获取到请求的METHOD、URI以及VERSION,并且将请求URI中的请求的参数变成字段,方便后续进行查询。可以用以下函数来做实现
# 使用正则将request uri抽取
e_regex("源字段名", "正则或有命名捕获正则", "目标字段名或数组(可选)", mode="fill-auto")
# 进行urldecode
url_decoding('值如v("字段名")’)
# 设置字段值
e_set("字段名", "固定值或表达式函数", ..., mode="overwrite")
# 将request_uri中的key=value的组合抽取成字段 值的模式
e_kv("源字段正则或列表", sep="=", prefix="")
实现语句
e_regex("request", "(?<request_method>[^s]*) (?<request_uri>[^s]*) (?<http_version>[^s]*)")
e_set("request_uri", url_decoding(v("request_uri")))
e_kv("request_uri", prefix="uri_")
实现效果
![38b50aac74cd6702bdf0f0e3049381e9.png](https://img-blog.csdnimg.cn/img_convert/38b50aac74cd6702bdf0f0e3049381e9.png)
Step4. http code状态码映射
每一个http状态码都代表了不同的含义,下面是一份http状态码的映射表, 我们可以通过e_table_map 函数来将状态码的信息扩展到我们的日志字段中,方便后续做统计分析。
![7a10f1c760aa740b67e52f8646ccbf92.png](https://img-blog.csdnimg.cn/img_convert/7a10f1c760aa740b67e52f8646ccbf92.png)
涉及到的数据加工函数如下:
# 用来做字段富化,类似sql里join的功能
e_table_map("表格如通过tab_parse_csv(...)解析得到的",
"源字段列表或映射列表如[('f1', 'f1_new'), ('f2', 'f2_new')]",
"目标字段列表")
# 用来把csv文件解析成table对象
tab_parse_csv(CSV文本数据, sep=',', quote='"')
# code的映射关系维度表是一个csv文件,存在oss上,使用res_oss_file
res_oss_file(endpoint="OSS的endpoint", ak_id="OSS的AK_ID",
ak_key="OSS的AK_KEY", bucket="OSS的bucket", file="在OSS中存的文件地址",
change_detect_interval="定时更新时间,默认为0")
实际使用到的DSL语句如下
# http状态码映射
e_table_map(
tab_parse_csv(
res_oss_file(endpoint="oss-cn-shanghai.aliyuncs.com",
ak_id='',ak_key='',
bucket="ali-sls-etl-test",
file="http_code.csv", format='text')),
[("status","code")],
[("alias","http_code_alias"),
("description","http_code_desc"),
("category","http_code_category")])
看一下映射后的效果
![9856fdd1af76ddbea00e11794c8efca5.png](https://img-blog.csdnimg.cn/img_convert/9856fdd1af76ddbea00e11794c8efca5.png)
Step5. 通过UserAgent判断客户端操作系统
我们想了解客户用的是什么os版本,可以通过user agent里的字段用正则匹配来判断,用到dsl语句
# 取某个字段的值
v("字段名")
# 获取ua相关信息
ua_parse_all("带useragent信息的内容")
# 展开json字段, 因为ua_parse_all得到的是一个json对象,为了展开到一级字段使用e_json做展开
# 模式有 simple、full、parent、root 参考https://help.aliyun.com/document_detail/125488.html#section-o7x-7rl-2qh
e_json("源字段名", fmt="模式", sep="字段分隔符")
# 丢弃临时产生的字段
e_drop_fields("字段1", "字段2")
用到的dsl语句
# 通过User Agent解析获得客户端信息
e_set("ua",ua_parse_all(v("http_user_agent")))
e_json("ua", fmt='full',sep='_')
e_drop_fields("ua",regex=False)
加工效果
![c2c4ceaf95232b98b15dc12592f291f5.png](https://img-blog.csdnimg.cn/img_convert/c2c4ceaf95232b98b15dc12592f291f5.png)
Step6. 非200的日志投递到指定logstore
可以使用e_output函数来做日志投递,用regex_match做字段匹配
# 条件判断if
e_if("条件1如e_match(...)", "操作1如e_regex(...)", "条件2", "操作2", ....)
# 判断是否相等
op_ne(v("字段名1"), v("字段名2"))
# output发送到目标名称,目标名称在数据加工保存任务的时候配置对应的logstore信息
e_output(name="指定的目标名称")
实际的dsl语句
# 分发非200的日志
e_if(op_ne(v("http_code_alias"),"2xx"), e_output(name="nginx-log-bad"))
在预览里看到这个效果。(保存加工的时候,需要设置好对应project、logstore的ak信息)
![19b5a9c00df60f9a492ea92ef83af05e.png](https://img-blog.csdnimg.cn/img_convert/19b5a9c00df60f9a492ea92ef83af05e.png)
完整的DSL代码以及上线流程
好了,通过一步一步的开发调试,现得到完整的DSL代码如下
# 通用字段抽取
e_regex("content",'(?<remote_addr>[0-9:.]*) - (?<remote_user>[a-zA-Z0-9-_]*) [(?<local_time>[a-zA-Z0-9/ :-]*)] "(?<request>[^"]*)" (?<status>[0-9]*) (?<body_bytes_sent>[0-9-]*) "(?<refer>[^"]*)" "(?<http_user_agent>[^"]*)"')
# 设置localttime
e_set("local_time", dt_strftime(dt_strptime(v("local_time"),"%d/%b/%Y:%H:%M:%S"),"%Y-%m-%d %H:%M:%S"))
# uri字段抽取
e_regex("request", "(?<request_method>[^s]*) (?<request_uri>[^s]*) (?<http_version>[^s]*)")
e_set("request_uri", url_decoding(v("request_uri")))
e_kv("request_uri", prefix="uri_")
# http状态码映射
e_table_map(
tab_parse_csv(
res_oss_file(endpoint="oss-cn-shanghai.aliyuncs.com",
ak_id='',ak_key='',
bucket="ali-sls-etl-test",
file="http_code.csv", format='text')),
[("status","code")],
[("alias","http_code_alias"),
("description","http_code_desc"),
("category","http_code_category")])
# 通过User Agent解析获得客户端信息
e_set("ua",ua_parse_all(v("http_user_agent")))
e_json("ua", fmt='full',sep='_')
e_drop_fields("ua",regex=False)
# 分发非200的日志
e_if(op_ne(v("http_code_alias"),"2xx"), e_coutput(name="nginx-log-bad"))
在页面提交代码以后,保存数据加工
配置目标logstore信息,默认走完加工逻辑的日志都会发送到第一个目标logstore,我们在代码里指定了e_output到指定logstore,因此还需要第二个目标,并且目标的名字和e_output里指定的目标名称一致。
![a08ba51635e8271cba180299a75ad7a7.png](https://img-blog.csdnimg.cn/img_convert/a08ba51635e8271cba180299a75ad7a7.png)
保存完即完成上线,可以在数据处理-加工下看到该任务,点击进去可以看到加工延迟等信息。
![c7dd2fdb791d7f342836ea0675bc089e.png](https://img-blog.csdnimg.cn/img_convert/c7dd2fdb791d7f342836ea0675bc089e.png)
Nginx日志查询、可视化、报警
查询
假设,我们想对nginx异常的日志进行查询,以便做问题定位。我们可以针对需要查询的字段开启索引
![aa221007c1e03d2c3f7b3a0356bbf364.png](https://img-blog.csdnimg.cn/img_convert/aa221007c1e03d2c3f7b3a0356bbf364.png)
开启索引可以使用“自动生成索引”来自动帮助生成字段索引列表(否则需要手工填写字段)
![1dc00f0ff16c1f0e93a11cad0bb9b0a9.png](https://img-blog.csdnimg.cn/img_convert/1dc00f0ff16c1f0e93a11cad0bb9b0a9.png)
点击确定后,即完成索引配置。比如我们要查询 uri_item_name参数值为“测试商品_89”的错误情况,可以使用这样的query
* and uri_item_name : 测试商品_89
![dedb952a532581f3f4db691e689b143e.png](https://img-blog.csdnimg.cn/img_convert/dedb952a532581f3f4db691e689b143e.png)
可视化
我们关心每个请求的http请求是否成功,对于异常状态码,想做相应的统计,以方便我们做问题发现。 可以使用如下query统计 nginx-log-bad(非2xx类请求的logstore)状态码分布
* | select http_code_alias,count(*) as c
from log where http_code_alias is not null
group by http_code_alias order by c
使用饼图做可视化
![f66bd25b9d4d3a336c3c2d9844be57d6.png](https://img-blog.csdnimg.cn/img_convert/f66bd25b9d4d3a336c3c2d9844be57d6.png)
点击,“添加到仪表盘”,即可完成仪表盘的创建
![063bd7534900237be0dc8918292e32ee.png](https://img-blog.csdnimg.cn/img_convert/063bd7534900237be0dc8918292e32ee.png)
添加完成后,在左侧仪表盘就
![7e2123346517b089f1e990bb78a74618.png](https://img-blog.csdnimg.cn/img_convert/7e2123346517b089f1e990bb78a74618.png)
报警
针对非2xx的状态码,我们不仅要做可视化,还需要对它进行报警。 可以在刚才创建的仪表盘里,点击“告警->创建”,根据提示创建相应的告警规则。
![444744b63d8d0bbff3a95d00cf7ff3e5.png](https://img-blog.csdnimg.cn/img_convert/444744b63d8d0bbff3a95d00cf7ff3e5.png)
![8f29fc12ccbe00a42e8edd96a03f5c63.png](https://img-blog.csdnimg.cn/img_convert/8f29fc12ccbe00a42e8edd96a03f5c63.png)
总结
本次训练营,以最常见的Nginx日志作为例,介绍数据加工在日志的转化、处理、富化、转发等场景下相关的算子使用,帮助大家入门SLS的数据加工。除了文中提到的算子,数据加工还有200+的算子以支持更多的日志处理的场景,相关内容可以参考如下:
a) SLS数据加工整体简介:https://help.aliyun.com/document_detail/125384.html
b) SLS数据加工函数总览:https://help.aliyun.com/document_detail/159702.html
在数据加工之后,针对相关字段建立索引,可以方便地对日志内容进行各种场景的分析,并且针对有需要的场景设置对应的报警,提升系统的稳定性。