logstash - convert hex to ascii - plugins

I wonder if there is any alternative to this hex plugin.
It's actually a nice and simple plugin but the problem is the latest updates for this plugin dated back to
2016.
My second question is how to update logstash on Linux while retaining custom plugins such as logstash-filter-hex? Last time the plugin was removed after the package update.

If the plugin stopped working, you can replicate the functionality of this plugin using a ruby filter in your logstash pipeline.
For example, consider the two log lines:
{ "exampleString": "convert string to hex", "exampleInt": 10 }
{ "hexString": "636f6e766572742068657820746f20737472696e67", "hexInt": "a" }
To convert the fields exampleString and exampleInt to HEX and the fields hexString and hexInt from HEX to ascii, you can use the following config in logstash.
filter {
if [exampleString] and [exampleInt] {
ruby {
code => "event.set('[toHexString]', event.get('[exampleString]').unpack('H*').first)"
}
ruby {
code => "event.set('[toHexINT]', event.get('[exampleInt]').to_i.to_s(16))"
}
}
if [hexString] and [hexInt] {
ruby {
code => "event.set('[fromHexString]', [event.get('[hexString]')].pack('H*'))"
}
ruby {
code => "event.set('[fromHexINT]', event.get('[hexInt]').to_i(16).to_s)"
}
}
}
And your result will be something like this.
{
"fromHexString" => "convert hex to string",
"fromHexINT" => "10",
"#timestamp" => 2020-05-18T12:41:37.624Z,
"#version" => "1",
"hexString" => "636f6e766572742068657820746f20737472696e67",
"hexInt" => "a",
"host" => "elk"
}
{
"toHexINT" => "a",
"#timestamp" => 2020-05-18T12:41:37.622Z,
"#version" => "1",
"exampleString" => "convert string to hex",
"toHexString" => "636f6e7665727420737472696e6720746f20686578",
"exampleInt" => 10,
"host" => "elk"
}
Where you can see that the fields were converted from hex and to hex.
Regarding your second question, when you update logstash it will update the files that references your installed plugins, so if you have a non bundled plugin, you will need to install it again.

Related

Create index with the same name as request path value, using ElasticSearch output

This is my logstash.conf:
input {
http {
host => "127.0.0.1"
port => 31311
}
}
output {
elasticsearch {
hosts => ["http://localhost:9200"]
}
stdout {
codec => "rubydebug"
}
}
As a test, I ran this command in PowerShell:
C:\Users\Me\Downloads\curl-7.64.1-win64-mingw\bin> .\curl.exe -XPUT
'http://127.0.0.1:31311/twitter'
The following output was displayed inside my Logstash terminal:
{
"#timestamp" => 2019-04-09T08:32:09.250Z,
"message" => "",
"#version" => "1",
"headers" => {
"request_path" => "/twitter",
"http_version" => "HTTP/1.1",
"http_user_agent" => "curl/7.64.1",
"request_method" => "PUT",
"http_accept" => "*/*",
"content_length" => "0",
"http_host" => "127.0.0.1:31311"
},
"host" => "127.0.0.1"
}
When I then ran
C:\Users\Me\Downloads\curl-7.64.1-win64-mingw\bin> .\curl.exe -XGET
"http://127.0.0.1:9200/_cat/indices"
inside PowerShell, I saw
yellow open logstash-2019.04.09 1THStdPfQySWl1WPNeiwPQ 5 1 0 0 401b 401b
An index named logstash-2019.04.09 has been created in response to my PUT request, following the ElasticSearch convention.
My question is: If I want the index to have the same value as the {index_name} parameter I pass inside the the command .\curl.exe -XPUT 'http://127.0.0.1:31311/{index_name}', how should I configure the ElasticSearch output inside my logstash.conf file?
EDIT: Just to clarify, I want {index_name} to be read dynamically every single time I make a PUT request to create a new index. Is that even possible?
It is possible with the index output configuration option.
This configuration can be dynamic using the %{foo} syntax. Since you want the value of [headers][request_path] to be in the index configuration, you can do something like this:
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "%{[headers][request_path]}"
}
}
For this to work the value [headers][request_path] field must not contain any of these characters: [ , \", *, \\, <, |, ,, >, /, ?].
I recommend that you use the gsub configuration option of the mutate filter. So, to remove all the forward slashes, you should have something like this:
filter{
mutate{
gsub => ["[headers][request_path]","/",""]
}
}
If the request path has several forward slashes, you could replace them with some character that will be accepted by elasticsearch.
So, your final logstash.conf file should look like this:
input {
http {
host => "127.0.0.1"
port => 31311
}
}
filter{
mutate{
gsub => ["[headers][request_path]","/",""]
}
}
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "%{[headers][request_path]}"
}
stdout {
codec => "rubydebug"
}
}
You can do so by adding an index configuration setting to your elasticsearch output section. e.g.
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "yourindexnamehere"
}
stdout {
codec => "rubydebug"
}
}

