Parsing Multiline Tomcat Exceptions with Fluent Bit - fluent-bit

Attempting to parse some Tomcat logs that contain log Exception messages using Fluent Bit but I am struggling to parse the multiline exception messages and logs into a single log entry. I can successfully parse the logs the way I desire, when the log is static and is not being written to and enabling read_from_head true; I can confirm this because this is what a sample output looks like (Exception is successfully written to one log entry).
{
"filename": "/opt/tomcat/catalina.out",
"fluentTimestamp": 1660079524549258200,
"hostname": "ip-172-22-11-142",
"msg": "com.sun.jersey.spi.container.ContainerResponse.mapMappableContainerException The exception contained within MappableContainerException could not be mapped to a response, re-throwing to the HTTP container\n\tjava.io.EOFException: No content to map to Object due to end of input\n\ blah blah blahg you get the idea",
"severity": "SEVERE",
"thread": "http-nio-8080-exec-4",
"timestamp": "09-Aug-2022 01:42:35.475"
}
But when I tail the file live, Fluent bit appears to ignore my parsing regex as I only get a "log" statement and none of the other fields. I'm assuming because the logs are partially being streamed and written and my regex is invalid. Here's a sample of my log file:
09-Aug-2022 06:36:45.901 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 18109 ms
09-Aug-2022 06:43:04.787 SEVERE [http-nio-8080-exec-2] com.sun.jersey.spi.container.ContainerResponse.mapMappableContainerException The exception contained within MappableContainerException could not be mapped to a response, re-throwing to the HTTP container
java.io.EOFException: No content to map to Object due to end of input
at org.codehaus.jackson.map.ObjectMapper._initForReading(ObjectMapper.java:2766)
at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2682)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1308)
at org.codehaus.jackson.jaxrs.JacksonJsonProvider.readFrom(JacksonJsonProvider.java:419)
at com.sun.jersey.json.impl.provider.entity.JacksonProviderProxy.readFrom(JacksonProviderProxy.java:139)
at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:490)
at com.sun.jersey.server.impl.model.method.dispatch.EntityParamDispatchProvider$EntityInjectable.getValue(EntityParamDispatchProvider.java:123)
at com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:86)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:153)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:203)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1542)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1473)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)
at java.base/java.lang.Thread.run(Thread.java:829)
09-Aug-2022 06:43:07.060 SEVERE [http-nio-8080-exec-3] com.sun.jersey.spi.container.ContainerResponse.mapMappableContainerException The exception contained within MappableContainerException could not be mapped to a response, re-throwing to the HTTP container
My config looks like this:
[SERVICE]
flush 5
daemon Off
log_level debug
parsers_file parsers.conf
[INPUT]
name tail
tag tomcat
path /opt/tomcat/catalina.out
multiline on
parser_firstline java_multiline
mem_buf_limit 5MB
skip_long_lines on
#read_from_head true
refresh_interval 10
[FILTER]
Name record_modifier
Match *
Record hostname ${HOSTNAME}
[OUTPUT]
name http
match *
host somelocation
My parser config:
[PARSER]
Name java_multiline
Format regex
Regex (?<timestamp>([012][0-9])-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\d\d\d\d [012]\d:[0-6]\d:[0-6]\d\.\d\d\d)\s(?<severity>[^\s]+)\s\[(?<thread>[^\]]+)\]\s(?<msg>[^*]+)
I also tried to do a multiline parser but still to no avail:
[MULTILINE_PARSER]
name multiline-regex-test
type regex
flush_timeout 1000
#
# Regex rules for multiline parsing
# ---------------------------------
#
# configuration hints:
#
# - first state always has the name: start_state
# - every field in the rule must be inside double quotes
#
# rules | state name | regex pattern | next state
# ------|---------------|--------------------------------------------
rule "start_state" "/([012][0-9])-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\d\d\d\d [012]\d:[0-6]\d:[0-6]\d\.\d\d\d/" "cont"
rule "cont" "/[^\t].+/" "cont"
Again, it works fine when parsing it statically but doesn't seem to work when I'm tailing the file live. Is there something I'm missing here?

