filebeat to logstash read json file with multiline - logstash

Trying to parse this multiline JSON file
{
"eventSource" : { "objectName": "SYSTEM.ADMIN.CHANNEL.EVENT",
"objectType" : "Queue" },
"eventType" : {
"name" : "Channel Event",
"value" : 46
},
"eventReason" : {
"name" : "Channel Blocked",
"value" : 2577
},
"eventCreation" : {
"timeStamp" : "2018/03/07 05:50:19.06 GMT",
"epoch" : 1520401819
},
"eventData" : {
"queueMgrName" : "QMG1",
"connectionName" : "localhost (192.168.10.1)",
"connectionNameList" : [
"localhost"
],
"reasonQualifier" : "Channel Blocked Noaccess",
"channelName" : "SVR.TEST",
"clientUserId" : "test1",
"applName" : "WebSphere MQ Client for Java",
"applType" : "Java"
}
}
filebeat is configured as
filebeat.prospectors:
- type: log
paths:
- /var/log/test2.log
fields:
tags: ['json']
logsource: mqjson
fields_under_root: true
input beats conf is as below.
input {
beats {
port => 5400
host => "192.168.205.11"
ssl => false
#ssl_certificate => "/etc/pki/tls/certs/logstash-beats.crt"
#ssl_key => "/etc/pki/tls/private/logstash-beats.key"
}
}
filter {
if [tags][json] {
json {
source => "message"
}
}
}
In elastic each line is a record.
Question:
How do i parse this multi line json
Also is there an option to extract certain keys, like eventData section.

by adding as below converts the json. There was an issue opened in elastic which was corrected in 6.0
processors:
- decode_json_fields:
fields: ['message']
target: json

Related

All messages receive a "user level notice"

Im trying to parse a message from my network devices which send messages in format similar to
<30>Feb 14 11:33:59 wireless: ath0 Sending auth to xx:xx:xx:xx:xx:xx. Status: The request has been declined due to MAC ACL (52).\n
<190>Feb 14 11:01:29 CCR00 user admin logged out from xx.xx.xx.xx via winbox
<134>2023 Feb 14 11:00:33 ZTE command-log:An alarm 36609 level notification occurred at 11:00:33 02/14/2023 CET sent by MCP GponRm notify: <gpon-onu_1/1/1:1> SubType:1 Pos:1 ONU Uni lan los. restore\n on \n
using this logstash.conf file
input {
beats {
port => 5044
}
tcp {
port => 50000
}
udp {
port => 50000
}
}
## Add your filters / logstash plugins configuration here
filter {
grok {
match => {
"message" => "^(?:<%{POSINT:syslog_pri}>)?%{GREEDYDATA:message_payload}"
}
}
syslog_pri {
}
mutate {
remove_field => [ "#version" , "message" ]
}
}
output {
stdout {}
elasticsearch {
hosts => "elasticsearch:9200"
user => "logstash_internal"
password => "${LOGSTASH_INTERNAL_PASSWORD}"
}
}
which results in this output
{
"#timestamp": [
"2023-02-14T10:38:59.228Z"
],
"data_stream.dataset": [
"generic"
],
"data_stream.namespace": [
"default"
],
"data_stream.type": [
"logs"
],
"event.original": [
"<14> Feb 14 11:38:59 UBNT BOXSERV[boxs Req]: boxs.c(691) 55381193 %% Error 17 occurred reading thermal sensor 2 data\n\u0000"
],
"host.ip": [
"10.125.132.10"
],
"log.syslog.facility.code": [
1
],
"log.syslog.facility.name": [
"user-level"
],
"log.syslog.severity.code": [
5
],
"log.syslog.severity.name": [
"notice"
],
"message_payload": [
" Feb 14 11:38:59 UBNT[boxs Req]: boxs.c(691) 55381193 %% Error 17 occurred reading thermal sensor 2 data\n\u0000"
],
"syslog_pri": [
"14"
],
"_id": "UzmBT4YBAZPdbqc4m_IB",
"_index": ".ds-logs-generic-default-2023.02.04-000001",
"_score": null
}
which is mostly satisfactory, but i would expect the
log.syslog.facility.name
and
log.syslog.severity.name
fields to be processed by the
syslog_pri
filter
with imput of
<14>
to result into
secur/auth
and
Alert
recpectively,
but i keep getting the default user-level notice for all my messages, no matter what the part of the syslog message contains
anyone could advise and maybe fix my .conf syntax, if its wrong?
thank you very much!
i have logstash configured properly to receive logs and send them to elastics, but the grok/syslog_pri doesnt yield expected results
The fact that the syslog_pri filter is setting [log][syslog][facility][code] shows that it has ECS compatibility enabled. As a result, if you do not set the syslog_pri_field_name option on the syslog_pri filter, it will try to parse [log][syslog][priority]. If that field does not exist then it will parse the default value of 13, which is user-level/notice.
thank you for the answer, i have adjusted the code by the given advice
filter {
grok {
match => { "message" => "^(?:<%{POSINT:syslog_code}>)?%{GREEDYDATA:message_payload}"
} }
syslog_pri { syslog_pri_field_name => "syslog_code"
}
mutate { remove_field => [ "#version" , "message" ] } }
and now it behaves as intended
"event" => {
"original" => "<30>Feb 15 18:41:04 dnsmasq-dhcp[960]: DHCPACK(eth0) 10.0.0.165 xx:xx:xx:xx:xx CZ\n"
},
"#timestamp" => 2023-02-15T17:41:04.977038615Z,
"message_payload" => "Feb 15 18:41:04 dnsmasq-dhcp[960]: DHCPACK(eth0) 10.0.0.165 xx:xx:xx:xx:xx CZ\n",
"log" => {
"syslog" => {
"severity" => {
"code" => 6,
"name" => "informational"
},
"facility" => {
"code" => 3,
"name" => "daemon"
}
}
},
"syslog_code" => "30",
"host" => {
"ip" => "xx.xx.xx.xx"
} }
i will adjust the message a bit to fit my needs,
but that is out of the scope of this question
thank you very much!