Ingest email attachments on ElasticSearch

I'm trying to use ELK pipeline to read an email (IMAP), extract generic attachments (mainly PDF, eventually doc or ppt) and put them on ElasticSearch.
This is what I was able to do:
Loading directly to ElasticSearch from file some base64 data using Logstash, using the Ingest Attachment Processor on ElasticSearch to read the base64 content.
Loading data from IMAP (exchange email) I can correctly load all email information on ElasticSearch except the attachment (what I need).
The first solution works fine and does what I am looking for, except that it doesn't extract attachments directly from the email and that I have hardcoded base64 data inside the files.
With the second solution I have a field x-ms-has-attach: yes on Kibana, but there isn't anywhere the attachment itself. The imap plugin is intended to load only the content of the email without the attachment?
What am I missing? Could you suggest me a pipeline to achieve what I am looking for?
This is my logstash configuration for the first example:
input {
file {
path => "/my/path/to/data/*"
start_position => "beginning"
# sincedb_path => "/my/path/to/sincedb"
sincedb_path => "/dev/null"
close_older => 0
tags => ["attachment"]
}
}
output {
elasticsearch {
index => "email-attachment"
hosts => [ "localhost:9200" ]
}
}
This is the pipeline:
PUT _ingest/pipeline/email-attachment
{
"description": "Pipeline to parse an email and its attachments",
"processors": [
{
"attachment" : {
"field" : "message"
}
},
{
"remove" : {
"field" : "message"
}
},
{
"date_index_name" : {
"field" : "#timestamp",
"index_name_prefix" : "email-attachment-",
"index_name_format": "yyyy-MM",
"date_rounding" : "M"
}
}
]
}
This is my logstash configuration for the second example:
input {
imap {
host => "my.domain.it"
password => "mypassword"
user => "myuser"
port => 12345
type => "imap"
secure => true
strip_attachment => true
}
}
output {
elasticsearch {
index => "email-attachment"
hosts => [ "localhost:9200" ]
}
}
UPDATE
I'm using version 5.2.2
In the end I defined a totally different pipeline.
I read emails using a Ruby application with the mail library (you can find it on github), where it's quite easy to extract attachments.
Then I put the base64 encoding of those attachments directly on ElasticSearch, using Ingest Attachment Processor.
I filter on content_type just to be sure to load only "real" attachments, as the multiparts emails treat any multimedial content in the body (ie: images) as attachment.
P.S.
Using the mail library, you should do something like:
Mail.defaults do
retriever_method :imap, { :address => address,
:port => port,
:user_name => user_name,
:password => password,
:enable_ssl => enable_ssl,
:openssl_verify_mode => openssl_verify_mode }
and new_messages = Mail.find(keys: ['NOT','SEEN']) to retrieve unseen messages.
Then iterate over new_messages. After, you can encode a message simply using encoded = Base64.strict_encode64(attachment.body.to_s). Please inspect new_messages to check the exact field names to use.
Your problem might come from strip_attachment => true in the imap input plugin.

Logstash - Custom Timestamp Error

