提取标签
概述
在 DataFlux 的日志管理中,可以配置标签提取规则对日志的文本内容进行切割,从而提取出特定的字段作为标签或者日志的时间戳。目前 DataFlux 支持 2 种日志提取方式:按 Grok 表达式方式提取和按 JSON 字段提取。
按 Grok 表达式方式提取
Grok 是一种通过正则表达式的方式对日志文本进行切割处理然后提取有效字段的方式。一个 Grok 提取表达式由多个子表达式组成,子表达式语法 %{syntax:semantic:type}
。syntax 代表的是正则表达式,semantic 代表这个表达式提取后对应的字段名,你可以自由命名,但命名尽量能简单易懂的表达出这个字段代表的意思,type 表示提取字段的类型,目前 type 只支持 2 种类型,float
和 int
。对于 syntax
,Grok 已经内置了120多种的正则表达式库,地址:https://github.com/logstash-plugins/logstash-patterns-core/tree/master/patterns。
对于同一种模式的日志,如果我们需要配置 Grok 提取规则,一般分为 4 步:
1、根据提取需求结合日志内容确定日志的切分原则。
2、对切割的每一部分进行分析,如果 Grok 中内置的匹配模式能够使用,直接使用,如果内容中的匹配模式没有,则需要进行自定义。
3、利用 Grok Debug 进行调试。
4、调试没问题后,在 DataFlux 中 创建提取规则。
举个例子,下面是一条 Nginx 的 access 日志:
127.0.0.1 - admin [14/Jul/2020:08:53:10 +0800] "POST /network_address_alias/_search?typed_keys=true&ignore_unavailable=false&expand_wildcards=open&allow_no_i
ndices=true&search_type=query_then_fetch&batched_reduce_size=512&ccs_minimize_roundtrips=true HTTP/1.1" 200 160 "-" "Apache-HttpAsyncClient/4.1.4 (Java/1.8.0
_252)" "-"
假设我们需要提取访问客户端IP、日志产生时间、HTTP 请求方法、HTTP 响应码。分析日志可知:
127.0.0.1
即客户端IP14/Jul/2020:08:53:10 +0800
即日志产生时间POST
即请求方法200
即响应码
首先提取访问IP,对应 IP Grok 已经内置了匹配模式 IPV4
,可以直接使用 %{IPV4:clientIP}
[14/Jul/2020:08:53:10 +0800]
是日志产生的时间,因为时间有不同的格式,所以我们需要找到对应的日志格式的匹配模式,Grok 内置的 HTTPDATE
可以匹配这个格式
请求访问可以通过内置模式 WORD
匹配
响应码我们可以通过自定义表达式进行匹配,Grok 自定义表达式语法:(?<field_name>the pattern here)
,field_name 即提取后的字段名,the pattern here
写匹配正则,HTTP 协议的响应码都是整数,所以响应码提取表达式可以这样写 (?<statusCode>(?:[+-]?(?:[0-9]+)))
综上,按照我们的需求,nginx 的日志提取表达式可以这样写:
%{IPV4:clientIP} - (?:.+) \[%{HTTPDATE:__timestampUs}\] "%{WORD:method} (?:.+?)" (?<statusCode>(?:[+-]?(?:[0-9]+)))
将表达式放到 Grok Debug 中测试,可以看出,我们希望提取的字段都已经被正确提取出来,这时就可以在 DataFlux 创建提取规则了。
按 JSON 字段提取
如果采集导入日志文本是 JSON 格式,可以设置通过 JSON 字段的方式进行提取。DataFlux 的 JSON 字段提取方式使用的是 jsonpath 语法,具体语法可参考这里。
举个例子,假设有这样一个日志:
{
"timestamp":1594281398904796,
"duration":1503145,
"traceId":"7996621b30aad19b",
"id":"d1fcbcf283ed151a",
"parentId":"bad9602e2d2968b7",
"name":"get /api",
"kind":"SERVER",
"shared":true,
"localEndpoint":{
"serviceName":"backend",
"ipv4":"172.19.39.63"
},
"tags":{
"http.path":"/api",
"http.status_code":"200"
}
}
我们需要提取 timestamp
作为日志的产生时间,提取 localEndpoint
中的 ipv4
和 tags
中的 http.path
作为标签,标签名分别为 ip
和 requestPath
,可以这样设置字段映射关系:
__timestampUs=timestamp;ip=localEndpoint.ipv4;requestPath=tags["http.path"]
注意:多个字段映射用英文逗号分隔
保留字段覆盖
在 DataFlux 的日志数据结构中,设计一些保留字段(DataFlux 中所有保留字段都以双下划线__
开头),如果需要覆盖保留的字段,可将提取的字段名命名为保留字段即可,例如:默认情况下 DataFlux 的 tailf 采集器会将日志采集的时间作为日志的产生时间戳,实际上,日志的产生时间一般都在日志的内容中,如果需要进行覆盖,可以将时间戳提取后的字段名命令问 __timestampUs
即可覆盖默认的日志时间。所有保留日志保留字段如下:
字段名 | 类型 | 说明 |
---|---|---|
__timestampUs | timestamp | 日志的产生时间,微秒为单位,tailf 采集器默认以日志的采集时间为产生时间,可通过配置提取规则进行覆盖 |
__content | field,string | 日志的原始内容 |
__class | tag | 日志的子分类,目前仅支持:tracing 表示该日志是链路追踪日志 |
__source | tag | 日志来源,日志上报时,需指定日志的来源,一般同一类应用产生的日志应该命名为同一个来源,比如 nginx,apache |
__serviceName | tag | 日志所属业务或服务的名称,建议用户通过该标签指定产生该日志业务系统的名称 |
__status | tag | 日志等级,状态,info:提示,warning:警告,error:错误,critical:严重,ok:成功,默认:info |
__parentID | tag | 用于链路日志,表示当前span 的上一个span 的 ID |
__operationName | tag | 用于链路日志,表示当前 span 操作名,也可理解为 span 名称 |
__spanID | tag | 用于链路日志,表示当前span 的 ID |
__traceID | tag | 用于链路日志,表示当前链路的 ID |
__isError | tag | 字符串类型,true 表示该 span 的请求响应是错误,false 或者无该标签,表示该 span 的响应是正常的请求 |
__spanType | tag | span 的类型,目前支持 2 个值:entry 和 local ,entry span 表示该 span 的调用的是服务的入口,即该服务的对其他服务提供调用请求的端点,几乎所有服务和消息队列消费者都是 entry span,因此只有 span 是 entry 类型的调用才是一个独立的请求。 local span 表示该 span 和远程调用没有任何关系,只是程序内部的函数调用,例如一个普通的 Java 方法,默认值 entry |
__endpoint | tag | 请求的目标地址,客户端用于访问目标服务的网络地址(但不一定是 IP + 端口),例如 127.0.0.1:8080 ,默认:null |