logstash-filter-elasticsearch 3.19.0 → 4.0.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 +4 -4
- data/CHANGELOG.md +9 -11
- data/docs/index.asciidoc +23 -240
- data/lib/logstash/filters/elasticsearch/client.rb +2 -27
- data/lib/logstash/filters/elasticsearch.rb +124 -177
- data/logstash-filter-elasticsearch.gemspec +3 -6
- data/spec/filters/elasticsearch_spec.rb +272 -163
- data/spec/filters/elasticsearch_ssl_spec.rb +17 -0
- data/spec/filters/integration/elasticsearch_spec.rb +2 -9
- metadata +3 -59
- data/lib/logstash/filters/elasticsearch/dsl_executor.rb +0 -140
- data/lib/logstash/filters/elasticsearch/esql_executor.rb +0 -178
- data/spec/filters/elasticsearch_dsl_spec.rb +0 -372
- data/spec/filters/elasticsearch_esql_spec.rb +0 -211
- data/spec/filters/integration/elasticsearch_esql_spec.rb +0 -167
@@ -2,23 +2,13 @@
|
|
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'
|
7
5
|
require 'logstash/plugin_mixins/ca_trusted_fingerprint_support'
|
8
|
-
require "logstash/plugin_mixins/normalize_config_support"
|
9
|
-
require 'logstash/plugin_mixins/validator_support/field_reference_validation_adapter'
|
10
6
|
require "monitor"
|
11
7
|
|
12
8
|
require_relative "elasticsearch/client"
|
9
|
+
require_relative "elasticsearch/patches/_elasticsearch_transport_http_manticore"
|
13
10
|
|
14
11
|
class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
|
15
|
-
|
16
|
-
require 'logstash/filters/elasticsearch/dsl_executor'
|
17
|
-
require 'logstash/filters/elasticsearch/esql_executor'
|
18
|
-
|
19
|
-
include LogStash::PluginMixins::ECSCompatibilitySupport
|
20
|
-
include LogStash::PluginMixins::ECSCompatibilitySupport::TargetCheck
|
21
|
-
|
22
12
|
config_name "elasticsearch"
|
23
13
|
|
24
14
|
# List of elasticsearch hosts to use for querying.
|
@@ -28,13 +18,8 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
|
|
28
18
|
# Field substitution (e.g. `index-name-%{date_field}`) is available
|
29
19
|
config :index, :validate => :string, :default => ""
|
30
20
|
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
# Elasticsearch query string. This can be in DSL or ES|QL query shape defined by @query_type.
|
35
|
-
# Read the Elasticsearch query string documentation.
|
36
|
-
# DSL: https://www.elastic.co/guide/en/elasticsearch/reference/master/query-dsl-query-string-query.html#query-string-syntax
|
37
|
-
# ES|QL: https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html
|
21
|
+
# Elasticsearch query string. Read the Elasticsearch query string documentation.
|
22
|
+
# for more info at: https://www.elastic.co/guide/en/elasticsearch/reference/master/query-dsl-query-string-query.html#query-string-syntax
|
38
23
|
config :query, :validate => :string
|
39
24
|
|
40
25
|
# File path to elasticsearch query in DSL format. Read the Elasticsearch query documentation
|
@@ -47,9 +32,6 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
|
|
47
32
|
# Array of fields to copy from old event (found via elasticsearch) into new event
|
48
33
|
config :fields, :validate => :array, :default => {}
|
49
34
|
|
50
|
-
# Custom headers for Elasticsearch requests
|
51
|
-
config :custom_headers, :validate => :hash, :default => {}
|
52
|
-
|
53
35
|
# Hash of docinfo fields to copy from old event (found via elasticsearch) into new event
|
54
36
|
config :docinfo_fields, :validate => :hash, :default => {}
|
55
37
|
|
@@ -79,18 +61,6 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
|
|
79
61
|
# Set the address of a forward HTTP proxy.
|
80
62
|
config :proxy, :validate => :uri_or_empty
|
81
63
|
|
82
|
-
# SSL
|
83
|
-
config :ssl, :validate => :boolean, :default => false, :deprecated => "Set 'ssl_enabled' instead."
|
84
|
-
|
85
|
-
# SSL Certificate Authority file
|
86
|
-
config :ca_file, :validate => :path, :deprecated => "Set 'ssl_certificate_authorities' instead."
|
87
|
-
|
88
|
-
# The keystore used to present a certificate to the server.
|
89
|
-
# It can be either .jks or .p12
|
90
|
-
config :keystore, :validate => :path, :deprecated => "Use 'ssl_keystore_path' instead."
|
91
|
-
|
92
|
-
# Set the keystore password
|
93
|
-
config :keystore_password, :validate => :password, :deprecated => "Use 'ssl_keystore_password' instead."
|
94
64
|
|
95
65
|
# OpenSSL-style X.509 certificate certificate to authenticate the client
|
96
66
|
config :ssl_certificate, :validate => :path
|
@@ -146,36 +116,24 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
|
|
146
116
|
# Tags the event on failure to look up geo information. This can be used in later analysis.
|
147
117
|
config :tag_on_failure, :validate => :array, :default => ["_elasticsearch_lookup_failure"]
|
148
118
|
|
149
|
-
# If set, the result set will be nested under the target field
|
150
|
-
config :target, :validate => :field_reference
|
151
|
-
|
152
119
|
# How many times to retry on failure?
|
153
120
|
config :retry_on_failure, :validate => :number, :default => 0
|
154
121
|
|
155
122
|
# What status codes to retry on?
|
156
123
|
config :retry_on_status, :validate => :number, :list => true, :default => [500, 502, 503, 504]
|
157
124
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
# {"type" => "%{[type]}"}
|
164
|
-
# {"min_depth" => "%{[depth]}"}
|
165
|
-
# ]
|
166
|
-
config :query_params, :validate => :array, :default => []
|
125
|
+
|
126
|
+
config :ssl, :obsolete => "Set 'ssl_enabled' instead."
|
127
|
+
config :ca_file, :obsolete => "Set 'ssl_certificate_authorities' instead."
|
128
|
+
config :keystore, :obsolete => "Set 'ssl_keystore_path' instead."
|
129
|
+
config :keystore_password, :validate => :password, :obsolete => "Set 'ssl_keystore_password' instead."
|
167
130
|
|
168
131
|
# config :ca_trusted_fingerprint, :validate => :sha_256_hex
|
169
132
|
include LogStash::PluginMixins::CATrustedFingerprintSupport
|
170
133
|
|
171
|
-
include LogStash::PluginMixins::NormalizeConfigSupport
|
172
|
-
|
173
134
|
include MonitorMixin
|
174
135
|
attr_reader :shared_client
|
175
136
|
|
176
|
-
LS_ESQL_SUPPORT_VERSION = "8.17.4" # the version started using elasticsearch-ruby v8
|
177
|
-
ES_ESQL_SUPPORT_VERSION = "8.11.0"
|
178
|
-
|
179
137
|
##
|
180
138
|
# @override to handle proxy => '' as if none was set
|
181
139
|
# @param value [Array<Object>]
|
@@ -193,22 +151,17 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
|
|
193
151
|
return super(value, :uri)
|
194
152
|
end
|
195
153
|
|
196
|
-
attr_reader :query_dsl
|
197
|
-
|
198
154
|
def register
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
@esql_executor ||= LogStash::Filters::Elasticsearch::EsqlExecutor.new(self, @logger)
|
207
|
-
else # dsl
|
208
|
-
validate_dsl_query_settings!
|
209
|
-
@esql_executor ||= LogStash::Filters::Elasticsearch::DslExecutor.new(self, @logger)
|
155
|
+
#Load query if it exists
|
156
|
+
if @query_template
|
157
|
+
if File.zero?(@query_template)
|
158
|
+
raise "template is empty"
|
159
|
+
end
|
160
|
+
file = File.open(@query_template, 'r')
|
161
|
+
@query_dsl = file.read
|
210
162
|
end
|
211
163
|
|
164
|
+
validate_query_settings
|
212
165
|
fill_hosts_from_cloud_id
|
213
166
|
setup_ssl_params!
|
214
167
|
validate_authentication
|
@@ -217,23 +170,73 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
|
|
217
170
|
@hosts = Array(@hosts).map { |host| host.to_s } # potential SafeURI#to_s
|
218
171
|
|
219
172
|
test_connection!
|
220
|
-
validate_es_for_esql_support! if @query_type == "esql"
|
221
173
|
setup_serverless
|
222
|
-
if get_client.es_transport_client_type == "elasticsearch_transport"
|
223
|
-
require_relative "elasticsearch/patches/_elasticsearch_transport_http_manticore"
|
224
|
-
end
|
225
174
|
end # def register
|
226
175
|
|
227
176
|
def filter(event)
|
228
|
-
|
229
|
-
|
177
|
+
matched = false
|
178
|
+
begin
|
179
|
+
params = { :index => event.sprintf(@index) }
|
180
|
+
|
181
|
+
if @query_dsl
|
182
|
+
query = LogStash::Json.load(event.sprintf(@query_dsl))
|
183
|
+
params[:body] = query
|
184
|
+
else
|
185
|
+
query = event.sprintf(@query)
|
186
|
+
params[:q] = query
|
187
|
+
params[:size] = result_size
|
188
|
+
params[:sort] = @sort if @enable_sort
|
189
|
+
end
|
230
190
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
191
|
+
@logger.debug("Querying elasticsearch for lookup", :params => params)
|
192
|
+
|
193
|
+
results = get_client.search(params)
|
194
|
+
raise "Elasticsearch query error: #{results["_shards"]["failures"]}" if results["_shards"].include? "failures"
|
195
|
+
|
196
|
+
event.set("[@metadata][total_hits]", extract_total_from_hits(results['hits']))
|
197
|
+
|
198
|
+
resultsHits = results["hits"]["hits"]
|
199
|
+
if !resultsHits.nil? && !resultsHits.empty?
|
200
|
+
matched = true
|
201
|
+
@fields.each do |old_key, new_key|
|
202
|
+
old_key_path = extract_path(old_key)
|
203
|
+
set = resultsHits.map do |doc|
|
204
|
+
extract_value(doc["_source"], old_key_path)
|
205
|
+
end
|
206
|
+
event.set(new_key, set.count > 1 ? set : set.first)
|
207
|
+
end
|
208
|
+
@docinfo_fields.each do |old_key, new_key|
|
209
|
+
old_key_path = extract_path(old_key)
|
210
|
+
set = resultsHits.map do |doc|
|
211
|
+
extract_value(doc, old_key_path)
|
212
|
+
end
|
213
|
+
event.set(new_key, set.count > 1 ? set : set.first)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
resultsAggs = results["aggregations"]
|
218
|
+
if !resultsAggs.nil? && !resultsAggs.empty?
|
219
|
+
matched = true
|
220
|
+
@aggregation_fields.each do |agg_name, ls_field|
|
221
|
+
event.set(ls_field, resultsAggs[agg_name])
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
rescue => e
|
226
|
+
if @logger.trace?
|
227
|
+
@logger.warn("Failed to query elasticsearch for previous event", :index => @index, :query => query, :event => event.to_hash, :error => e.message, :backtrace => e.backtrace)
|
228
|
+
elsif @logger.debug?
|
229
|
+
@logger.warn("Failed to query elasticsearch for previous event", :index => @index, :error => e.message, :backtrace => e.backtrace)
|
230
|
+
else
|
231
|
+
@logger.warn("Failed to query elasticsearch for previous event", :index => @index, :error => e.message)
|
232
|
+
end
|
233
|
+
@tag_on_failure.each{|tag| event.tag(tag)}
|
234
|
+
else
|
235
|
+
filter_matched(event) if matched
|
236
|
+
end
|
237
|
+
end # def filter
|
235
238
|
|
236
|
-
# public only to be
|
239
|
+
# public only to be reuse in testing
|
237
240
|
def prepare_user_agent
|
238
241
|
os_name = java.lang.System.getProperty('os.name')
|
239
242
|
os_version = java.lang.System.getProperty('os.version')
|
@@ -257,8 +260,7 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
|
|
257
260
|
:ssl => client_ssl_options,
|
258
261
|
:retry_on_failure => @retry_on_failure,
|
259
262
|
:retry_on_status => @retry_on_status,
|
260
|
-
:user_agent => prepare_user_agent
|
261
|
-
:custom_headers => @custom_headers
|
263
|
+
:user_agent => prepare_user_agent
|
262
264
|
}
|
263
265
|
end
|
264
266
|
|
@@ -344,10 +346,53 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
|
|
344
346
|
end
|
345
347
|
end
|
346
348
|
|
349
|
+
# get an array of path elements from a path reference
|
350
|
+
def extract_path(path_reference)
|
351
|
+
return [path_reference] unless path_reference.start_with?('[') && path_reference.end_with?(']')
|
352
|
+
|
353
|
+
path_reference[1...-1].split('][')
|
354
|
+
end
|
355
|
+
|
356
|
+
# given a Hash and an array of path fragments, returns the value at the path
|
357
|
+
# @param source [Hash{String=>Object}]
|
358
|
+
# @param path [Array{String}]
|
359
|
+
# @return [Object]
|
360
|
+
def extract_value(source, path)
|
361
|
+
path.reduce(source) do |memo, old_key_fragment|
|
362
|
+
break unless memo.include?(old_key_fragment)
|
363
|
+
memo[old_key_fragment]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
# Given a "hits" object from an Elasticsearch response, return the total number of hits in
|
368
|
+
# the result set.
|
369
|
+
# @param hits [Hash{String=>Object}]
|
370
|
+
# @return [Integer]
|
371
|
+
def extract_total_from_hits(hits)
|
372
|
+
total = hits['total']
|
373
|
+
|
374
|
+
# Elasticsearch 7.x produces an object containing `value` and `relation` in order
|
375
|
+
# to enable unambiguous reporting when the total is only a lower bound; if we get
|
376
|
+
# an object back, return its `value`.
|
377
|
+
return total['value'] if total.kind_of?(Hash)
|
378
|
+
|
379
|
+
total
|
380
|
+
end
|
381
|
+
|
347
382
|
def hosts_default?(hosts)
|
348
383
|
hosts.is_a?(Array) && hosts.size == 1 && !original_params.key?('hosts')
|
349
384
|
end
|
350
385
|
|
386
|
+
def validate_query_settings
|
387
|
+
unless @query || @query_template
|
388
|
+
raise LogStash::ConfigurationError, "Both `query` and `query_template` are empty. Require either `query` or `query_template`."
|
389
|
+
end
|
390
|
+
|
391
|
+
if @query && @query_template
|
392
|
+
raise LogStash::ConfigurationError, "Both `query` and `query_template` are set. Use either `query` or `query_template`."
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
351
396
|
def validate_authentication
|
352
397
|
authn_options = 0
|
353
398
|
authn_options += 1 if @cloud_auth
|
@@ -434,107 +479,9 @@ class LogStash::Filters::Elasticsearch < LogStash::Filters::Base
|
|
434
479
|
end
|
435
480
|
|
436
481
|
def setup_ssl_params!
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
# Infer the value if neither the deprecate `ssl` and `ssl_enabled` were set
|
442
|
-
infer_ssl_enabled_from_hosts
|
443
|
-
|
444
|
-
@ssl_keystore_path = normalize_config(:ssl_keystore_path) do |normalize|
|
445
|
-
normalize.with_deprecated_alias(:keystore)
|
446
|
-
end
|
447
|
-
|
448
|
-
@ssl_keystore_password = normalize_config(:ssl_keystore_password) do |normalize|
|
449
|
-
normalize.with_deprecated_alias(:keystore_password)
|
450
|
-
end
|
451
|
-
|
452
|
-
@ssl_certificate_authorities = normalize_config(:ssl_certificate_authorities) do |normalize|
|
453
|
-
normalize.with_deprecated_mapping(:ca_file) do |ca_file|
|
454
|
-
[ca_file]
|
455
|
-
end
|
456
|
-
end
|
457
|
-
|
458
|
-
params['ssl_enabled'] = @ssl_enabled
|
459
|
-
params['ssl_keystore_path'] = @ssl_keystore_path unless @ssl_keystore_path.nil?
|
460
|
-
params['ssl_keystore_password'] = @ssl_keystore_password unless @ssl_keystore_password.nil?
|
461
|
-
params['ssl_certificate_authorities'] = @ssl_certificate_authorities unless @ssl_certificate_authorities.nil?
|
462
|
-
end
|
463
|
-
|
464
|
-
def infer_ssl_enabled_from_hosts
|
465
|
-
return if original_params.include?('ssl') || original_params.include?('ssl_enabled')
|
466
|
-
|
467
|
-
@ssl_enabled = params['ssl_enabled'] = effectively_ssl?
|
468
|
-
end
|
469
|
-
|
470
|
-
def effectively_ssl?
|
471
|
-
return true if @ssl_enabled
|
472
|
-
|
473
|
-
hosts = Array(@hosts)
|
474
|
-
return false if hosts.nil? || hosts.empty?
|
475
|
-
|
476
|
-
hosts.all? { |host| host && host.to_s.start_with?("https") }
|
477
|
-
end
|
478
|
-
|
479
|
-
def validate_dsl_query_settings!
|
480
|
-
#Load query if it exists
|
481
|
-
if @query_template
|
482
|
-
if File.zero?(@query_template)
|
483
|
-
raise "template is empty"
|
484
|
-
end
|
485
|
-
file = File.open(@query_template, 'r')
|
486
|
-
@query_dsl = file.read
|
487
|
-
end
|
488
|
-
|
489
|
-
validate_query_settings
|
490
|
-
end
|
491
|
-
|
492
|
-
def validate_query_settings
|
493
|
-
unless @query || @query_template
|
494
|
-
raise LogStash::ConfigurationError, "Both `query` and `query_template` are empty. Require either `query` or `query_template`."
|
495
|
-
end
|
496
|
-
|
497
|
-
if @query && @query_template
|
498
|
-
raise LogStash::ConfigurationError, "Both `query` and `query_template` are set. Use either `query` or `query_template`."
|
499
|
-
end
|
500
|
-
|
501
|
-
if original_params.keys.include?("query_params")
|
502
|
-
raise LogStash::ConfigurationError, "`query_params` is not allowed when `query_type => 'dsl'`."
|
503
|
-
end
|
504
|
-
end
|
505
|
-
|
506
|
-
def validate_ls_version_for_esql_support!
|
507
|
-
if Gem::Version.create(LOGSTASH_VERSION) < Gem::Version.create(LS_ESQL_SUPPORT_VERSION)
|
508
|
-
fail("Current version of Logstash does not include Elasticsearch client which supports ES|QL. Please upgrade Logstash to at least #{LS_ESQL_SUPPORT_VERSION}")
|
509
|
-
end
|
510
|
-
end
|
511
|
-
|
512
|
-
def validate_esql_query_and_params!
|
513
|
-
# If Array, validate that query_params needs to contain only single-entry hashes, convert it to a Hash
|
514
|
-
if @query_params.kind_of?(Array)
|
515
|
-
illegal_entries = @query_params.reject {|e| e.kind_of?(Hash) && e.size == 1 }
|
516
|
-
raise LogStash::ConfigurationError, "`query_params` must contain only single-entry hashes. Illegal placeholders: #{illegal_entries}" if illegal_entries.any?
|
517
|
-
|
518
|
-
@query_params = @query_params.reduce({}, :merge)
|
519
|
-
end
|
520
|
-
|
521
|
-
illegal_keys = @query_params.keys.reject {|k| k[/^[a-z_][a-z0-9_]*$/] }
|
522
|
-
if illegal_keys.any?
|
523
|
-
message = "Illegal #{illegal_keys} placeholder names in `query_params`. A valid parameter name starts with a letter and contains letters, digits and underscores only;"
|
524
|
-
raise LogStash::ConfigurationError, message
|
525
|
-
end
|
526
|
-
|
527
|
-
placeholders = @query.scan(/(?<=[?])[a-z_][a-z0-9_]*/i)
|
528
|
-
placeholders.each do |placeholder|
|
529
|
-
raise LogStash::ConfigurationError, "Placeholder #{placeholder} not found in query" unless @query_params.include?(placeholder)
|
530
|
-
end
|
531
|
-
end
|
532
|
-
|
533
|
-
def validate_es_for_esql_support!
|
534
|
-
# make sure connected ES supports ES|QL (8.11+)
|
535
|
-
@es_version ||= get_client.es_version
|
536
|
-
es_supports_esql = Gem::Version.create(@es_version) >= Gem::Version.create(ES_ESQL_SUPPORT_VERSION)
|
537
|
-
fail("Connected Elasticsearch #{@es_version} version does not supports ES|QL. ES|QL feature requires at least Elasticsearch #{ES_ESQL_SUPPORT_VERSION} version.") unless es_supports_esql
|
482
|
+
# Infer the value if neither `ssl_enabled` was not set
|
483
|
+
return if original_params.include?('ssl_enabled')
|
484
|
+
params['ssl_enabled'] = @ssl_enabled ||= Array(@hosts).all? { |host| host && host.to_s.start_with?("https") }
|
538
485
|
end
|
539
486
|
|
540
487
|
end #class LogStash::Filters::Elasticsearch
|
@@ -1,13 +1,13 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-filter-elasticsearch'
|
4
|
-
s.version = '
|
4
|
+
s.version = '4.0.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"
|
8
8
|
s.authors = ["Elastic"]
|
9
9
|
s.email = 'info@elastic.co'
|
10
|
-
s.homepage = "
|
10
|
+
s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
|
11
11
|
s.require_paths = ["lib"]
|
12
12
|
|
13
13
|
# Files
|
@@ -21,12 +21,9 @@ Gem::Specification.new do |s|
|
|
21
21
|
|
22
22
|
# Gem dependencies
|
23
23
|
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
|
24
|
-
s.add_runtime_dependency 'elasticsearch', ">= 7.14.9"
|
24
|
+
s.add_runtime_dependency 'elasticsearch', ">= 7.14.9" # LS >= 6.7 and < 7.14 all used version 5.0.5
|
25
25
|
s.add_runtime_dependency 'manticore', ">= 0.7.1"
|
26
|
-
s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~> 1.3'
|
27
26
|
s.add_runtime_dependency 'logstash-mixin-ca_trusted_fingerprint_support', '~> 1.0'
|
28
|
-
s.add_runtime_dependency 'logstash-mixin-normalize_config_support', '~>1.0'
|
29
|
-
s.add_runtime_dependency 'logstash-mixin-validator_support', '~> 1.0'
|
30
27
|
s.add_development_dependency 'cabin', ['~> 0.6']
|
31
28
|
s.add_development_dependency 'webrick'
|
32
29
|
s.add_development_dependency 'logstash-devutils'
|