Logstash: send event elsewhere if output failed

Giving the following logstash pipeline:
input
{
generator
{
lines => [
'{"name" : "search", "product" : { "module" : "search" , "name" : "api"}, "data" : { "query" : "toto"}}',
'{"name" : "user_interaction", "product" : { "module" : "search" , "name" : "front"}, "data" : { "query" : "toto"}}',
'{"name" : "search", "product" : { "module" : "search" , "name" : "api"}, "data" : { "query" : "toto"}}',
'{"hello": "world"}',
'{"name" :"wrong data", "data" : "I am wrong !"}',
'{"name" :"wrong data", "data" : { "hello" : "world" }}'
]
codec => json
count => 1
}
}
filter
{
mutate
{
remove_field => ["sequence", "host", "#version"]
}
}
output
{
elasticsearch
{
hosts => ["elasticsearch:9200"]
index => "events-dev6-test"
document_type => "_doc"
manage_template => false
}
stdout
{
codec => rubydebug
}
}
elasticsearch has a strict mapping for this index, hence, some events are giving 400 error "mapping set to strict, dynamic introduction of [hello] within [data] is not allowed" (which is normal).
How to send failed events elsewhere (text logs or another elasticsearch index) (so I dont lost events) ?
Logstash 6.2 introduced Dead Letter Queues that can be used to do what you want. You'll need to enable dead_letter_queue.enable: true in your logstash.yml.
And then just deal with it as an input:
input {
dead_letter_queue {
path => "/path/to/data/dead_letter_queue"
commit_offsets => true
pipeline_id => "main"
}
}
output {
file {
path => ...
codec => line { format => "%{message}"}
}
}
Prior to 6.2, I don't believe there was a way to do what you want.

Logging with winston-mongodb, express-winston and winston

I'm using winston, expressWinston, winston-mongoDB to manage the logs in my NodeJs application.
While using winston-mongodb transport with express-winston; i can store the logs to my mongoDB collection in the following format. (meta:true)
{
"_id" : ObjectId("5a124f9781d911337ebeb98d"),
"timestamp" : ISODate("2017-11-20T03:44:23.336Z"),
"level" : "info",
"message" : "GET /stylesheets/bootstrap.css 304 2ms",
"meta" : {
"res" : {
"statusCode" : 304
},
"req" : {
"url" : "/stylesheets/bootstrap.css",
"headers" : {
"host" : "localhost:3000",
"connection" : "keep-alive",
},
"method" : "GET",
"httpVersion" : "1.1",
"originalUrl" : "/stylesheets/bootstrap.css",
"query" : {}
},
"responseTime" : 2
}
I can get the request/response info in the meta.
Is it possible that these details be a part of the collection directly ? , something like this:
{
"_id" : ObjectId("5a12537d81b6b634cb7d4696"),
"timestamp" : ISODate("2017-11-20T04:01:01.229Z"),
"level" : "info",
"message" : "GET /stylesheets/bootstrap.css 304 11ms",
"status": 200,
"requestUrl": '/',
"requestMethod": 'GET',
"remoteIp": '::1'
"meta" : {}
}
you can override the default log function implementation to save whatever you want exactly
let logger = new winston.Logger(options);
logger.log = function () {
var args = arguments;
// here you can transform your meta obj
winston.Logger.prototype.log.apply(this, args);
};
Hope it will help you the idea

converting a nested field to a list json in logstash

I want to convert a field to a json list, sg like this:
"person": {
"name":"XX",
"adress":"124"
}
to
"person": [{"name":"XX",
"adress":"124"}]
Thank you for help.
A bit of ruby magic will do here:
input {
stdin{}
}
filter {
ruby {
code => "
require 'json'
event['res'] = [JSON.parse(event['message'])['person']]
"
}
}
output {
stdout { codec => rubydebug }
}
This will simply parse your message field containing your Json document, then extract the person object and add it to a field.
The test looks as such:
artur#pandaadb:~/dev/logstash$ ./logstash-2.3.2/bin/logstash -f conf_json_list/
Settings: Default pipeline workers: 8
Pipeline main started
{ "person": { "name":"XX", "adress":"124" }}
{
"message" => "{ \"person\": { \"name\":\"XX\", \"adress\":\"124\" }}",
"#version" => "1",
"#timestamp" => "2017-03-15T11:34:37.424Z",
"host" => "pandaadb",
"res" => [
[0] {
"name" => "XX",
"adress" => "124"
}
]
}
As you can see, your hash now lives in a list on index 0.
Hope that helps,
Artur

Kibana4 geo map Error - not showing the client_ip field

I am trying to get kibana-4 geo map to work with ELB logs
when i click the discover tab i can clearly see a field geoip.location with values of [lat, lon]
but when i click the visualise tab -> Tile map -> new search -> Geo coordinates
i get an error (not showing anywhere what is the error i've also checked the kibana logs - but nothing is there)
I checked inspect element - also nothing
I then select GeoHash, but the field is empty (when i click on it its blank with a check icon)
How can i see what is the error ?
How can get this map to work ?
my config is:
input {
file {
path => "/logstash_data/logs/elb/**/*"
exclude => "*.gz"
type => "elb"
start_position => "beginning"
sincedb_path => "log_sincedb"
}
}
filter {
if [type] == "elb" {
grok {
match => [
"message", '%{TIMESTAMP_ISO8601:timestamp} %{NGUSERNAME:loadbalancer} %{IP:client_ip}:%{POSINT:client_port} (%{IP:backend_ip}:%{POSINT:backend_port}|-) %{NUMBER:request_processing_time} %{NUMBER:backend_processing_time} %{NUMBER:response_processing_time} %{POSINT:elb_status_code} %{INT:backend_status_code} %{NUMBER:received_bytes} %{NUMBER:sent_bytes} \\?"%{WORD:method} https?://%{WORD:request_subdomain}.server.com:%{POSINT:request_port}%{URIPATH:request_path}(?:%{URIPARAM:query_string})? %{NOTSPACE}"'
]
}
date {
match => [ "timestamp", "ISO8601" ]
target => "#timestamp"
}
if [query_string] {
kv {
field_split => "&?"
source => "query_string"
prefix => "query_string_"
}
mutate {
remove => [ "query_string" ]
}
}
if [client_ip] {
geoip {
source => "client_ip"
add_tag => [ "geoip" ]
}
}
if [timestamp] {
ruby { code => "event['log_timestamp'] = event['#timestamp'].strftime('%Y-%m-%d')"}
}
}
}
}
output {
elasticsearch {
cluster => "ElasticSearch"
host => "elasticsearch.server.com"
port => 9300
protocol => "node"
manage_template => true
template => "/etc/logstash/lib/logstash/outputs/elasticsearch/elasticsearch-template.json"
index => "elb-%{log_timestamp}"
}
}
geo_ip index did not work in my case because my index names did not started with logstash-
if you want the custom index name to get the geo-ip, you must create a template for that index name
in the output for elasticsearch use it
elasticsearch {
manage_template => true
template => "/etc/logstash/templates/custom_template.json"
}
your template should look like this
{
"template" : "index_name-*",
"settings" : {
"index.refresh_interval" : "5s"
},
"mappings" : {
"_default_" : {
"_all" : {"enabled" : true, "omit_norms" : true},
"dynamic_templates" : [ {
"message_field" : {
"match" : "message",
"match_mapping_type" : "string",
"mapping" : {
"type" : "string", "index" : "analyzed", "omit_norms" : true
}
}
}, {
"string_fields" : {
"match" : "*",
"match_mapping_type" : "string",
"mapping" : {
"type" : "string", "index" : "analyzed", "omit_norms" : true,
"fields" : {
"raw" : {"type": "string", "index" : "not_analyzed", "ignore_above" : 256}
}
}
}
} ],
"properties" : {
"#version": { "type": "string", "index": "not_analyzed" },
"geoip" : {
"type" : "object",
"dynamic": true,
"properties" : {
"location" : { "type" : "geo_point" }
}
}
}
}
}
}
On our maps, we specify a field geoip.location which according to the documentation is automatically created by the geoip filter.
Can you see that field in discover? If not, can you try amending your geoip filter to
if [client_ip] {
geoip {
source => "client_ip"
add_tag => [ "geoip" ]
target => "geoip"
}
}
and see if you can now see geoip.location in new entries?
The elasticsearch templates look for the "geoip" target when creating the associated geoip fields.
Once we have the geoip.location being created, we can create a new map with the following steps in Kibana 4.
Click on visualise
Choose 'Tile Map' from the list of visualisation types
Select either new search or saved - we're using a saved search that filters out Apache entries, but as long as the data contains geoip.location you should be good
Select the 'geo coordinates' bucket type - you'll have an error flagged at this point
In 'aggregation' dropdown, select 'geohash'
In 'field' dropdown, select 'geoip.location'

Resources