背景
这里我们对一个Logstore中的网关数据(阿里云SLB日志)举例,对其数据进行加工并分发到不通的Logstore中。
数据
源logstore(slb-log)的数据内容是一个阿里云SLB的网络日志,格式样例如下:
__source__: log_service
__tag__:__receive_time__: 1559799897
__topic__:
body_bytes_sent: 740
client_ip: 1.2.3.4
host: m.abcd.com
http_host: m.abcd.com
http_referer: -
http_x_forwarded_for: -
http_x_real_ip: -
read_request_time: 0
request_length: 0
request_method: GET
request_time: 0.000
request_uri: /category/abc/product_id?id=75&type=2&sam=123
scheme: https
server_protocol: HTTP/2.0
slb_vport: 443
slbid: lb-1234
ssl_cipher: ECDHE-RSA-AES128-GCM-SHA256
ssl_protocol: TLSv1.2
status: 200
tcpinfo_rtt: 58775
time: 2019-06-06T13:44:50+08:00
upstream_addr: 1.2.3.4:80
upstream_response_time: 4.1234
upstream_status: 200
vip_addr: 1.2.3.4
write_response_time: 4.1234
目标
这里我们希望对数据进行如下加工获取三份数据:
分发
- 将所有status非2XX或者3XX的请求,复制一份到目标logstore:
slb-log-error
中,日志时间180天,以便进一步做研发与安全类分析,__topic__
设置为slb_error
- 将所有不那么重要的图片或静态资源的请求日志,分发到目标logstore:
slb-log-media
,日志保存30天, topic设置为slb_media_request
- 其他的请求日志,用于进一步分析统计业务对接的,分发到目标logstore:
slb-log-normal
,日志保存90天,topic设置为slb_normal
转换
- 对
slb_media_request
的请求
- 提取如下字段
object_file=app.icon
object_type = icon # css, jpeg, js 等
- 保留如下字段:
http_referer: -
body_bytes_sent: 740
client_ip: 1.2.3.4
host: m.abcd.com
request_time: 4.33
-
slb_normal
请求
- 保留如下字段
body_bytes_sent: 740
client_ip: 1.2.3.4
host: m.abcd.com
http_referer: -
http_x_real_ip: -
request_length: 0
request_method: GET
request_time: 4.33
request_uri: /category/abc/product_id?id=75&type=2&sam=123
scheme: https
slb_vport: 443
slbid: lb-1234
status: 200
time: 2019-06-06T13:44:50+08:00
- 提取request_uri的参数加上前缀
reqparam_
reqparam_id: 75
reqparam_type: 2
reqparam_sam: 123
-
http_x_real_ip
如果为空或者-
时,填上client_ip
的值 - 提取
host
中的domain值:
domain: abcd
准备工作
目标logstore准备
- 创建好如下3个logstore
slb-log-normal # 日志保存90天,逻辑命名定为target0
slb-log-error # 日志保存180天,逻辑命名定为target1
slb-log-media # 日志保存30天, 逻辑命名定位target2
- 并各自配置好索引
点击每个logstore的【查询】页面的【索引】设置,并根据每个logstore存储的日志的字段,配置相应的索引。也可以使用CloudShell中的CLI的copy_logstore子命令来从源logstore复制一份索引到目标,再进行调整来简化操作。
权限秘钥准备
当前操作需要授权以便读取源logstore或写入目标logstore
- 通过AK秘钥授权
- 通过角色授权(二期会支持)
需要准备好一个或多个(每个logstore对应一个)AK秘钥访问:
源logstore的最小RAM授权
{
"Version": "1",
"Statement": [
{
"Action": [
"log:ListShards",
"log:GetCursorOrData",
"log:GetConsumerGroupCheckPoint",
"log:UpdateConsumerGroup",
"log:ConsumerGroupHeartBeat",
"log:ConsumerGroupUpdateCheckPoint",
"log:ListConsumerGroup",
"log:CreateConsumerGroup"
],
"Resource": [
"acs:log:*:*:project/源project/logstore/slb-log",
"acs:log:*:*:project/源project/logstore/slb-log/*"
],
"Effect": "Allow"
}
]
}
目标logstore的最下RAM授权
{
"Statement": [
{
"Action": [
"log:Post*"
],
"Effect": "Allow",
"Resource": [ "acs:log:*:*:project/目标Project/logstore/slb-log-error", "acs:log:*:*:project/目标Project/logstore/slb-log-media", "acs:log:*:*:project/目标Project/logstore/slb-log-normal"]
}
],
"Version": "1"
}
也可以考虑将这两个授权合并成一个以便简化操作。
配置加工任务
进入加工规则界面
- 在日志服务列表中,选择源logstore(slb-log)【加工】
- 进入交互的加工界面
在 #1 中选择日期的时间,例如【今天】,确保能够看到数据:
复制失败的请求日志到sbl-log-error
在编辑框中输入如下的规则(关于语法说明,可参考后续的章节):
TRANSFORM_ANY_1 = {"status": r"4\d+|5\d+" }, COUTPUT(name='target1', topic="slb_error")
DROP_EVENT_1 = ANY
再点击【预览数据】,会弹窗提示输入访问源logstore的AK秘钥,输入前面准备的,
等一会,可以在【数据加工】标签页中看到结果中,将所有非2XX/3XX的请求会输出到target1
的目标中,且topic
设置为了slb_error
:
提取静态类请求日志并输出到sbl-log-media
在规则编辑框中更新如下规则(关于语法说明,可参考后续的章节:
#TRANSFORM_ANY_1 = {"status": r"4\d+|5\d+" }, COUTPUT(name='target1', topic="slb_error")
SET_EVENT_object_file = regex(v("request_uri"), r"/([\.\w]+\.\w+)(?:\?.+|$)?", gi=0)
SET_EVENT_object_type = regex(v("object_file"), r"^[\w\.]+\.(\w+)$", gi=0)
TRANSFORM_EVENT_2 = NO_EMPTY("object_file"),
[ KEEP_F([F_META, r"object_\w+|request_uri|client_ip|host|request_time" ]),
OUTPUT(name="target2", topic="slb_media_request"),
]
DROP_EVENT_1 = ANY
再点击【预览数据】,等一会,可以在【数据加工】标签页中看到结果中,将静态类请求会输出到target2
的目标中,如前面需求描述,特定的字段被提取,并且还新增了2个字段object_file
和object_type
且topic
设置为了slb_media_request
:
调整字段并输出正常请求日志到sbl-log-normal
在编辑框中更新如下规则(关于语法说明,可参考后续的章节:
#TRANSFORM_ANY_1 = {"status": r"4\d+|5\d+" }, COUTPUT(name='target1', topic="slb_error")
#SET_EVENT_object_file = regex(v("request_uri"), r"/([\.\w]+\.\w+)(?:\?.+|$)?", gi=0)
#SET_EVENT_object_type = regex(v("object_file"), r"^[\w\.]+\.(\w+)$", gi=0)
#TRANSFORM_EVENT_2 = NO_EMPTY("object_file"),
# [ KEEP_F([F_META, r"object_\w+|request_uri|client_ip|host|request_time" ]),
# OUTPUT(name="target2", topic="slb_media_request"),
# ]
SET_EVENT___topic__ = 'slb_normal'
EXTRACT_EVENT_request_uri = KV(prefix="reqparam_")
SET_EVENT_http_x_real_ip = op_if(op_eq(v("http_x_real_ip"), '-'), v("client_ip"), v("http_x_real_ip")
KEEP_FIELDS_1 = [F_META, r"body_bytes_sent|client_ip|host|http_referer|http_x_real_ip|request_length",
"request_method|request_time|request_uri|scheme|slb_vport|slbid|status"]
#DROP_EVENT_1 = ANY
再点击【预览数据】,等一会,可以在【数据加工】标签页中看到结果中,将非媒体类请求输出到target0
的目标中,如前面需求描述,特定的字段被提取,并且字段http_x_real_ip
被设置成了非-
的值,且topic
设置为了slb_normal
:
保存配置
最终加工规则
在确认规则正确后,去掉注释的部分,就是完整版本:
TRANSFORM_ANY_1 = {"status": r"4\d+|5\d+" }, COUTPUT(name='target1', topic="slb_error")
SET_EVENT_object_file = regex(v("request_uri"), r"/([\.\w]+\.\w+)(?:\?.+|$)?", gi=0)
SET_EVENT_object_type = regex(v("object_file"), r"^[\w\.]+\.(\w+)$", gi=0)
TRANSFORM_EVENT_2 = NO_EMPTY("object_file"),
[ KEEP_F([F_META, r"object_\w+|request_uri|client_ip|host|request_time" ]),
OUTPUT(name="target2", topic="slb_media_request"),
]
SET_EVENT___topic__ = 'slb_normal'
EXTRACT_EVENT_request_uri = KV(prefix="reqparam_")
SET_EVENT_http_x_real_ip = op_if(op_eq(v("http_x_real_ip"), '-'), v("client_ip"), v("http_x_real_ip")
KEEP_FIELDS_1 = [F_META, r"body_bytes_sent|client_ip|host|http_referer|http_x_real_ip|request_length",
"request_method|request_time|request_uri|scheme|slb_vport|slbid|status"]
配置目标
点击【保存加工配置】,在配置中,依据前面的需求,配置源logstore的秘钥(预览的时候已经配置了),以及3个目标logstore的Project名、logstore名和写入的AK秘钥。注意3个目标的逻辑名称需要与规则中应用的规则保持一致。
配置加工范围
在加工范围中,可以根据情况选择【所有】、【某个时间开始】或者特定范围,这里选择【某个时间开始】,并选择此刻。那么保存后,新写入源logstore的数据将会自动应用规则写入到配置的3个目标去。
加工任务管理与监控
任务管理
点击日志服务项目页面的左侧导航栏中的【数据加工】,可以看到保存的加工任务,可以根据情况选择修改、停止、重启等操作。
状态洞察
对于数据加工的状态,可以点击以上的【规则洞察】,可以看到当前任务的执行状态,以及错误信息,以便调整:
语法详细说明
第一次预览操作
规则
TRANSFORM_ANY_1 = {"status": r"4\d+|5\d+" }, COUTPUT(name='target1', topic="slb_error")
DROP_EVENT_1 = ANY
说明
- 这里的规则
TRANSFORM_ANY_1 = 条件, 操作
- Python语法中,字符串前面用
r
修饰,可以避免写两个\
的麻烦。 - 操作:COUTPUT(name='target1', topic="slb_error") 表示复制一份数据并输出到目标
target1
中,并且将topic
设置为slb_error
- 规则
DROP_EVENT_1 = ANY
表示丢弃所有剩余的日志;这里是为了预览的效果特意加上,实际保存的配置中不会有这句话。
第二次预览操作
规则
#TRANSFORM_ANY_1 = {"status": r"4\d+|5\d+" }, COUTPUT(name='target1', topic="slb_error")
SET_EVENT_object_file = regex(v("request_uri"), r"/([\.\w]+\.\w+)(?:\?.+|$)?", gi=0)
SET_EVENT_object_type = regex(v("object_file"), r"^[\w\.]+\.(\w+)$", gi=0)
TRANSFORM_EVENT_2 = NO_EMPTY("object_file"),
[ KEEP_F([F_META, r"object_\w+|request_uri|client_ip|host|request_time" ]),
OUTPUT(name="target2", topic="slb_media_request"),
]
DROP_EVENT_1 = ANY
详细说明
-
SET_EVENT_字段名
表示设置一个新字段,使用后面的表达式函数
的返回值:从字段request_uri
中提取了字段object_file
,然后进一步提取了object_type
,如果object_file
不存在,字段object_type
也不会存在。 -
TRANSFORM_EVENT_2 = 条件, [操作1, 操作2]
表示对于字段object_file
不为空的事件,保留特定字段,并且输出到target2
后不再后续处理。 - 规则中的第一行步骤使用Python的语法方式
#
注释掉了,保留最后一行DROP_EVENT_1 = ANY
的目的是方便预览。
第三次预览操作
规则
#TRANSFORM_ANY_1 = {"status": r"4\d+|5\d+" }, COUTPUT(name='target1', topic="slb_error")
#SET_EVENT_object_file = regex(v("request_uri"), r"/([\.\w]+\.\w+)(?:\?.+|$)?", gi=0)
#SET_EVENT_object_type = regex(v("object_file"), r"^[\w\.]+\.(\w+)$", gi=0)
#TRANSFORM_EVENT_2 = NO_EMPTY("object_file"),
# [ KEEP_F([F_META, r"object_\w+|request_uri|client_ip|host|request_time" ]),
# OUTPUT(name="target2", topic="slb_media_request"),
# ]
SET_EVENT___topic__ = 'slb_normal'
EXTRACT_EVENT_request_uri = KV(prefix="reqparam_")
SET_EVENT_http_x_real_ip = op_if(op_eq(v("http_x_real_ip"), '-'), v("client_ip"), v("http_x_real_ip")
KEEP_FIELDS_1 = [F_META, r"body_bytes_sent|client_ip|host|http_referer|http_x_real_ip|request_length",
"request_method|request_time|request_uri|scheme|slb_vport|slbid|status"]
详细说明
- 这里设置默认的事件
__topic__
- 使用
EXTRACT_EVENT_字段名 = 字段类操作
,对字段request_uri
的值进行KV
操作,自动提取其中的键值对并放到事件中。 - 进一步的基于表达式函数设置了字段
http_x_real_ip
的值。最后保留特定字段。 - 默认没有使用
OUTPUT
等,因为默认会将事件输出到第一个配置的目标target0
中。 - 规则中的前2个步骤使用Python的语法方式
#
注释掉了,目的是为了避免预览效果的查看,后续会恢复。
进一步参考
欢迎扫码加入官方钉钉群 (11775223)获得实时更新与阿里云工程师的及时直接的支持: