logstash-filter-elasticsearch 3.17.1 → 3.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a29cd8cf20b82a601cbaaae69662b4341a40dc5d7c935c0c5b13b6b36d7de236
4
- data.tar.gz: bd1e19d8f42b8066aee89c44622d5efa193e0a800ac1951c186bcaf7ed166626
3
+ metadata.gz: f93bd5f45ce46abe35c9fb54f03ce2f2241a6a7e5c530671a2954324f7965b18
4
+ data.tar.gz: 3bd3ae0babbeb6e46a1e6001888aa85c8fc47d7fb5c794a0063ad7688f3d3bd0
5
5
  SHA512:
6
- metadata.gz: 0c1374ae82f6a3b78b9192186b8dddae4a4826da2befdcf471d8a26abc3faa433f901ed76ad7e1ba0f3e0f1fd223813230125d7c588a454374315dc55935f5b4
7
- data.tar.gz: 4555b95388fe23d825e7d5a34c1a5714dccf394b8657182c483858bef383fae17bd6bb2f818af3c21f0304d29606df9e42378058d675518ffa1a5c9904a3ac37
6
+ metadata.gz: a59b18ddbb4706e50c94c7af206886b430063370376adee33b5795635d813142e662d55830b8401cd17b2e4ecfc69bace939f2ffd16daf2ecedfc4e1f16e5717
7
+ data.tar.gz: eb3c6a279badcc7b9fdaea8831cfeff276cde141773d28f9ead912606c816f30320e706efd34799060349bb09df09c8a4e5f05bf5f6ed2ccb9b0d5b19207eaff
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 3.18.0
2
+ - Add `target` configuration option to store the result into it [#197](https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/197)
3
+
1
4
  ## 3.17.1
2
5
  - Add elastic-transport client support used in elasticsearch-ruby 8.x [#193](https://github.com/logstash-plugins/logstash-filter-elasticsearch/pull/193)
3
6
 
data/docs/index.asciidoc CHANGED
@@ -160,6 +160,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
160
160
  | <<plugins-{type}s-{plugin}-ssl_truststore_type>> |<<string,string>>|No
161
161
  | <<plugins-{type}s-{plugin}-ssl_verification_mode>> |<<string,string>>, one of `["full", "none"]`|No
162
162
  | <<plugins-{type}s-{plugin}-tag_on_failure>> |<<array,array>>|No
163
+ | <<plugins-{type}s-{plugin}-target>> |<<string,string>>|No
163
164
  | <<plugins-{type}s-{plugin}-user>> |<<string,string>>|No
164
165
  |=======================================================================
165
166
 
@@ -173,8 +174,11 @@ filter plugins.
173
174
 
174
175
  * Value type is <<hash,hash>>
175
176
  * Default value is `{}`
177
+ * Format: `"aggregation_name" => "[path][on][event]"`:
178
+ ** `aggregation_name`: aggregation name in result from {es}
179
+ ** `[path][on][event]`: path for where to place the value on the current event, using field-reference notation
176
180
 
177
- Hash of aggregation names to copy from elasticsearch response into Logstash event fields
181
+ A mapping of aggregations to copy into the <<plugins-{type}s-{plugin}-target>> of the current event.
178
182
 
179
183
  Example:
180
184
  [source,ruby]
@@ -244,8 +248,11 @@ These custom headers will override any headers previously set by the plugin such
244
248
 
245
249
  * Value type is <<hash,hash>>
246
250
  * Default value is `{}`
251
+ * Format: `"path.in.source" => "[path][on][event]"`:
252
+ ** `path.in.source`: field path in document source of result from {es}, using dot-notation
253
+ ** `[path][on][event]`: path for where to place the value on the current event, using field-reference notation
247
254
 
248
- Hash of docinfo fields to copy from old event (found via elasticsearch) into new event
255
+ A mapping of docinfo (`_source`) fields to copy into the <<plugins-{type}s-{plugin}-target>> of the current event.
249
256
 
250
257
  Example:
251
258
  [source,ruby]
@@ -271,9 +278,11 @@ Whether results should be sorted or not
271
278
 
272
279
  * Value type is <<array,array>>
273
280
  * Default value is `{}`
281
+ * Format: `"path.in.result" => "[path][on][event]"`:
282
+ ** `path.in.result`: field path in indexed result from {es}, using dot-notation
283
+ ** `[path][on][event]`: path for where to place the value on the current event, using field-reference notation
274
284
 
275
- An array of fields to copy from the old event (found via elasticsearch) into the
276
- new event, currently being processed.
285
+ A mapping of indexed fields to copy into the <<plugins-{type}s-{plugin}-target>> of the current event.
277
286
 
278
287
  In the following example, the values of `@timestamp` and `event_id` on the event
279
288
  found via elasticsearch are copied to the current event's
@@ -521,6 +530,43 @@ WARNING: Setting certificate verification to `none` disables many security benef
521
530
 
522
531
  Tags the event on failure to look up previous log event information. This can be used in later analysis.
523
532
 
533
+ [id="plugins-{type}s-{plugin}-target"]
534
+ ===== `target`
535
+
536
+ * Value type is <<string,string>>
537
+ * There is no default value for this setting.
538
+
539
+ Define the target field for placing the result data.
540
+ If this setting is omitted, the target will be the root (top level) of the event.
541
+
542
+ The destination fields specified in <<plugins-{type}s-{plugin}-fields>>, <<plugins-{type}s-{plugin}-aggregation_fields>>, and <<plugins-{type}s-{plugin}-docinfo_fields>> are relative to this target.
543
+
544
+ For example, if you want the data to be put in the `operation` field:
545
+ [source,ruby]
546
+ if [type] == "end" {
547
+ filter {
548
+ query => "type:start AND transaction:%{[transactionId]}"
549
+ elasticsearch {
550
+ target => "transaction"
551
+ fields => {
552
+ "@timestamp" => "started"
553
+ "transaction_id" => "id"
554
+ }
555
+ }
556
+ }
557
+ }
558
+
559
+ `fields` fields will be expanded into a data structure in the `target` field, overall shape looks like this:
560
+ [source,ruby]
561
+ {
562
+ "transaction" => {
563
+ "started" => "2025-04-29T12:01:46.263Z"
564
+ "id" => "1234567890"
565
+ }
566
+ }
567
+
568
+ NOTE: when writing to a field that already exists on the event, the previous value will be overwritten.
569
+
524
570
  [id="plugins-{type}s-{plugin}-user"]
525
571
  ===== `user`
526
572
 
@@ -2,13 +2,20 @@
2
2
  require "logstash/filters/base"
3
3
  require "logstash/namespace"
4
4
  require "logstash/json"
5
+ require 'logstash/plugin_mixins/ecs_compatibility_support'
6
+ require 'logstash/plugin_mixins/ecs_compatibility_support/target_check'
5
7
  require 'logstash/plugin_mixins/ca_trusted_fingerprint_support'
6
8
  require "logstash/plugin_mixins/normalize_config_support"
9
+ require 'logstash/plugin_mixins/validator_support/field_reference_validation_adapter'
7
10
  require "monitor"
8
11
 
9
12
  require_relative "elasticsearch/client"
10
13
 
11
14
  class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
15
+
16
+ include LogStash::PluginMixins::ECSCompatibilitySupport
17
+ include LogStash::PluginMixins::ECSCompatibilitySupport::TargetCheck
18
+
12
19
  config_name "elasticsearch"
13
20
 
14
21
  # List of elasticsearch hosts to use for querying.
@@ -131,6 +138,9 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
131
138
  # Tags the event on failure to look up geo information. This can be used in later analysis.
132
139
  config :tag_on_failure, :validate => :array, :default => ["_elasticsearch_lookup_failure"]
133
140
 
141
+ # If set, the the result set will be nested under the target field
142
+ config :target, :validate => :field_reference
143
+
134
144
  # How many times to retry on failure?
135
145
  config :retry_on_failure, :validate => :number, :default => 0
136
146
 
@@ -214,17 +224,19 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
214
224
  matched = true
215
225
  @fields.each do |old_key, new_key|
216
226
  old_key_path = extract_path(old_key)
217
- set = resultsHits.map do |doc|
227
+ extracted_hit_values = resultsHits.map do |doc|
218
228
  extract_value(doc["_source"], old_key_path)
219
229
  end
220
- event.set(new_key, set.count > 1 ? set : set.first)
230
+ value_to_set = extracted_hit_values.count > 1 ? extracted_hit_values : extracted_hit_values.first
231
+ set_to_event_target(event, new_key, value_to_set)
221
232
  end
222
233
  @docinfo_fields.each do |old_key, new_key|
223
234
  old_key_path = extract_path(old_key)
224
- set = resultsHits.map do |doc|
235
+ extracted_docs_info = resultsHits.map do |doc|
225
236
  extract_value(doc, old_key_path)
226
237
  end
227
- event.set(new_key, set.count > 1 ? set : set.first)
238
+ value_to_set = extracted_docs_info.count > 1 ? extracted_docs_info : extracted_docs_info.first
239
+ set_to_event_target(event, new_key, value_to_set)
228
240
  end
229
241
  end
230
242
 
@@ -232,7 +244,7 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
232
244
  if !resultsAggs.nil? && !resultsAggs.empty?
233
245
  matched = true
234
246
  @aggregation_fields.each do |agg_name, ls_field|
235
- event.set(ls_field, resultsAggs[agg_name])
247
+ set_to_event_target(event, ls_field, resultsAggs[agg_name])
236
248
  end
237
249
  end
238
250
 
@@ -265,6 +277,18 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
265
277
 
266
278
  private
267
279
 
280
+ # if @target is defined, creates a nested structure to inject result into target field
281
+ # if not defined, directly sets to the top-level event field
282
+ # @param event [LogStash::Event]
283
+ # @param new_key [String] name of the field to set
284
+ # @param value_to_set [Array] values to set
285
+ # @return [void]
286
+ def set_to_event_target(event, new_key, value_to_set)
287
+ key_to_set = target ? "[#{target}][#{new_key}]" : new_key
288
+
289
+ event.set(key_to_set, value_to_set)
290
+ end
291
+
268
292
  def client_options
269
293
  @client_options ||= {
270
294
  :user => @user,
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-filter-elasticsearch'
4
- s.version = '3.17.1'
4
+ s.version = '3.18.0'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Copies fields from previous log events in Elasticsearch to current events "
7
7
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -23,8 +23,10 @@ Gem::Specification.new do |s|
23
23
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24
24
  s.add_runtime_dependency 'elasticsearch', ">= 7.14.9", '< 9'
25
25
  s.add_runtime_dependency 'manticore', ">= 0.7.1"
26
+ s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~> 1.3'
26
27
  s.add_runtime_dependency 'logstash-mixin-ca_trusted_fingerprint_support', '~> 1.0'
27
28
  s.add_runtime_dependency 'logstash-mixin-normalize_config_support', '~>1.0'
29
+ s.add_runtime_dependency 'logstash-mixin-validator_support', '~> 1.0'
28
30
  s.add_development_dependency 'cabin', ['~> 0.6']
29
31
  s.add_development_dependency 'webrick'
30
32
  s.add_development_dependency 'logstash-devutils'
@@ -864,6 +864,33 @@ describe LogStash::Filters::Elasticsearch do
864
864
  end
865
865
  end
866
866
 
867
+ describe "#set_to_event_target" do
868
+
869
+ context "when `@target` is nil, default behavior" do
870
+ let(:config) {{ }}
871
+
872
+ it "sets the value directly to the top-level event field" do
873
+ plugin.send(:set_to_event_target, event, "new_field", %w[value1 value2])
874
+ expect(event.get("new_field")).to eq(%w[value1 value2])
875
+ end
876
+ end
877
+
878
+ context "when @target is defined" do
879
+ let(:config) {{ "target" => "nested" }}
880
+
881
+ it "creates a nested structure under the target field" do
882
+ plugin.send(:set_to_event_target, event, "new_field", %w[value1 value2])
883
+ expect(event.get("nested")).to eq({ "new_field" => %w[value1 value2] })
884
+ end
885
+
886
+ it "overwrites existing target field with new data" do
887
+ event.set("nested", { "existing_field" => "existing_value", "new_field" => "value0" })
888
+ plugin.send(:set_to_event_target, event, "new_field", ["value1"])
889
+ expect(event.get("nested")).to eq({ "existing_field" => "existing_value", "new_field" => ["value1"] })
890
+ end
891
+ end
892
+ end
893
+
867
894
  def extract_transport(client)
868
895
  # on 7x: client.transport.transport
869
896
  # on >=8.x: client.transport
@@ -84,7 +84,9 @@ describe LogStash::Filters::Elasticsearch, :integration => true do
84
84
  end
85
85
 
86
86
  it "fails to register plugin" do
87
- expect { plugin.register }.to raise_error Elasticsearch::Transport::Transport::Errors::Unauthorized
87
+ expect { plugin.register }.to raise_error elastic_ruby_v8_client_available? ?
88
+ Elastic::Transport::Transport::Errors::Unauthorized :
89
+ Elasticsearch::Transport::Transport::Errors::Unauthorized
88
90
  end
89
91
 
90
92
  end if ELASTIC_SECURITY_ENABLED
@@ -150,5 +152,10 @@ describe LogStash::Filters::Elasticsearch, :integration => true do
150
152
  end
151
153
  end
152
154
  end
153
-
155
+ def elastic_ruby_v8_client_available?
156
+ Elasticsearch::Transport
157
+ false
158
+ rescue NameError # NameError: uninitialized constant Elasticsearch::Transport if Elastic Ruby client is not available
159
+ true
160
+ end
154
161
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-filter-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.17.1
4
+ version: 3.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-17 00:00:00.000000000 Z
11
+ date: 2025-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -64,6 +64,20 @@ dependencies:
64
64
  - - ">="
65
65
  - !ruby/object:Gem::Version
66
66
  version: 0.7.1
67
+ - !ruby/object:Gem::Dependency
68
+ requirement: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '1.3'
73
+ name: logstash-mixin-ecs_compatibility_support
74
+ type: :runtime
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '1.3'
67
81
  - !ruby/object:Gem::Dependency
68
82
  requirement: !ruby/object:Gem::Requirement
69
83
  requirements:
@@ -92,6 +106,20 @@ dependencies:
92
106
  - - "~>"
93
107
  - !ruby/object:Gem::Version
94
108
  version: '1.0'
109
+ - !ruby/object:Gem::Dependency
110
+ requirement: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - "~>"
113
+ - !ruby/object:Gem::Version
114
+ version: '1.0'
115
+ name: logstash-mixin-validator_support
116
+ type: :runtime
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '1.0'
95
123
  - !ruby/object:Gem::Dependency
96
124
  requirement: !ruby/object:Gem::Requirement
97
125
  requirements: