Logstash: Custom delimiter for multi-line XML logs - logstash

I have XML logs where logs are closed with "=======", e.g.
<log>
<level>DEBUG</level>
<message>This is debug level</message>
</log>
=======
<log>
<level>ERROR</level>
<message>This is error level</message>
</log>
=======
Every log can span across multiple lines.
How to parse those logs using logstash?

This can be done using multiline codec. The delimiter "=======" can be used in pattern like this
input {
file {
type => "xml"
path => "/path/to/logs/*.log"
codec => multiline {
pattern => "^======="
negate => "true"
what => "previous"
}
}
}
filter {
mutate {
gsub => [ "message", "=======", ""]
}
xml {
force_array => false
source => "message"
target => "log"
}
mutate {
remove_field => [ "message" ]
}
}
output {
elasticsearch {
codec => json
hosts => ["http://localhost:9200"]
index => "logs-%{+YYYY.MM.dd}"
}
}
Here the combination of pattern and negate => true means: if a line does not start with "=======" it belongs to the previous event (thus what => "previous"). When a line with the delimiter is hit, we start a new event. In the filter the delimiter is simply removed with gsub and XML is parsed with xml plugin.

Related

Retrieving RESTful GET parameters in logstash

I am trying to get logstash to parse key-value pairs in an HTTP get request from my ELB log files.
the request field looks like
http://aaa.bbb/get?a=1&b=2
I'd like there to be a field for a and b in the log line above, and I am having trouble figuring it out.
My logstash conf (formatted for clarity) is below which does not load any additional key fields. I assume that I need to split off the address portion of the URI, but have not figured that out.
input {
file {
path => "/home/ubuntu/logs/**/*.log"
type => "elb"
start_position => "beginning"
sincedb_path => "log_sincedb"
}
}
filter {
if [type] == "elb" {
grok {
match => [ "message", "%{TIMESTAMP_ISO8601:timestamp}
%{NOTSPACE:loadbalancer} %{IP:client_ip}:%{NUMBER:client_port:int}
%{IP:backend_ip}:%{NUMBER:backend_port:int}
%{NUMBER:request_processing_time:float}
%{NUMBER:backend_processing_time:float}
%{NUMBER:response_processing_time:float}
%{NUMBER:elb_status_code:int}
%{NUMBER:backend_status_code:int}
%{NUMBER:received_bytes:int} %{NUMBER:sent_bytes:int}
%{QS:request}" ]
}
date {
match => [ "timestamp", "ISO8601" ]
}
kv {
field_split => "&?"
source => "request"
exclude_keys => ["callback"]
}
}
}
output {
elasticsearch { host => localhost }
}
kv will take a URL and split out the params. This config works:
input {
stdin { }
}
filter {
mutate {
add_field => { "request" => "http://aaa.bbb/get?a=1&b=2" }
}
kv {
field_split => "&?"
source => "request"
}
}
output {
stdout {
codec => rubydebug
}
}
stdout shows:
{
"request" => "http://aaa.bbb/get?a=1&b=2",
"a" => "1",
"b" => "2"
}
That said, I would encourage you to create your own versions of the default URI patterns so that they set fields. You can then pass the querystring field off to kv. It's cleaner that way.
UPDATE:
For "make your own patterns", I meant to take the existing ones and modify them as needed. In logstash 1.4, installing them was as easy as putting them in a new file the 'patterns' directory; I don't know about patterns for >1.4 yet.
MY_URIPATHPARAM %{URIPATH}(?:%{URIPARAM:myuriparams})?
MY_URI %{URIPROTO}://(?:%{USER}(?::[^#]*)?#)?(?:%{URIHOST})?(?:%{MY_URIPATHPARAM})?
Then you could use MY_URI in your grok{} pattern and it would create a field called myuriparams that you could feed to kv{}.

logstash : how to extract data from log4j message?

I try to extract data from my log4j message with logstash.
The message look like this :
Method findAll - Start by : bokc
I would like to extract the method name : "findAll" and the user "bokc".
How can I do this?
I use logstash 1.5.2 and my config is :
input {
log4j {
mode => "server"
type => "log4j-artemis"
port => 4560
}
}
filter {
multiline {
type => "log4j-artemis"
pattern => "^\\s"
what => "previous"
}
mutate {
add_field => [ "source_ip", "%{host}" ]
}
}
Use a grok filter:
filter {
grok {
match => [
"message",
"^Method %{WORD:method} - Start by : %{USER:user}"
]
tag_on_failure => []
}
}
This extracts the two words into the fields "method" and "user". The setting of tag_on_failure makes sure that non-matching messages aren't tagged with _grokparsefailure. Since most messages aren't supposed to match the pattern it doesn't make sense to mark them as failures.

logstash output not showing the desired timestamp

I am trying to get the desired time stamp format from logstash output. I can''t get that if I use this format in syslog
Please share your thoughts about convert to the other format that’s in the _source field like Yyyy-mm-ddThh:mm:ss.sssZ format?
filter {
grok {
match => [ "logdate", "Yyyy-mm-ddThh:mm:ss.sssZ" ]
overwrite => ["host", "message"]
}
_source: {
message: "activity_log: {"created_at":1421114642210,"actor_ip":"192.168.1.1","note":"From system","user":"4561c9d7aaa9705a25f66d","user_id":null,"actor":"4561c9d7aaa9705a25f66d","actor_id":null,"org_id":null,"action":"user.failed_login","data":{"transaction_id":"d6768c473e366594","name":"user.failed_login","timing":{"start":1422127860691,"end":14288720480691,"duration":0.00257},"actor_locatio
I am using this code in syslog file
filter {
if [message] =~ /^activity_log: / {
grok {
match => ["message", "^activity_log: %{GREEDYDATA:json_message}"]
}
json {
source => "json_message"
remove_field => "json_message"
}
date {
match => ["created_at", "UNIX_MS"]
}
mutate {
rename => ["[json][repo]", "repo"]
remove_field => "json"
}
}
}
output {
elasticsearch { host => localhost }
stdout { codec => rubydebug }
}
thanks
"message" => "<134>feb 1 20:06:12 {\"created_at\":1422765535789, pid=5450 tid=28643 version=b0b45ac proto=http ip=192.168.1.1 duration_ms=0.165809 fs_sent=0 fs_recv=0 client_recv=386 client_sent=0 log_level=INFO msg=\"http op done: (401)\" code=401" }
"#version" => "1",
"#timestamp" => "2015-02-01T20:06:12.726Z",
"type" => "activity_log",
"host" => "192.168.1.1"
The pattern in your grok filter doesn't make sense. You're using a Joda-Time pattern (normally used for the date filter) and not a grok pattern.
It seems your message field contains a JSON object. That's good, because it makes it easy to parse. Extract the part that comes after "activity_log: " to a temporary json_message field,
grok {
match => ["message", "^activity_log: %{GREEDYDATA:json_message}"]
}
and parse that field as JSON with the json filter (removing the temporary field if the operation was successful):
json {
source => "json_message"
remove_field => ["json_message"]
}
Now you should have the fields from the original message field at the top level of your message, including the created_at field with the timestamp you want to extract. That number is the number of milliseconds since the epoch so you can use the UNIX_MS pattern in a date filter to extract it into #timestamp:
date {
match => ["created_at", "UNIX_MS"]
}

Facing errors in logstash

When i defined the pattern for parsing apache tomcat and application log files in logstash we are getting the following error .
Sample log file is :
2014-08-20 12:35:26,037 INFO [routerMessageListener-74] PoolableRuleEngineFactory Executing the rule -->ECE Tagging Rule
config file is :
filter{
grok{
type => "log4j"
#pattern => "%{TIMESTAMP_ISO8601:logdate} %{LOGLEVEL:severity} \[\w+\[% {GREEDYDATA:thread},.*\]\] %{JAVACLASS:class} - %{GREEDYDATA:message}"
pattern => "%{TIMESTAMP_ISO8601:logdate}"
#add_tag => [ "level_%{level}" ]
}
date {
match => [ "logdate", "YYYY-MM-dd HH:mm:ss,SSS"]
}
}
Unknown setting 'timestamp' for date {:level=>:error}
Your post does not show a setting 'timestamp' for your date filter. I suspect you had started with the example here which used timestamp setting that used to be in older versions of date filter. You correctly fixed it for newer version of logstash to use match setting but perhaps had not saved your change. I have no problems using above filter with logstash-1.5.3.
Here is my complete config file. Note I am still testing it but it seems to be working to import a JBoss log with Log4J log messages imported from an existing log file.
input {
tcp {
type => "log4j"
port => 4560
}
stdin {
type => "log4j"
}
}
filter {
grok{
type => "log4j"
#pattern => "%{TIMESTAMP_ISO8601:logdate} %{LOGLEVEL:severity} \[\w+\[%{GREEDYDATA:thread},.*\]\] %{JAVACLASS:class} - %GREEDYDATA:message}"
pattern => "%{TIMESTAMP_ISO8601:logdate}"
#add_tag => [ "level_%{level}" ]
}
date {
type => "log4j"
match => [ "logdate", "YYYY-MM-dd HH:mm:ss,SSS"]
exclude_tags => "_grokparsefailure"
}
# Catches normal space indented type things, probably could be removed b/c the other multiline should do everythign we need
multiline {
type => "log4j"
tags => ["_grokparsefailure"] # exclude anything we already handled
pattern => ".*"
what => "previous"
add_tag => "notgrok"
}
}
output {
gelf {
host => "localhost"
custom_fields => ["environment", "PROD", "service", "BestServiceInTheWorld"]
}
# Print each event to stdout.
stdout {
codec => json
}
}

How to remove trailing newline from message field

I am shipping Glassfish 4 logfiles with Logstash to an ElasticSearch sink. How can I remove with Logstash the trailing newline from a message field?
My event looks like this:
{
"#timestamp" => "2013-11-21T13:29:33.081Z",
"message" => "[2013-11-21T13:29:32.577+0000] [glassfish 4.0] [INFO] [] [javax.resourceadapter.mqjmsra.lifecycle] [tid: _ThreadID=142 _ThreadName=Thread-43] [timeMillis: 1385040572577] [levelValue: 800] [[\n MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter stopped.]]\n",
"#version" => "1",
"tags" => ["multiline", "date_filtered"],
"host" => "myhost",
"path" => "../server.log"
}
A second solution is using the mutate filter of Logstash. It allows you to strip the value of a field.
filter {
# Remove leading and trailing whitspaces (including newline etc. etc.)
mutate {
strip => "message"
}
}
You have to use the multiline filter with the correct pattern, to tell logstash, that every line with precending whitespace belongs to the line before. Add this lines to your conf file.
filter{
...
multiline {
type => "gflogs"
pattern => "\[\#\|\d{4}"
negate => true
what => "previous"
}
...
}
You can also include grok plugin to handle timestamp and filter irregular lines from beeing indexed.
See complete stack with single logstash instance on same machine
input {
stdin {
type => "stdin-type"
}
file {
path => "/path/to/glassfish/logs/*.log"
type => "gflogs"
}
}
filter{
multiline {
type => "gflogs"
pattern => "\[\#\|\d{4}"
negate => true
what => "previous"
}
grok {
type => "gflogs"
pattern => "(?m)\[\#\|%{TIMESTAMP_ISO8601:timestamp}\|%{LOGLEVEL:loglevel}\|%{DATA:server_version}\|%{JAVACLASS:category}\|%{DATA:kv}\|%{DATA:message}\|\#\]"
named_captures_only => true
singles => true
}
date {
type => "gflogs"
match => [ "timestamp", "ISO8601" ]
}
kv {
type => "gflogs"
exclude_tags => "_grokparsefailure"
source => "kv"
field_split => ";"
value_split => "="
}
}
output {
stdout { codec => rubydebug }
elasticsearch { embedded => true }
}
This worked for me. Pleas look also this post on logstash-usergroup. I can also advice the great and up to date logstash book. Its also a good way to support the work of the logstash author.
Hope to see you on any JUG-Berlin Event!

Resources