Kibana - 如何从现有的Kubernetes日志中提取字段

时间:2017-02-16 10:02:26

标签: logging kubernetes kibana elastic-stack fluentd

我有一种ELK堆栈,使用流利而不是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中可见的字段如下截图所示:

kibana nginx log

是否可以在索引后从这种类型的日志中提取字段?

流利的收集器配置了以下源,它处理所有容器,因此由于不同容器的输出非常不同,因此无法在此阶段强制执行格式:

<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”等。

2 个答案:

答案 0 :(得分:3)

经过几天的研究并习惯了EFK stack,我得到了一个EFK特定的解决方案,而不是Darth_Vader的答案,这只能在ELK堆栈上进行。

总而言之,我使用的是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 - 告诉流利者应用解析器过滤器

key_name log - 仅在日志行的log属性上应用模式,而不是整行,这是一个json字符串

reserve_data yes - 非常重要,如果没有指定,整个日志行对象只会被从format中提取的属性替换,所以如果你已经有了其他属性,比如{{{ 1}}过滤器,在不添加kubernetes_metadata选项

时会删除这些内容

reserve_data - 应用于format键的值以提取命名属性的正则表达式

请注意我使用的是Fluentd 1.12,因此这种语法与较新的1.14语法并不完全兼容,但原理适用于对解析器声明的微调。

答案 1 :(得分:1)

要将日志行提取到字段中,您可能必须使用grok过滤器。你可以做的是拥有一个正则表达式模式,以匹配你需要的日志行的确切部分。 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,可以派上用场!希望这会有所帮助。