I try to efficiently rename pattern in logstash. So if the json field comes as instrument_network_a
it will be renamed to network.labels.a
, it it comes as instrument_network_b
it will be renamed to network.labels.b
and so on.
Really what I thought it would be some mutate { gsub { } }
expression but can't figure out how to make it to work with glob (*
). So I try ruby filter instead.
I tried to wrap gsub
inside the event to hash conversion but I have a problems to make it executing.
Below are three cases of different approaches:
Case 1 taken from StackOverflow but it causes logstash to break execution.
1 - pipeline.id: amq
2 config.string: |
3 input { stdin { } }
4
5 filter {
6 json { source => "message" }
7 ruby { code => ' event.to_hash.each_pair { |k, v|
8 if !!(/instrument_network_*/ =~ k)
9 newkey = k.gsub(/^instrument_network_/, 'network.labels.')
10 event.set(newkey, v);
11 event.remove(k)
12 end }'
13 }
14 }
15
16 output { stdout { codec => rubydebug } }
When I run it it just stops:
$ /usr/share/logstash/bin/logstash --path.settings . --path.data data -l . --log.level debug
Sending Logstash's logs to . which is now configured via log4j2.properties
$
I logstash-plain.log the error shows as:
[2019-01-26T20:14:26,015][ERROR][logstash.agent ] Failed to execute action {:action=>LogStash::PipelineAction::Create/pipeline_id:amq, :exception=>"LogStash::ConfigurationError", :message=>"Expected one of #, {, } at line 7, column 62 (byte 229) after filter {\n json { source => \"message\" }\n ruby { code => ' event.to_hash.each_pair { |k, v|\n if !!(/instrument_network_*/ =~ k)\n newkey = k.gsub(/^instrument_network_/, '", :backtrace=>["/usr/share/logstash/logstash-core/lib/logstash/compiler.rb:42:in `compile_imperative'", "/usr/share/logstash/logstash-core/lib/logstash/compiler.rb:50:in `compile_graph'", "/usr/share/logstash/logstash-core/lib/logstash/compiler.rb:12:in `block in compile_sources'", "org/jruby/RubyArray.java:2486:in `map'", "/usr/share/logstash/logstash-core/lib/logstash/compiler.rb:11:in `compile_sources'", "/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:49:in `initialize'", "/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:167:in `initialize'", "/usr/share/logstash/logstash-core/lib/logstash/pipeline_action/create.rb:40:in `execute'", "/usr/share/logstash/logstash-core/lib/logstash/agent.rb:305:in `block in converge_state'"]}
which I don't really see any clue why it does not work.
I have built another parsing solution base on string
1 - pipeline.id: amq
2 config.string: |
3 input { stdin { } }
4
5 filter {
6 json { source => "message" }
7 ruby { code => ' event.to_hash.each_pair { |k, v|
8 if !!(/instrument_network_*/ =~ k)
9 newkey = "#{["network.labels", k.split("_", 3)[2]].join(".")}"
10 event.set(newkey, v);
11 event.remove(k)
12 end }'
13 }
14 }
15
16 output { stdout { codec => rubydebug } }
with the output:
$ /usr/share/logstash/bin/logstash --path.settings . --path.data data -l . --log.level debug
Sending Logstash's logs to . which is now configured via log4j2.properties
The stdin plugin is now waiting for input:
{"instrument_network_a":false, "instrument_network_b":true, "instrument_network":false}
{
"network.labels.a" => false,
"@version" => "1",
"@timestamp" => 2019-01-26T20:08:52.692Z,
"network.labels.b" => true,
"network.labels." => false,
"host" => "***",
"message" => "{\"instrument_network_a\":false, \"instrument_network_b\":true, \"instrument_network\":false}"
}
but it feels neither clear to read not efficient to work
- What would be the most efficient way to built "mutate" filter using glob?
- Is there any way to measure or time execution of the filter?
- Why
rsub
does not work in this case. As far as I read the docs and check syntax, I understand it should work. - Ideally I would like to eliminate
network.labels
without the name of the instrument. Sonetwork.labels.a
is accepted butnetwork.labels.
really is not. Is there a simple/efficient way to incorporate such behaviour?
All advise well appreciated.