我在k8s中有一个相当简单的Apache部署,使用fluent bit v1.5作为日志转发器。我的设置与下面回购中的设置几乎相同。我正在运行AWS EKS并将日志输出到AWS ElasticSearch服务。
https://github.com/fluent/fluent-bit-kubernetes-logging
ConfigMap在这里:https://github.com/fluent/fluent-bit-kubernetes-logging/blob/master/output/elasticsearch/fluent-bit-configmap.yaml
Apache访问(->/dev/stdout(和错误(-</dev/stderr(日志行都在节点上的同一容器日志文件中。我遇到的问题是fluent bit似乎无法自动检测要使用哪个解析器,我不确定它是否应该使用,而且我们只能在部署的注释部分指定一个解析器,我已经指定了apache。因此,最终不会解析写入同一文件但来自stderr的错误日志行。我应该将日志从fluent bit发送到fluentd来处理错误文件,假设fluentd可以处理这个问题,还是应该以某种方式将错误行泵回fluent bit进行解析?
我是不是错过了什么?
谢谢!
通过使用FluentBit FILTER和'parser'插件(名称(,我能够将第二个(和第三个(解析器应用于日志,如下所示。
此处记录:https://docs.fluentbit.io/manual/pipeline/filters/parser
[FILTER]
Name parser
Match kube.*
Parser apache_error_custom
Parser apache_error
Preserve_Key On
Reserve_Data On
Key_Name log
Fluentbit能够对输入运行多个解析器。
如果您将多个解析器作为换行符添加到解析器过滤器中(对于非多行解析,因为多行支持逗号分隔(,例如
[Filter]
Name Parser
Match *
Parser parse_common_fields
Parser json
Key_Name log
第一个解析器parse_common_fields
将尝试解析日志,只有在失败时,第二个解析器json
才会尝试解析这些日志。
如果您想解析一个日志,然后再次解析它,例如,日志中只有一部分是JSON。然后你会想要添加2个解析器,像这样:
[Filter]
Name Parser
Match *
Parser parse_common_fields
Key_Name log
[Filter]
Name Parser
Match *
Parser json
# This is the key from the parse_common_fields regex that we expect there to be JSON
Key_Name log
下面是一个可以运行来测试的示例:
示例
试图解析日志,但某些日志可能是JSON,而其他时候则不是。
示例日志行
2022-07-28T22:03:44.585+0000 [http-nio-8080-exec-3] [2a166faa-dbba-4210-a328-774861e3fdef][0ed32f19-47bb-4c1f-92c2-c9b7c43aa91f] INFO SomeService:000 - Using decorator records threshold: 0
2022-07-29T11:36:59.236+0000 [http-nio-8080-exec-3] [][] INFO CompleteOperationLogger:25 - {"action":"Complete","operation":"healthcheck","result":{"outcome":"Succeeded"},"metrics":{"delayBeforeExecution":0,"duration":0},"user":{},"tracking":{}}
parser.conf
[PARSER]
Name parse_common_fields
Format regex
Regex ^(?<timestamp>[^ ]+)..+ [(?<log_type>[^ []]+)] [(?<transaction_id>[^ []]*)][(?<transaction_id2>[^ []]*)] (?<level>[^ ]*)s+(?<service_id>[^ ]+) - (?<log>.+)$
Time_Format %Y-%m-%dT%H:%M:%S
Time_Key timestamp
[PARSER]
Name json
Format json
fluentbit.conf
[SERVICE]
Flush 1
Log_Level info
Parsers_File parser.conf
[INPUT]
NAME dummy
Dummy {"log": "2022-07-28T22:03:44.585+0000 [http-nio-8080-exec-3] [2a166faa-dbba-4210-a328-774861e3fdef][0ed32f19-47bb-4c1f-92c2-c9b7c43aa91f] INFO AnonymityService:245 - Using decorator records threshold: 0"}
Tag testing.deanm.non-json
[INPUT]
NAME dummy
Dummy {"log": "2022-07-29T11:36:59.236+0000 [http-nio-8080-exec-3] [][] INFO CompleteOperationLogger:25 - {"action":"Complete","operation":"healthcheck","result":{"outcome":"Succeeded"},"metrics":{"delayBeforeExecution":0,"duration":0},"user":{},"tracking":{}}"}
Tag testing.deanm.json
[Filter]
Name Parser
Match *
Parser parse_common_fields
Key_Name log
[Filter]
Name Parser
Match *
Parser json
Key_Name log
[OUTPUT]
Name stdout
Match *
结果
parse_common_fields
过滤器在日志行上运行后,它成功地解析了公共字段,并且log
将是字符串或转义的json字符串
第一次通过
[0] testing.deanm.non-json: [1659045824.000000000, {"log_type"=>"http-nio-8080-exec-3", "transaction_id"=>"2a166faa-dbba-4210-a328-774861e3fdef", "transaction_id2"=>"0ed32f19-47bb-4c1f-92c2-c9b7c43aa91f", "level"=>"INFO", "service_id"=>"AnonymityService:245", "log"=>"Using decorator records threshold: 0"}]
[0] testing.deanm.json: [1659094619.000000000, {"log_type"=>"http-nio-8080-exec-3", "level"=>"INFO", "service_id"=>"CompleteOperationLogger:25", "log"=>"{"action":"Complete","operation":"healthcheck","result":{"outcome":"Succeeded"},"metrics":{"delayBeforeExecution":0,"duration":0},"user":{},"tracking":{}}"}]
一旦Filterjson
解析了日志,我们就成功地使JSON也正确解析了
第二遍
[0] testing.deanm.non-json: [1659045824.000000000, {"log_type"=>"http-nio-8080-exec-3", "transaction_id"=>"2a166faa-dbba-4210-a328-774861e3fdef", "transaction_id2"=>"0ed32f19-47bb-4c1f-92c2-c9b7c43aa91f", "level"=>"INFO", "service_id"=>"AnonymityService:245", "log"=>"Using decorator records threshold: 0"}]
[0] testing.deanm.json: [1659094619.000000000, {"action"=>"Complete", "operation"=>"healthcheck", "result"=>{"outcome"=>"Succeeded"}, "metrics"=>{"delayBeforeExecution"=>0, "duration"=>0}, "user"=>{}, "tracking"=>{}}]
注意:上面的result1和result2之间的区别在于,在第一次传递之后,json字符串仍然在日志对象中,而第二次传递则将json解析为自己的密钥,例如:
Pass1:
[1659094619.000000000, {"log"=>"{"action": {"Complete", ...
Pass2:
[1659094619.000000000, {"action"=>"Complete", ...
FluentBit没有看到这一点,但Fluentd:
- https://github.com/fluent/fluentd-kubernetes-daemonset
- https://github.com/repeatedly/fluent-plugin-multi-format-parser#configuration
注意,format none
作为最后一个选项意味着如果其他选项都不起作用,则保持日志行原样,例如明文。
您还可以使用FluentBit作为纯日志收集器,然后使用Fluentd进行单独的部署,该部署从FluentBit接收流、解析并执行所有输出。在FluentBit输出中使用type forward
,在Fluentd中使用源@type forward
。文档:https://docs.fluentbit.io/manual/pipeline/outputs/forward