Kibana - 如何从现有的 Kubernetes 日志中提取字段
Kibana - How to extract fields from existing Kubernetes logs
我有一种 ELK 堆栈,使用 fluentd 而不是 logstash,运行 作为 Kubernetes 集群上的 DaemonSet,并将来自所有容器的所有日志以 logstash 格式发送到 Elasticsearch 服务器。
在 Kubernetes 集群上的许多容器 运行 中,一些是 nginx 容器,它们输出以下格式的日志:
121.29.251.188 - [16/Feb/2017:09:31:35 +0000] host="subdomain.site.com" req="GET /data/schedule/update?date=2017-03-01&type=monthly&blocked=0 HTTP/1.1" status=200 body_bytes=4433 referer="https://subdomain.site.com/schedule/2589959/edit?location=23092&return=monthly" user_agent="Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0" time=0.130 hostname=webapp-3188232752-ly36o
Kibana 中可见的字段如下图所示:
是否可以在索引后从这种类型的日志中提取字段?
fluentd 收集器配置了以下源,它处理所有容器,因此由于不同容器的输出非常不同,因此在此阶段无法强制执行格式:
<source>
type tail
path /var/log/containers/*.log
pos_file /var/log/es-containers.log.pos
time_format %Y-%m-%dT%H:%M:%S.%NZ
tag kubernetes.*
format json
read_from_head true
</source>
在理想情况下,我想用 "log" 字段中的元字段丰富上面屏幕截图中可见的字段,例如 "host"、"req"、"status"等
为了将日志行提取到字段中,您可能必须使用 grok 过滤器。您可以做的是使用 regex 模式,以匹配您需要的日志行的确切部分。 Grok 过滤器可能看起来像这样:
grok {
patterns_dir => ["pathto/patterns"]
match => { "message" => "^%{LOGTIMESTAMP:logtimestamp}%{GREEDYDATA:data}" }
} ^-----------------------^ are the fields you would see in ES when log is being indexed
-------------------------------------------- ------^ LOGTIMESTAMP
应该在您的模式文件中定义为:
LOGTIMESTAMP %{YEAR}%{MONTHNUM}%{MONTHDAY} %{TIME}
一旦你有了匹配的字段,那么你可以简单地将它们用于 filtering
目的,或者你仍然可以保持原样,如果主要原因是它从日志行中提取字段。
if "something" in [message]{
mutate {
add_field => { "new_field" => %{logtimestamp} }
}
}
以上只是一个示例,您可以根据自己的需要进行复制。您可以使用 this 工具来测试您的模式以及您想要匹配的字符串!
Blog post,可以派上用场!希望这有帮助。
经过几天的研究并习惯了 EFK stack,我找到了一个 EFK 特定的解决方案,这与 Darth_Vader 的答案相反,后者只能在麋鹿栈.
总而言之,我使用的是 Fluentd 而不是 Logstash,因此如果您还安装 Fluentd Grok Plugin,任何 grok 解决方案都可以使用,我决定不这样做,因为:
事实证明,Fluentd 通过使用 parser filters 拥有自己的字段提取功能。为了解决我问题中的问题,就在 <match **>
行之前,所以在日志行对象已经用 kubernetes 元数据字段和标签丰富之后,我添加了以下内容:
<filter kubernetes.var.log.containers.webapp-**.log>
type parser
key_name log
reserve_data yes
format /^(?<ip>[^-]*) - \[(?<datetime>[^\]]*)\] host="(?<hostname>[^"]*)" req="(?<method>[^ ]*) (?<uri>[^ ]*) (?<http_version>[^"]*)" status=(?<status_code>[^ ]*) body_bytes=(?<body_bytes>[^ ]*) referer="(?<referer>[^"]*)" user_agent="(?<user_agent>[^"]*)" time=(?<req_time>[^ ]*)/
</filter>
说明:
<filter kubernetes.var.log.containers.webapp-**.log>
- 在匹配该标签的所有行上应用该块;在我的例子中,Web 服务器组件的容器称为 webapp-{something}
type parser
- 告诉 fluentd 应用解析器过滤器
key_name log
- 仅在日志行的 log
属性 应用模式,而不是整行,这是一个 json 字符串
reserve_data yes
- 非常重要,如果未指定,整个日志行对象将仅替换为从 format
中提取的属性,因此如果您已经有其他属性,例如由kubernetes_metadata
过滤器,不添加 reserve_data
选项时将删除这些
format
- 应用于 log
键的值以提取命名属性的正则表达式
请注意我使用的是 Fluentd 1.12,因此此语法与较新的 1.14 语法不完全兼容,但原理将通过对解析器声明的微小调整起作用。
我有一种 ELK 堆栈,使用 fluentd 而不是 logstash,运行 作为 Kubernetes 集群上的 DaemonSet,并将来自所有容器的所有日志以 logstash 格式发送到 Elasticsearch 服务器。
在 Kubernetes 集群上的许多容器 运行 中,一些是 nginx 容器,它们输出以下格式的日志:
121.29.251.188 - [16/Feb/2017:09:31:35 +0000] host="subdomain.site.com" req="GET /data/schedule/update?date=2017-03-01&type=monthly&blocked=0 HTTP/1.1" status=200 body_bytes=4433 referer="https://subdomain.site.com/schedule/2589959/edit?location=23092&return=monthly" user_agent="Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0" time=0.130 hostname=webapp-3188232752-ly36o
Kibana 中可见的字段如下图所示:
是否可以在索引后从这种类型的日志中提取字段?
fluentd 收集器配置了以下源,它处理所有容器,因此由于不同容器的输出非常不同,因此在此阶段无法强制执行格式:
<source>
type tail
path /var/log/containers/*.log
pos_file /var/log/es-containers.log.pos
time_format %Y-%m-%dT%H:%M:%S.%NZ
tag kubernetes.*
format json
read_from_head true
</source>
在理想情况下,我想用 "log" 字段中的元字段丰富上面屏幕截图中可见的字段,例如 "host"、"req"、"status"等
为了将日志行提取到字段中,您可能必须使用 grok 过滤器。您可以做的是使用 regex 模式,以匹配您需要的日志行的确切部分。 Grok 过滤器可能看起来像这样:
grok {
patterns_dir => ["pathto/patterns"]
match => { "message" => "^%{LOGTIMESTAMP:logtimestamp}%{GREEDYDATA:data}" }
} ^-----------------------^ are the fields you would see in ES when log is being indexed
-------------------------------------------- ------^ LOGTIMESTAMP
应该在您的模式文件中定义为:
LOGTIMESTAMP %{YEAR}%{MONTHNUM}%{MONTHDAY} %{TIME}
一旦你有了匹配的字段,那么你可以简单地将它们用于 filtering
目的,或者你仍然可以保持原样,如果主要原因是它从日志行中提取字段。
if "something" in [message]{
mutate {
add_field => { "new_field" => %{logtimestamp} }
}
}
以上只是一个示例,您可以根据自己的需要进行复制。您可以使用 this 工具来测试您的模式以及您想要匹配的字符串!
Blog post,可以派上用场!希望这有帮助。
经过几天的研究并习惯了 EFK stack,我找到了一个 EFK 特定的解决方案,这与 Darth_Vader 的答案相反,后者只能在麋鹿栈.
总而言之,我使用的是 Fluentd 而不是 Logstash,因此如果您还安装 Fluentd Grok Plugin,任何 grok 解决方案都可以使用,我决定不这样做,因为:
事实证明,Fluentd 通过使用 parser filters 拥有自己的字段提取功能。为了解决我问题中的问题,就在 <match **>
行之前,所以在日志行对象已经用 kubernetes 元数据字段和标签丰富之后,我添加了以下内容:
<filter kubernetes.var.log.containers.webapp-**.log>
type parser
key_name log
reserve_data yes
format /^(?<ip>[^-]*) - \[(?<datetime>[^\]]*)\] host="(?<hostname>[^"]*)" req="(?<method>[^ ]*) (?<uri>[^ ]*) (?<http_version>[^"]*)" status=(?<status_code>[^ ]*) body_bytes=(?<body_bytes>[^ ]*) referer="(?<referer>[^"]*)" user_agent="(?<user_agent>[^"]*)" time=(?<req_time>[^ ]*)/
</filter>
说明:
<filter kubernetes.var.log.containers.webapp-**.log>
- 在匹配该标签的所有行上应用该块;在我的例子中,Web 服务器组件的容器称为 webapp-{something}
type parser
- 告诉 fluentd 应用解析器过滤器
key_name log
- 仅在日志行的 log
属性 应用模式,而不是整行,这是一个 json 字符串
reserve_data yes
- 非常重要,如果未指定,整个日志行对象将仅替换为从 format
中提取的属性,因此如果您已经有其他属性,例如由kubernetes_metadata
过滤器,不添加 reserve_data
选项时将删除这些
format
- 应用于 log
键的值以提取命名属性的正则表达式
请注意我使用的是 Fluentd 1.12,因此此语法与较新的 1.14 语法不完全兼容,但原理将通过对解析器声明的微小调整起作用。