I am trying to input a timestamp field in Logstash and i am getting dateparsefailure message.
My Message -
2014-08-01;11:00:22.123
Pipeline file
input {
stdin{}
#beats {
# port => "5043"
# }
}
# optional.
filter {
date {
locale => "en"
match => ["message", "YYYY-MM-dd;HH:mm:ss.SSS"]
target => "#timestamp"
add_field => { "debug" => "timestampMatched"}
}
}
output {
elasticsearch {
hosts => [ "127.0.0.1:9200" ]
}
stdout { codec => rubydebug }
}
Can someone tell me what i am missing ?
Update 1
I referred to the link - How to remove trailing newline from message field and now it works.
But, in my log message, i have multiple values other than timestamp
<B 2014-08-01;11:00:22.123 Field1=Value1 Field2=Value2
When i give this as input, it is not working. How to read a part of the log and make it as timestamp ?
Update 2
it works now.
Changed the config file as below
filter {
kv
{
}
mutate {
strip => "message"
}
date {
locale => "en"
match => ["timestamp1", "YYYY-MM-dd;HH:mm:ss.SSS"]
target => "#timestamp"
add_field => { "debug" => "timestampMatched"}
}
}
I am posting the answer below and steps i used to solve the issue so that i can help people like me.
Step 1 - I read the message in the form of key and value pair
Step 2 - I trimmed off the extra space that leads to parse exception
Step 3 - I read the timestamp value and other fields in respective fields.
input {
beats {
port => "5043"
}
}
# optional.
filter {
kv { }
date {
match => [ "timestamp", "yyyy-MM-dd HH:mm:ss,SSS" ]
remove_field => [ "timestamp" ]
}
}
output {
elasticsearch {
hosts => [ "127.0.0.1:9200" ]
}
}

Add a field if match

i'm triyng to monitor an irc server. And i'm loot for a way to create a new numeral field (example: Alert_level) only if a message match a specific word inside.
Example: Message: ABC | Alert_level: 1 ; Message: ZYX | Alert_level: 3.
Its the running code
input {
irc {
channels => "#xyz"
host => "a.b.c"
nick => "myusername"
catch_all => true
get_stats => true
}
}
output {
stdout { codec => "rubydebug" }
elasticsearch {
hosts => "localhost"
index => "logstash-irc-%{+YYYY.MM.dd}"
}
}
Thank you!
As #Val suggested above you might need to use the grok filter in order match something from the input. For example your filter could look something like this:
filter {
grok {
match => { "message" => "%{GREEDYDATA:somedata}" }
}
if "ZYX" in [message]{ <-- change your condition accordingly
mutate {
add_field => { "%{Alert_level}" => "12345" } <-- somefield is the field name
convert => { "Alert_level" => "integer" } <-- do the conversion
}
}
}
NOTE that you have to do the conversion in order to create a numeric field through logstash, where you can't directly create one. The above is just a sample so that you can reproduce. Do change the grok match in respect to your requirement. Hope it helps!

Filter Date Logstash

I just started with Logstash parsing a CSV document. CSV document only has two columns "Date" and "High". I have read various configurations to parse a date but I can not, giving me error in that field. The date has the format DD / MM / YYYY and error tells me the following:
Failed parsing date from field {:field=>"Date", :value=>"Date", :exception=>"Invalid format: \"Date\"", :config_parsers=>"dd/MM/YYYY", :config_locale=>"default=es_ES", :level=>:warn}
This is my configuration file to filter Logstash:
input {
file {
path => "/path/to/data.csv"
start_position => "beginning"
}
}
filter {
csv {
separator => ","
columns => ["Date","High"]
}
date{
match => [ "Date", "dd/MM/YYYY" ]
}
mutate {convert => ["High", "float"]}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
action => "index"
index => "machine"
workers => 1
}
stdout { codec => rubydebug }
}
Thank you!!
In your date plugin try to change the letter cases in the match setting. Something like this:
date{
match => [ "Date", "DD/MM/YYYY" ]
}
If not helping try to make them all lowercase.
The format string dd/MM/yyyy should work. You can find detailed specifications for formatting strings in the JodaTime documentation.