I’ve been having an issue on my logstash node where about 5 log sources (linux servers) are generating about 30 logstash-plain.log files every day, each with about 20-30k lines.
About 99% of these logs consist of the same error which always references one of five field names and appears on indexes generated for one of the 5 log sources.
The errors all look as such:
[timestamp][WARN ][logstash.outputs.elasticsearch][pipeline-1][5e64f0864877a20a1228b6b5316c4503e7bcc197143f3e86a6a33b949360472e] Could not index event to Elasticsearch.
...
"status"=>400, "error"=>{"type"=>"mapper_parsing_exception", "reason"=>"failed to parse field [nested][fieldname] of type [text] in document with id 'some_document_id'. Preview of field's value: '{port=12345, bytes=123, ip=123.45.67.89, domain=some-dns-name.com, packets=666}'", "caused_by"=>{"type"=>"illegal_state_exception", "reason"=>"Can't get text on a START_OBJECT at 1:1938"}}}}}
The field’s values differ but essentially it appears sometimes the field source can be a simple string as: {‘1234.566:1111’} and then on other occasions which generate the error itself they can have nested values as shown in the field value’s preview above.
So when I modify the index template to map this field as an object (see below mapping examples), I can no longer ingest simple string values and the error changes to:
[timestamp][WARN ][logstash.outputs.elasticsearch][pipeline-1][5e64f0864877a20a1228b6b5316c4503e7bcc197143f3e86a6a33b949360472e] Could not index event to Elasticsearch.
...
"status"=>400, "error"=>{"type"=>"mapper_parsing_exception", "reason"=>"object mapping for [nested][fieldname] tried to parse field [nested][fieldname] as object, but found a concrete value"}}}}
So far I have tried resolving this error in the following ways but none have actually worked which leads me to believe I am doing something very wrong here..
Attempted to use mutate filters in logstash:
filter { # convert field to string
mutate {
convert => {
"[nested][fieldname]" => "string"
}
}
}
filter { # remove '{' and '}' chars from field
mutate {
gsub => [
"[nested][fieldname]", "[{}]", ""
]
}
}
filter { # filter field value in quotes
mutate {
gsub => [
"[nested][fieldname]", "^", """,
"[nested][fieldname]", "$", """
]
}
}
Attempted a few different ruby filters to convert object field to string
filter { # convert field to string if they are arrays
ruby {
code => "
params = event.get('[nested][fieldname]')
if fieldname.is_a?(Array)
fieldname.each do |param|
if param['value'].is_a?(Hash) || param['value'].is_a?(Array)
param['value'] = param['value'].to_json
end
end
event.set('[nested][fieldname]', fieldname)
end
"
}
}
filter { # convert all fields to string if they are arrays
ruby {
code => "
fields = ['[source]', '[nested][fieldname1]', '[nested][fieldname2][value]', '[nested][fieldname3]']
fields.each do |field|
value = event.get(field)
if value.is_a?(Hash) || value.is_a?(Array)
event.set(field, value.to_json)
end
end
"
}
}
filter { # convert to string and remove curly brackets
if [nested][fieldname] {
ruby {
code => '
addr = event.get("[nested][fieldname]")
if addr.is_a?(String)
addr.gsub!(/[{}]/, "")
event.set("[nested][fieldname]", addr)
elsif addr.is_a?(Hash)
addr_string = addr.to_s.gsub(/[{}]/, "")
event.set("[nested][fieldname]", addr_string)
end
'
}
}
}
Attempted a few different index templates to modify the fields mapping
{ # text and keyword types
"index_patterns": ["*index-pattern*"],
"priority": 510, # another template with a priority of 500 already takes effect here
"template": {
"mappings": {
"properties": {
"nested": {
"properties": {
"fieldname": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}
}
{ # keyword type
"index_patterns": ["*index-pattern*"],
"priority": 510, # another template with a priority of 500 already takes effect here
"template": {
"mappings": {
"properties": {
"nested": {
"properties": {
"fieldname": {
"type": "keyword"
}
}
}
}
}
}
}
{ # nested object type
"index_patterns": ["*index-pattern*"],
"priority": 510, # another template with a priority of 500 already takes effect here
"template": {
"mappings": {
"properties": {
"nested": {
"properties": {
"fieldname": {
"type": "object",
"properties": {
"remote": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}
}
}
}
Thanks!