Closed marckamerbeek closed 6 years ago
hi @marckamerbeek
there are two approaches;
Fluent Bit 0.12: this is the actual stable version and the filter_kubernetes only allows to take the raw log message (without parsing) or parse it when the message comes as a JSON map. Of course this is not so ideal since not all applications generate logs in JSON format.
Fluent Bit 0.13: this is the actual development version which we aim to release on January 31 if everything is fine with testing and QA. The major feature here is that in your application Pod definition you can "suggest" a parser for the log processor, e.g: if you are going to deploy a Pod which is Apache web server, in the annotations you specify "logging.parser: apache", so the log processor will lookup that parser definition and apply it for the specific log entries for that container.
If you want to experiment with #2 and also help us with testing, please refer to the instructions sent to the Google group this week:
https://groups.google.com/forum/?hl=en#!topic/fluent-bit/Va2gsviVaRE
please let me know how that goes.
Wow...thats exactly what we had in mind. We have a story on the backlog to build a new plugin that does that. That saves us a lot of work! We are not familiar with building plugins in C.
Ofcourse I want to experiment with that. I'll keep you posted.
And what about multi format log files? Like kubernetes nginx-ingress-controller logs. That has 3 different formats in one log file. Like Access logs, Go and another one. Or am I asking to much now...:-)
Ofcourse I want to experiment with that. I'll keep you posted.
great :)
And what about multi format log files? Like kubernetes nginx-ingress-controller logs. That has 3 different formats in one log file. Like Access logs, Go and another one. Or am I asking to much now...:-)
oh, I did not think about that specific use case, which can happen on any multi-container Pod. Likely the solutions seems to be around let the Pod suggest multiple parsers and let Fluent Bit process that. It's not that good in terms of performance but something that needs to be solved in some way.
Well, actually its not a multicontainer pod. Its just one container spitting out all different formats to stdout. We also got some python containers doing the same. Fluentd got that multi format plugin (https://github.com/repeatedly/fluent-plugin-multi-format-parser) which does the thing. But I can imagine that will have some performance issues running through those regexes.
I discussed your solution with some colleague's mentioned in 2. It's nice to have an annotation to define the parser that is needed. But wouldn't it be nice to define your own regex so development teams can determine their own format? Like an adding a regex with an annotation. Or two options. One custom and one predefined.
Like:
apiVersion: v1 kind: Pod metadata: name: apache-logs namespace: default annotations: logging.parser: apache logging.parser.regex: /...your regexp pattern.../ spec: containers: name: apache-logs image: edsiper/apache_logs imagePullPolicy: Always restartPolicy: Always
Actually I hear that idea recently from a conference attendee, initially I discarded that approach because of performance reasons, but as you said, the benefit of that solutions pays-off the cost of solving the log processing problem for multiple formats.
The cost associated is to compile the regular expression when Fluent Bit filter gather the metadata, of course this is just one time procedure while the regex keeps in the metadata cache.
I will think more about how to implement it properly..
Likely the solutions seems to be around let the Pod suggest multiple parsers and let Fluent Bit process that. It's not that good in terms of performance but something that needs to be solved in some way.
Can you just allow for annotations at the container level rather than at the pod level?
@derekperkins would you please provide an example of a Pod with annotations at container level ?, I cannot find a reference.
@edsiper My bad, I thought they were supported. I think there's an opportunity to do the same thing at the pod annotation level. It's valid to nest json inside of an annotation: https://github.com/kubernetes/kubernetes/issues/12226#issuecomment-173481190
What if the current implementation of a string stayed the same for the common use case, but also supported a json mapping?
logging.parser: >
{
"container1": "apache",
"container2": "nginx",
"container3": "mysql-slow"
...
}
I'm not sure if it would be preferable to do it all with the same logging.parser
key or whether to support a separate key like logging.parsers
or logging.containerParsers
, but that shouldn't impact the usability.
@edsiper any thoughts on that proposal?
In general it would be better to have multiple annotations for each container and to follow a more common annotation style.
Something like this:
fluent-bit.io/parsers/container/apache-app: "apache"
fluent-bit.io/parsers/container/nginx-proxy: "nginx"
fluent-bit.io/parsers/container/dbcontainer: "mysql-slow"
The same thing could leave you open to custom regex parsers through annotations
@bigkraig I like that syntax a lot
I just tested the dev-13 version with kubernetes and set the annotation and got the message parsed as expected.
The only thing missing is multiline support, with docker, the message is split into multiple JSON lines as below
@shahbour For a java application please try specifying the annotation as "logging.parser: java_multiline" and see if this works.
@StevenACoffman will this work even we are receiving them as multiple lines from docker?
@shahbour It depends on whether the kubernetes filter parser is operating on a stream, or on each discrete message. I'd be interested in seeing the result.
As I am using my own regex (custom logging) so I changed it to be like java_multiline
[PARSER]
Name java_multiline
Format regex
Regex /^(?<time>\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}) \[(?<thread>.*)\] (?<level>[^\s]+)(?<message>.*)/
Time_Key time
Time_Format %Y-%m-%d %H:%M:%S
[PARSER]
Name springboot
Format regex
Regex /^(?<date>[0-9]+-[0-9]+-[0-9]+\s+[0-9]+:[0-9]+:[0-9]+.[0-9]+)\s+\[(?<user_name>.*)\]\s+(?<log_level>[Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?)\s+(?<pid>[0-9]+)\s+---\s+\[(?<thread>.*)\]\s+(?<class_name>.*)\s+:\s+(?<message>.*)$/
Time_Key date
Time_Format %Y-%m-%d
Still, I got each message by itself on elasticsearch
FYI: Multiline inside a JSON key/value is not supported, only at raw text level for now.
I've been struggling with java multiline in combination with the json from docker logs. That json needs to be parsed with a json parser. But with "Multiline On" in the tail plugin, the json parser will be ommited.
My solution was to let my Java (Springboot) log in json format. Multiline will work out of the box since its wrapped in json. To let Springboot log in json:
Add a logback.xml with the following XML:
<configuration>
<appender name="consoleAppender"
class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<fieldNames>
<timestamp>application_timestamp</timestamp>
</fieldNames>
</encoder>
</appender>
<logger name="jsonLogger" additivity="false" level="DEBUG">
<appender-ref ref="consoleAppender" />
</logger>
<root level="INFO">
<appender-ref ref="consoleAppender" />
</root>
</configuration>
And add the following dependency:
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>4.7</version>
</dependency>
To make sure your log in Kibana is dealing the line endings correctly of the stacktrace add "Decodedas String" is added to your configuration
Configuration:
[SERVICE]
Flush 1
Daemon Off
Log_Level debug
Parsers_File parsers_custom.conf
[INPUT]
Buffer_Chunk_Size 400k
Buffer_Max_Size 5MB
DB /var/log/containers/fluent-bit-online-tst.db
Mem_Buf_Limit 5MB
Name tail
Parser docker
Path /var/log/containers/*.log
Refresh_Interval 5
Tag kube.spring.*
[FILTER]
K8S-Logging.Parser Off
Kube_URL https://${KUBERNETES_SERVICE_HOST}:443
Match kube.*
Merge_JSON_Log On
Name kubernetes
tls.verify Off
[OUTPUT]
Name es
Match *
Host xxx.xxx.xxx.xxx
Port 9200
Logstash_Format On
Logstash_Prefix kubernetes-2-tst
Include_Tag_Key true
Retry_Limit False
[PARSER]
Decode_Field_As escaped log
Format json
Name docker
Time_Format %Y-%m-%dT%H:%M:%S %z
Time_Key time
Thanks for the hint, I just updated the logback-spring.xml so it changes based on environment
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<fieldNames>
<timestamp>application_timestamp</timestamp>
</fieldNames>
</encoder>
</appender>
<root level="INFO">
<springProfile name="!kubernetes">
<appender-ref ref="CONSOLE" />
</springProfile>
<springProfile name="kubernetes">
<appender-ref ref="consoleAppender"/>
</springProfile>
</root>
</configuration>
Haha...well thats what we discussed yesterday here to implement. That makes the log human readable locally. Thanks for the code example!
One more note: I override the timestamp with "application_timestamp" (See logback xml) due to a duplicate key exception in Elastic. Fluent bit adds the time key aswell.
@marckamerbeek with Fluent Bit 0.13 (to be released next Monday) you can workaround the problem setting up specific Pod annotations describing the pre-defined parser to be used.
Is there any doc on this awesome feature?
I enabled it for our nginx ingress controller, but it doesn't work.
$ kubectl -n ingress-nginx describe pod nginx-ingress-controller-b878b75bf-cmqzs
Name: nginx-ingress-controller-b878b75bf-cmqzs
Namespace: ingress-nginx
Node: ip-10-10-1-231.us-west-2.compute.internal/10.10.1.231
Start Time: Tue, 14 Aug 2018 18:39:49 +0800
Labels: app=ingress-nginx
pod-template-hash=643463169
Annotations: fluentbit.io/parser=nginx
prometheus.io/port=10254
prometheus.io/scrape=true
I install fluent-bit by:
$ helm --kube-context $CONTEXT install --namespace $NAMESPACE --name fluent-bit stable/fluent-bit --set backend.type=es,backend.es.host=elasticsearch-client
the installed version is 0.13.0
$ kubectl -n logging describe pod fluent-bit-lwzxp
Name: fluent-bit-lwzxp
Namespace: logging
Node: ip-10-10-1-231.us-west-2.compute.internal/10.10.1.231
Start Time: Tue, 14 Aug 2018 17:24:58 +0800
Labels: app=fluent-bit-fluent-bit
controller-revision-hash=2471733741
pod-template-generation=1
release=fluent-bit
Annotations: checksum/config=d7eceedd9eca0f295eb455f0b1b10f6a3ae253b88513025a0f67613873f92d36
Status: Running
IP: 10.10.1.25
Controlled By: DaemonSet/fluent-bit
Containers:
fluent-bit:
Container ID: docker://34d4294d8b404745f171789adc00846970102af5328aa97ead72415ea7f34f1b
Image: fluent/fluent-bit:0.13.0
Image ID: docker-pullable://fluent/fluent-bit@sha256:313b51885c3524cca9c7fa2c68ea3afce47fd4d22ab7820334cc4cf4764de6f3
Port: <none>
Host Port: <none>
State: Running
Started: Tue, 14 Aug 2018 17:25:02 +0800
Ready: True
Restart Count: 0
Limits:
memory: 100Mi
Requests:
cpu: 100m
memory: 100Mi
Environment: <none>
Thanks.
@edsiper cloud you help me?
I would be glad to help you, but I'm missing your fluentbit config. You have to add the kubernetes filter and turn on the parser:
K8S-Logging.Parser: On
@marckamerbeek thanks for you help.
I turn on the parser, but still no lucky. This is my fluent-bit configmap
apiVersion: v1
data:
fluent-bit.conf: |-
[SERVICE]
Flush 1
Daemon Off
Log_Level info
Parsers_File parsers.conf
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.*
Refresh_Interval 5
Mem_Buf_Limit 5MB
Skip_Long_Lines On
[FILTER]
Name kubernetes
Match kube.*
Kube_URL https://kubernetes.default.svc:443
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
K8S-Logging.Parser On
[OUTPUT]
Name es
Match *
Host elasticsearch-client
Port 9200
Logstash_Format On
Retry_Limit False
Type flb_type
Logstash_Prefix kubernetes_cluster
parsers.conf: ""
kind: ConfigMap
metadata:
creationTimestamp: 2018-08-14T09:24:58Z
labels:
app: fluent-bit-fluent-bit
chart: fluent-bit-0.8.0
heritage: Tiller
release: fluent-bit
name: fluent-bit-fluent-bit-config
namespace: logging
resourceVersion: "13114430"
selfLink: /api/v1/namespaces/logging/configmaps/fluent-bit-fluent-bit-config
uid: e99029eb-9fa3-11e8-b731-02107822efe8
or any document on this is appreciated.
You must define a parser with the name "nginx" as you mentioned in your annotation.
Be aware that parsing a nginx log could be quite expensive with a regex. My nginx-ingress-controller is logging in json. This can be forwarded to elastic one on one. You can configure your nginx to log in json.
This is my configuration (from a helm chart, but the values are the same):
inputs:
- Name: tail
Path: "/var/log/containers/*.log"
Exclude_Path: "*kube-system*.log"
Refresh_Interval: "5"
Mem_Buf_Limit: "25MB"
Tag: "kube.services.*"
Parser: docker
Buffer_Max_Size: "25MB"
Buffer_Chunk_Size: "1MB"
Skip_Long_Lines: "On"
DB: "/var/log/containers/fluent-bit.db"
## Special tail for nginx logging since *kube-system* is excluded in the tail above. (nginx is part of kube-system)
- Name: tail
Path: "/var/log/containers/*nginx*.log"
Refresh_Interval: "5"
Mem_Buf_Limit: "25MB"
Tag: "kube.ingress.*"
Parser: docker
Buffer_Max_Size: "25MB"
Buffer_Chunk_Size: "1MB"
Skip_Long_Lines: "On"
DB: "/var/log/containers/fluent-bit-nginx.db"
# Filters configuration
# This kubernetes filter is able to pickup an annotation from your pod:
# spec:
# template:
# metadata:
# annotations:
# fluentbit.io/parser: "json"
#
# This annotation suggests fluent-bit to use (in this case) the json parser (defined below)
filters:
- Name: "kubernetes"
Match: "kube.*"
tls.verify: "Off"
Kube_URL: "https://${KUBERNETES_SERVICE_HOST}:443"
Merge_JSON_Log: "On"
K8S-Logging.Parser: "On"
K8S-Logging.exclude: "True"
outputs:
- Name: "es"
Match: kube.services.*
Host: "x.x.x.x"
Port: "9200"
Logstash_Format: "On"
Logstash_Prefix: "k8s-services-prd"
Logstash_DateFormat: "%G.%V"
Include_Tag_Key: "true"
Retry_Limit: "False"
- Name: "es"
Match: kube.ingress.*
Host: "x.x.x.x"
Port: "9200"
Logstash_Format: "On"
Logstash_Prefix: "k8s-ingress-prd"
Logstash_DateFormat: "%G.%V"
Include_Tag_Key: "true"
Retry_Limit: "False"
parsers:
custom:
- Name: json
Format: json
Time_Key: time
Time_Format: "%Y-%m-%dT%H:%M:%S.%L"
Decode_Field_As: "escaped log"
- Name: docker
Format: json
Time_Key: time
Time_Format: "%Y-%m-%dT%H:%M:%S.%L"
Time_Keep: On
Decode_Field_As: "escaped log"
@marckamerbeek Tanks for your suggesion, I will try that later. for K8S-Logging.Parser
, I still have problem, here's my fluent-bit config:
fluent-bit.conf:
[SERVICE]
Flush 1
Daemon Off
Log_Level info
Parsers_File parsers.conf
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.*
Refresh_Interval 5
Mem_Buf_Limit 5MB
Skip_Long_Lines On
[FILTER]
Name kubernetes
Match kube.*
Kube_URL https://kubernetes.default.svc:443
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
# Merge_Log On
K8S-Logging.Parser On
[OUTPUT]
Name es
Match *
Host elasticsearch-client
Port 9200
Logstash_Format On
Retry_Limit False
Time_Key @datetime
Type flb_type
Logstash_Prefix kubernetes_cluster
parsers.conf
[PARSER]
Name apache
Format regex
Regex ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
Time_Key time
Time_Format %d/%b/%Y:%H:%M:%S %z
[PARSER]
Name apache2
Format regex
Regex ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
Time_Key time
Time_Format %d/%b/%Y:%H:%M:%S %z
[PARSER]
Name apache_error
Format regex
Regex ^\[[^ ]* (?<time>[^\]]*)\] \[(?<level>[^\]]*)\](?: \[pid (?<pid>[^\]]*)\])?( \[client (?<client>[^\]]*)\])? (?<message>.*)$
[PARSER]
Name nginx
Format regex
Regex ^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
Time_Key time
Time_Format %d/%b/%Y:%H:%M:%S %z
[PARSER]
Name json
Format json
Time_Key time
Time_Format %d/%b/%Y:%H:%M:%S %z
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
# Command | Decoder | Field | Optional Action
# =============|==================|=================
Decode_Field_As escaped log
[PARSER]
Name docker-daemon
Format regex
Regex time="(?<time>[^ ]*)" level=(?<level>[^ ]*) msg="(?<msg>[^ ].*)"
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
[PARSER]
Name syslog-rfc5424
Format regex
Regex ^\<(?<pri>[0-9]{1,5})\>1 (?<time>[^ ]+) (?<host>[^ ]+) (?<ident>[^ ]+) (?<pid>[-0-9]+) (?<msgid>[^ ]+) (?<extradata>(\[(.*)\]|-)) (?<message>.+)$
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
[PARSER]
Name syslog-rfc3164-local
Format regex
Regex ^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$
Time_Key time
Time_Format %b %d %H:%M:%S
Time_Keep On
[PARSER]
Name syslog-rfc3164
Format regex
Regex /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
Time_Key time
Time_Format %b %d %H:%M:%S
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
[PARSER]
Name mongodb
Format regex
Regex ^(?<time>[^ ]*)\s+(?<severity>\w)\s+(?<component>[^ ]+)\s+\[(?<context>[^\]]+)]\s+(?<message>.*?) *(?<ms>(\d+))?(:?ms)?$
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
Time_Key time
[PARSER]
Name kube-custom
Format regex
Regex var\.log\.containers\.(?<pod_name>[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<namespace_name>[^_]+)_(?<container_name>.+)-(?<docker_id>[a-z0-9]{64})\.log$
[PARSER]
Name filter-kube-test
Format regex
Regex .*kubernetes.(?<pod_name>[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<namespace_name>[^_]+)_(?<container_name>.+)-(?<docker_id>[a-z0-9]{64})\.log$
and here's a sample pod:
apiVersion: v1
kind: Pod
metadata:
name: apache-logs
annotations:
fluentbit.io/parser: apache
labels:
app: apache-logs
spec:
containers:
- name: apache-logs
image: edsiper/apache_logs
imagePullPolicy: Always
restartPolicy: Always
and no log is parsed as shown from kibana:
{
"_index": "kubernetes_cluster-2018.08.28",
"_type": "flb_type",
"_id": "VRJ0f2UBf6UOjByGBs65",
"_version": 1,
"_score": null,
"_source": {
"@datetime": "2018-08-28T07:33:54.808Z",
"log": "245.152.66.117 - - [28/Aug/2018: 7:33:54 +0000] \"GET /carbamate HTTP/1.0\" 204 2216\n",
"stream": "stdout",
"time": "2018-08-28T07:33:54.808729434Z",
"kubernetes": {
"pod_name": "apache-logs",
"namespace_name": "default",
"pod_id": "64eb5068-aa93-11e8-b731-02107822efe8",
"labels": {
"app": "apache-logs"
},
"annotations": {
"fluentbit_io/parser": "apache"
},
"host": "ip-10-10-1-231.us-west-2.compute.internal",
"container_name": "apache-logs",
"docker_id": "7344df5240492d1cedcfc5424d80617c20679003cb9990312b62512e2d333303"
}
},
"fields": {
"time": [
"2018-08-28T07:33:54.808Z"
],
"@datetime": [
"2018-08-28T07:33:54.808Z"
]
},
"highlight": {
"kubernetes.labels.app": [
"@kibana-highlighted-field@apache@/kibana-highlighted-field@-@kibana-highlighted-field@logs@/kibana-highlighted-field@"
]
},
"sort": [
1535441634808
]
}
It's really bad without document, I'm about give up this week.
If I use your regex in a regex tester and take the log line in your Kibana output, its not matching. I checked this on regex101.com
Have you checked your fluent-bit logging (/var/log/containers) on parsing errors?
Fluentbit has a default apache parser: https://fluentbit.io/documentation/current/parser/
Can't you use this one first? Or take a very simple regex that at least matches something?
The log field from kibana is escaped, I can parse raw log:
214.23.247.34 - - [29/Aug/2018: 5:26:52 +0000] "GET /carpetbags HTTP/1.0" 500 2216
with:
[PARSER]
Name apache
Format regex
Regex ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
Time_Key time
Time_Format %d/%b/%Y:%H:%M:%S %z
Does your K8S-Logging.Parser On
work as expect? Then I may miss some important config.
Please check the following documentation, if possible try the test case described at bottom:
https://docs.fluentbit.io/manual/filter/kubernetes#kubernetes-annotations
I found a nice solution for the multiple line java exception 1- Convert the new line in exception to \u000d (new line in unicode) , for a spring boot application this can easily be done by setting the pattern to
%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%replace(%wEx){'\n','\u000d'}%nopex%n
the important and only new part is this %replace(%wEx){'\n','\u000d'}%nopex%
where we did replace \n
For other Java application, you can follow this link
2- In Parser, I used escaped_utf8 decoding like below
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
# Command | Decoder | Field | Optional Action
# =============|==================|=================
Decode_Field_As escaped_utf8 log
Now exception is logged perfectly in elastic search with new line and one entry .
@shahbour Nice job finding this creative solution!
I changed all the springboot logging to json so this will not help me, but certainly other people! Be aware that parsing Java logging with regex is more cpu expensive!
Multiple formats already supported (still need improvement in multiline stuff).
Closing this thread as the initial issue is fixed.
@edsiper We are talking here about multiline on docker json logs , can you please show us how it is supported ?
Hi, We run Kubernetes 1.8.1 on premise and start using fluent-bit as log forwarder to elastic search. There are running 600+ docker containers with all kinds of technologies. Java, Spring boot, Python, NodeJS etc...
How should my config look like? Do I need all kind of different tail inputs? Or just *.log tail input and go through all the filters with all kind of different parsers with regexes (performance wise not a good idea I think)?
Am I the only one with this question or I really have no clue how fluent-bit should work.