What version are you using? If using 1.8+ then use the built-in java parser. See https://docs.fluentbit.io/manual/pipeline/inputs/tail#multiline-support
[INPUT]
name tail
...
multiline.parser java

Related

Biztalk Server 2020: Invalid Character found

When sending EDI INVOIC I receive the following error:
Uncaught exception (see the 'inner exception' below) has suspended an instance of service 'Microsoft.BizTalk.Edi.BatchSuspendOrchestration.BatchElementSuspendService(52b477a6-f224-d7ee-a40d-92c8ad5f5544)'.
The service instance will remain suspended until administratively resumed or terminated.
If resumed the instance will continue from its last persisted state and may re-throw the same unexpected exception.
InstanceId: 2194c57a-bdb1-4bb7-9c7b-9e6f884af3a2
Shape name: Throw that an error has occured
ShapeId: 209c5624-f52a-404d-b44d-d8fb41b0fed4
Exception thrown from: segment 2, progress 33
Inner exception: The batch element is being suspended as it either failed schema validation or context properties are not matching batch definition. The error is : Stopping after the first error !!
Error: 1 (Field level error)
SegmentID: FTX
Position in TS: 5
Data Element ID: C10801
Position in Segment: 5
Position in Field: 1
Data Value: Bezüglich der späteren Entgeltminderung verweisen wir auf die
21:
This happens only by two out three identities of the partner and only it the text contains umlauts. Only this partner has this problem, every other partner is not affected.
I've change everything, change encoding, ports, etc.
I ended up deleting the business profiles and agreements, and recreating them with the same settings. That solved my problem but it would be good to know why it didn't work from the beginning.
EDI Character Sets (Microsoft.com)
An EDIFACT-encoded interchange is self-describing in terms of its character set. The UNB1 data element is used. EDIFACT requires that tag names and separators/delimiters are ASCII types; as a result, locating UNB1 to apply the relevant code page for the remaining interchange is possible.
So check the UNB1, and I think you will find that it in probably UNOA or UNOB that don't support those characters. If it is, then your partner needs to update it at their end to have the correct character encoding set in the payload.
See also EDIFACT Encoding – EDI Character Set Support (Sandro Pereira's blog)

Configure Fluentbit "Docker Json parse depth"

Using one of these parser plugin configurations:
[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 do_next
Decode_Field_As json log
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
Is it possible to determine the depth to which the the plugin parses fields.
To make that more clear,
Let's say that you're trying to log an HTTP response from a Docker container containing a large body with multiple items.
Fluentbit should parse the Docker log, which it does. Great.
But it shouldn't be parsing the entire body as well.
I don't want 1000 fields in Elasticsearch, because it's trying to parse all items in my response body too.
{
"length":"value",
"timestamp":"timestamp",
"items": [
{...},
{...},
{...},
...
]
}
Is there any way to configure the depth to which Fluentbit will parse JSON?
Thanks!

Crystal-lang no overload matches 'HTTP::Server.new' with type Int32 http server

I'm a newbie to Crystal-lang.
I'm trying the Http Server example given in the crystal-lang docs.
require "http/server"
server = HTTP::Server.new(8080) do |context|
context.response.content_type = "text/plain"
context.response.print "Hello world! The time is #{Time.now}"
end
puts "Listening on http://127.0.0.1:8080"
server.listen
When I run this code I'm getting the following error.
Error in httpserv.cr:3: no overload matches 'HTTP::Server.new' with type Int32
Overloads are:
- HTTP::Server.new(handlers : Array(HTTP::Handler), &handler)
- HTTP::Server.new(&handler)
- HTTP::Server.new(handlers : Array(HTTP::Handler))
- HTTP::Server.new(handler : HTTP::Handler | HTTP::Handler::Proc)
server = HTTP::Server.new(8080) do |context|
What I can gather from this is I need to specify some methods/functions for handling the HTTP requests, but I'm not getting how to do that.
What is the correct way to do that is my question?
Thanks in advance.
The HTTP::Server API has changed in the latest release Crystal 0.25.0. It's use is documented in the recent API docs (the 0.25.0 release docs have a slight error, but it's fixed on master).
As you can see from the error message, the signature of Server.new has changed. It now only accepts some form of handler. You already have that defined in your example in the do block. The constructor no longer accepts a port number, but you need to call #bind_tcp seperately.
Your example should now look like this:
require "http/server"
server = HTTP::Server.new do |context|
context.response.content_type = "text/plain"
context.response.print "Hello world! The time is #{Time.now}"
end
address = server.bind_tcp 8080
puts "Listening on http://#{address}"
server.listen

Robot Framework Getting Keyword failure reason

Trying to implement a listener interface for robot framework in order to collect information about keyword executions like time taken for execution, Pass/Fail status, failure message in case if status is fail. Sample code is given below
import os.path
import tempfile
class PythonListener:
ROBOT_LISTENER_API_VERSION = 2
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
def __init__(self, filename='listen.txt'):
outpath = os.path.join(tempfile.gettempdir(), filename)
self.outfile = open(outpath, 'w')
def end_keyword(self, name, attrs):
self.outfile.write(name + "\n")
self.outfile.write(str(attrs) + "\n")
def close(self):
self.outfile.close()
All the information apart from keyword failure message is available in the attributes which is passed to end_test method from robot framework.
Documentation can be found here. https://github.com/robotframework/robotframework/blob/master/doc/userguide/src/ExtendingRobotFramework/ListenerInterface.rst#id36
The failure message is available in the attributes for end_test() method. But this will not have information if a keyword is run using RunKeywordAndIgnoreError.
I could see that there is a special variable ${KEYWORD MESSAGE} in robot framework, which contains the possible error message of the current keyword Is it possible to access this variable in the listener class.?
https://github.com/robotframework/robotframework/blob/master/doc/userguide/src/CreatingTestData/Variables.rst#automatic-variables
Are there any other ways to collect the failure message information at the end of every keyword?
That's an interesting approach, indeed, end_test will ensure an attributes.message field containing the failure. (so it goes for end_suite if it fails during the suite setup/teardown)
With end_keyword you don't have such message, but at least you can filter for the FAIL status and detect which one failed. Then the message returned by Run Keyword And Ignore Error has to be logged explicitly by you so you can capture such triggering logs with the log_message hook. Otherwise nobody is aware of the message of the exception handled by the wrapper keyword which returns a tuple of (status, message).
There's also the message hook but couldn't manage to get it called from a normal breaking robot:
Called when the framework itself writes a syslog message.
message is a dictionary with the same contents as with log_message method.
Side note: To not expose these hooks as keywords, you can precede the method names with _. Examples:
def _end_test(self, name, attributes): ...
def _log_message(self, message): ...

Benchmarking Solr indexing with Jmeter

I want to use Jmeter to update a document on solr using http post.
I want it to take a different file to update in every iteration, create a proper http post request and monitor the responses from the server.
Can someone guide me of how this can be done:
Taking a different file every time.
Creating a http post from it.
Your use case can be split into 2 parts:
Get list of files to send
Send them to server
In regards to point 1, I would suggest to obtain file list via scripting.
Assuming following Test Plan Structure:
Add a Thread Group (all defaults)
Add a JSR223 Sampler as a child of Thread Group
Select "beanshell" as language
In "Script" area add following code:
File folder = new File("PATH TO FOLDER WITH YOUR FILES");
File [] files2send = folder.listFiles();
int counter = 1;
for (File file : files2send)
{
vars.put("FILE_" + counter, file.getPath());
counter++;
}
This will save files, you will be sending as JMeter Variables like:
FILE_1=d:\2solr\sometxtfile.txt
FILE_2=d:\2solr\somewordfile.docx
FILE_3=d:\2solr\someexcelfile.xlsx
After that you can use For Each Controller to iterate through files and add them to your request
Add For Each Controller as a child of Thread Group (same level as JSR223 Sampler)
Make sure that For Each Controller has following configuration:
Input variable prefix: FILE
Output variable name: CURRENTFILE
Add _ before number is checked
Add HTTP Request as a child of For Each Controller
Access file you want to send as ${CURRENTFILE} in "Send Files With The Request" stanza of the HTTP Request
It's just one of the approaches, if you are not very comfortable with JSR233 or Beanshell you may wish to use CSV Data Set Config instead.

Resources