logstash-input-elasticsearch 4.9.0 → 4.12.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -3
- data/Gemfile +3 -0
- data/README.md +1 -1
- data/docs/index.asciidoc +48 -25
- data/lib/logstash/inputs/{patch.rb → elasticsearch/patches/_elasticsearch_transport_connections_selector.rb} +9 -6
- data/lib/logstash/inputs/elasticsearch/patches/_elasticsearch_transport_http_manticore.rb +43 -0
- data/lib/logstash/inputs/elasticsearch.rb +75 -42
- data/logstash-input-elasticsearch.gemspec +9 -8
- data/spec/es_helper.rb +21 -19
- data/spec/fixtures/test_certs/ca.crt +20 -0
- data/spec/fixtures/test_certs/ca.key +27 -0
- data/spec/fixtures/test_certs/es.crt +20 -0
- data/spec/fixtures/test_certs/es.key +27 -0
- data/spec/inputs/elasticsearch_spec.rb +355 -152
- data/spec/inputs/integration/elasticsearch_spec.rb +79 -23
- metadata +69 -55
- data/spec/fixtures/test_certs/ca/ca.crt +0 -32
- data/spec/fixtures/test_certs/ca/ca.key +0 -51
- data/spec/fixtures/test_certs/test.crt +0 -36
- data/spec/fixtures/test_certs/test.key +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a4ed685c9f90446a47fc84cb4e52e585f164c5451c9dca3f7359b756077bbd4
|
4
|
+
data.tar.gz: 050b54e5c660a4ab436f57ab16ea20d6a64a6b8a8c063eaaca69cc2c77235bd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 902070db657622bd65bcba8c17470456366134aae23cd38fb70ec89c97686b74da591e6f47d34957f3e5753f0e029ad78b845dd6355d6d559b6c135e0c94d28e
|
7
|
+
data.tar.gz: 22391299a87f5ce0a3085b4be7886a7f7251c9e33bd7051996871ea7cc34cbd7fbc53a3d54d841722b319949c4422e0ab7e6ff7d04899db6255543363fc32f66
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,34 @@
|
|
1
|
+
## 4.12.3
|
2
|
+
- Fix: update Elasticsearch Ruby client to correctly customize 'user-agent' header[#171](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/171)
|
3
|
+
|
4
|
+
## 4.12.2
|
5
|
+
- Fix: hosts => "es_host:port" regression [#168](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/168)
|
6
|
+
|
7
|
+
## 4.12.1
|
8
|
+
- Fixed too_long_frame_exception by passing scroll_id in the body [#159](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/159)
|
9
|
+
|
10
|
+
## 4.12.0
|
11
|
+
- Feat: Update Elasticsearch client to 7.14.0 [#157](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/157)
|
12
|
+
|
13
|
+
## 4.11.0
|
14
|
+
- Feat: add user-agent header passed to the Elasticsearch HTTP connection [#158](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/158)
|
15
|
+
|
16
|
+
## 4.10.0
|
17
|
+
- Feat: added ecs_compatibility + event_factory support [#149](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/149)
|
18
|
+
|
19
|
+
## 4.9.3
|
20
|
+
- Fixed SSL handshake hang indefinitely with proxy setup [#156](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/156)
|
21
|
+
|
22
|
+
## 4.9.2
|
23
|
+
- Fix: a regression (in LS 7.14.0) where due the elasticsearch client update (from 5.0.5 to 7.5.0) the `Authorization`
|
24
|
+
header isn't passed, this leads to the plugin not being able to leverage `user`/`password` credentials set by the user.
|
25
|
+
[#153](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/153)
|
26
|
+
|
27
|
+
|
28
|
+
## 4.9.1
|
29
|
+
- [DOC] Replaced hard-coded links with shared attributes [#143](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/143)
|
30
|
+
- [DOC] Added missing quote to docinfo_fields example [#145](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/145)
|
31
|
+
|
1
32
|
## 4.9.0
|
2
33
|
- Added `target` option, allowing the hit's source to target a specific field instead of being expanded at the root of the event. This allows the input to play nicer with the Elastic Common Schema when the input does not follow the schema. [#117](https://github.com/logstash-plugins/logstash-input-elasticsearch/issues/117)
|
3
34
|
|
@@ -33,7 +64,7 @@
|
|
33
64
|
- Feat: Added support for cloud_id / cloud_auth configuration [#112](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/112)
|
34
65
|
|
35
66
|
## 4.4.0
|
36
|
-
- Changed Elasticsearch Client transport to use Manticore [#111](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/111)
|
67
|
+
- Changed Elasticsearch Client transport to use Manticore [#111](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/111)
|
37
68
|
|
38
69
|
## 4.3.3
|
39
70
|
- Loosen restrictions on Elasticsearch gem [#110](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/110)
|
@@ -72,7 +103,7 @@
|
|
72
103
|
|
73
104
|
## 4.0.2
|
74
105
|
- Bump ES client to 5.0.2 to get content-type: json behavior
|
75
|
-
- Revert unneeded manticore change
|
106
|
+
- Revert unneeded manticore change
|
76
107
|
|
77
108
|
## 4.0.1
|
78
109
|
- Switch internal HTTP client to support TLSv1.2
|
@@ -85,7 +116,7 @@
|
|
85
116
|
behavior
|
86
117
|
- Improve documentation to show sort by \_doc, and how to add it to custom
|
87
118
|
queries.
|
88
|
-
|
119
|
+
|
89
120
|
## 3.0.2
|
90
121
|
- Relax constraint on logstash-core-plugin-api to >= 1.60 <= 2.99
|
91
122
|
|
data/Gemfile
CHANGED
@@ -9,3 +9,6 @@ if Dir.exist?(logstash_path) && use_logstash_source
|
|
9
9
|
gem 'logstash-core', :path => "#{logstash_path}/logstash-core"
|
10
10
|
gem 'logstash-core-plugin-api', :path => "#{logstash_path}/logstash-core-plugin-api"
|
11
11
|
end
|
12
|
+
|
13
|
+
gem 'manticore', ENV['MANTICORE_VERSION'] if ENV['MANTICORE_VERSION']
|
14
|
+
gem 'elasticsearch', ENV['ELASTICSEARCH_VERSION'] if ENV['ELASTICSEARCH_VERSION']
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Logstash Plugin
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/logstash-input-elasticsearch.svg)](https://badge.fury.io/rb/logstash-input-elasticsearch)
|
4
|
-
[![Travis Build Status](https://travis-ci.
|
4
|
+
[![Travis Build Status](https://travis-ci.com/logstash-plugins/logstash-input-elasticsearch.svg)](https://travis-ci.com/logstash-plugins/logstash-input-elasticsearch)
|
5
5
|
|
6
6
|
This is a plugin for [Logstash](https://github.com/elastic/logstash).
|
7
7
|
|
data/docs/index.asciidoc
CHANGED
@@ -83,8 +83,18 @@ Authentication to a secure Elasticsearch cluster is possible using _one_ of the
|
|
83
83
|
Authorization to a secure Elasticsearch cluster requires `read` permission at index level and `monitoring` permissions at cluster level.
|
84
84
|
The `monitoring` permission at cluster level is necessary to perform periodic connectivity checks.
|
85
85
|
|
86
|
+
[id="plugins-{type}s-{plugin}-ecs"]
|
87
|
+
==== Compatibility with the Elastic Common Schema (ECS)
|
88
|
+
|
89
|
+
When ECS compatibility is disabled, `docinfo_target` uses the `"@metadata"` field as a default, with ECS enabled the plugin
|
90
|
+
uses a naming convention `"[@metadata][input][elasticsearch]"` as a default target for placing document information.
|
91
|
+
|
92
|
+
The plugin logs a warning when ECS is enabled and `target` isn't set.
|
93
|
+
|
94
|
+
TIP: Set the `target` option to avoid potential schema conflicts.
|
95
|
+
|
86
96
|
[id="plugins-{type}s-{plugin}-options"]
|
87
|
-
==== Elasticsearch Input
|
97
|
+
==== Elasticsearch Input configuration options
|
88
98
|
|
89
99
|
This plugin supports the following configuration options plus the <<plugins-{type}s-{plugin}-common-options>> described later.
|
90
100
|
|
@@ -99,6 +109,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
|
|
99
109
|
| <<plugins-{type}s-{plugin}-docinfo>> |<<boolean,boolean>>|No
|
100
110
|
| <<plugins-{type}s-{plugin}-docinfo_fields>> |<<array,array>>|No
|
101
111
|
| <<plugins-{type}s-{plugin}-docinfo_target>> |<<string,string>>|No
|
112
|
+
| <<plugins-{type}s-{plugin}-ecs_compatibility>> |<<string,string>>|No
|
102
113
|
| <<plugins-{type}s-{plugin}-hosts>> |<<array,array>>|No
|
103
114
|
| <<plugins-{type}s-{plugin}-index>> |<<string,string>>|No
|
104
115
|
| <<plugins-{type}s-{plugin}-password>> |<<password,password>>|No
|
@@ -111,7 +122,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
|
|
111
122
|
| <<plugins-{type}s-{plugin}-slices>> |<<number,number>>|No
|
112
123
|
| <<plugins-{type}s-{plugin}-ssl>> |<<boolean,boolean>>|No
|
113
124
|
| <<plugins-{type}s-{plugin}-socket_timeout_seconds>> | <<number,number>>|No
|
114
|
-
| <<plugins-{type}s-{plugin}-target>> |
|
125
|
+
| <<plugins-{type}s-{plugin}-target>> | {logstash-ref}/field-references-deepdive.html[field reference] | No
|
115
126
|
| <<plugins-{type}s-{plugin}-user>> |<<string,string>>|No
|
116
127
|
|=======================================================================
|
117
128
|
|
@@ -130,7 +141,7 @@ Authenticate using Elasticsearch API key. Note that this option also requires en
|
|
130
141
|
|
131
142
|
Format is `id:api_key` where `id` and `api_key` are as returned by the
|
132
143
|
Elasticsearch
|
133
|
-
|
144
|
+
{ref}/security-api-create-api-key.html[Create
|
134
145
|
API key API].
|
135
146
|
|
136
147
|
[id="plugins-{type}s-{plugin}-ca_file"]
|
@@ -150,8 +161,7 @@ SSL Certificate Authority file in PEM encoded format, must also include any chai
|
|
150
161
|
Cloud authentication string ("<username>:<password>" format) is an alternative for the `user`/`password` pair.
|
151
162
|
|
152
163
|
For more info, check out the
|
153
|
-
|
154
|
-
documentation]
|
164
|
+
{logstash-ref}/connecting-to-cloud.html[Logstash-to-Cloud documentation].
|
155
165
|
|
156
166
|
[id="plugins-{type}s-{plugin}-cloud_id"]
|
157
167
|
===== `cloud_id`
|
@@ -162,8 +172,7 @@ documentation]
|
|
162
172
|
Cloud ID, from the Elastic Cloud web console. If set `hosts` should not be used.
|
163
173
|
|
164
174
|
For more info, check out the
|
165
|
-
|
166
|
-
documentation]
|
175
|
+
{logstash-ref}/connecting-to-cloud.html[Logstash-to-Cloud documentation].
|
167
176
|
|
168
177
|
[id="plugins-{type}s-{plugin}-connect_timeout_seconds"]
|
169
178
|
===== `connect_timeout_seconds`
|
@@ -199,13 +208,14 @@ Example
|
|
199
208
|
size => 500
|
200
209
|
scroll => "5m"
|
201
210
|
docinfo => true
|
211
|
+
docinfo_target => "[@metadata][doc]"
|
202
212
|
}
|
203
213
|
}
|
204
214
|
output {
|
205
215
|
elasticsearch {
|
206
|
-
index => "copy-of-production.%{[@metadata][_index]}"
|
207
|
-
document_type => "%{[@metadata][_type]}"
|
208
|
-
document_id => "%{[@metadata][_id]}"
|
216
|
+
index => "copy-of-production.%{[@metadata][doc][_index]}"
|
217
|
+
document_type => "%{[@metadata][doc][_type]}"
|
218
|
+
document_id => "%{[@metadata][doc][_id]}"
|
209
219
|
}
|
210
220
|
}
|
211
221
|
|
@@ -216,8 +226,9 @@ Example
|
|
216
226
|
input {
|
217
227
|
elasticsearch {
|
218
228
|
docinfo => true
|
229
|
+
docinfo_target => "[@metadata][doc]"
|
219
230
|
add_field => {
|
220
|
-
identifier => %{[@metadata][_index]}:%{[@metadata][_type]}:%{[@metadata][_id]}"
|
231
|
+
identifier => "%{[@metadata][doc][_index]}:%{[@metadata][doc][_type]}:%{[@metadata][doc][_id]}"
|
221
232
|
}
|
222
233
|
}
|
223
234
|
}
|
@@ -238,11 +249,25 @@ more information.
|
|
238
249
|
===== `docinfo_target`
|
239
250
|
|
240
251
|
* Value type is <<string,string>>
|
241
|
-
* Default value is
|
252
|
+
* Default value depends on whether <<plugins-{type}s-{plugin}-ecs_compatibility>> is enabled:
|
253
|
+
** ECS Compatibility disabled: `"@metadata"`
|
254
|
+
** ECS Compatibility enabled: `"[@metadata][input][elasticsearch]"`
|
255
|
+
|
256
|
+
If document metadata storage is requested by enabling the `docinfo` option,
|
257
|
+
this option names the field under which to store the metadata fields as subfields.
|
258
|
+
|
259
|
+
[id="plugins-{type}s-{plugin}-ecs_compatibility"]
|
260
|
+
===== `ecs_compatibility`
|
261
|
+
|
262
|
+
* Value type is <<string,string>>
|
263
|
+
* Supported values are:
|
264
|
+
** `disabled`: CSV data added at root level
|
265
|
+
** `v1`,`v8`: Elastic Common Schema compliant behavior
|
266
|
+
* Default value depends on which version of Logstash is running:
|
267
|
+
** When Logstash provides a `pipeline.ecs_compatibility` setting, its value is used as the default
|
268
|
+
** Otherwise, the default value is `disabled`
|
242
269
|
|
243
|
-
|
244
|
-
option, this option names the field under which to store the metadata
|
245
|
-
fields as subfields.
|
270
|
+
Controls this plugin's compatibility with the {ecs-ref}[Elastic Common Schema (ECS)].
|
246
271
|
|
247
272
|
[id="plugins-{type}s-{plugin}-hosts"]
|
248
273
|
===== `hosts`
|
@@ -260,10 +285,9 @@ can be either IP, HOST, IP:port, or HOST:port. The port defaults to
|
|
260
285
|
* Value type is <<string,string>>
|
261
286
|
* Default value is `"logstash-*"`
|
262
287
|
|
263
|
-
The index or alias to search. See
|
264
|
-
|
265
|
-
|
266
|
-
multiple indices.
|
288
|
+
The index or alias to search. See {ref}/multi-index.html[Multi Indices
|
289
|
+
documentation] in the Elasticsearch documentation for more information on how to
|
290
|
+
reference multiple indices.
|
267
291
|
|
268
292
|
|
269
293
|
[id="plugins-{type}s-{plugin}-password"]
|
@@ -292,9 +316,8 @@ environment variables e.g. `proxy => '${LS_PROXY:}'`.
|
|
292
316
|
* Value type is <<string,string>>
|
293
317
|
* Default value is `'{ "sort": [ "_doc" ] }'`
|
294
318
|
|
295
|
-
The query to be executed. Read the
|
296
|
-
|
297
|
-
for more information.
|
319
|
+
The query to be executed. Read the {ref}/query-dsl.html[Elasticsearch query DSL
|
320
|
+
documentation] for more information.
|
298
321
|
|
299
322
|
[id="plugins-{type}s-{plugin}-request_timeout_seconds"]
|
300
323
|
===== `request_timeout_seconds`
|
@@ -345,7 +368,7 @@ This allows you to set the maximum number of hits returned per scroll.
|
|
345
368
|
|
346
369
|
In some cases, it is possible to improve overall throughput by consuming multiple
|
347
370
|
distinct slices of a query simultaneously using
|
348
|
-
|
371
|
+
{ref}/paginate-search-results.html#slice-scroll[sliced scrolls],
|
349
372
|
especially if the pipeline is spending significant time waiting on Elasticsearch
|
350
373
|
to provide results.
|
351
374
|
|
@@ -382,7 +405,7 @@ Socket timeouts usually occur while waiting for the first byte of a response, su
|
|
382
405
|
[id="plugins-{type}s-{plugin}-target"]
|
383
406
|
===== `target`
|
384
407
|
|
385
|
-
* Value type is
|
408
|
+
* Value type is {logstash-ref}/field-references-deepdive.html[field reference]
|
386
409
|
* There is no default value for this setting.
|
387
410
|
|
388
411
|
Without a `target`, events are created from each hit's `_source` at the root level.
|
@@ -406,4 +429,4 @@ empty string authentication will be disabled.
|
|
406
429
|
[id="plugins-{type}s-{plugin}-common-options"]
|
407
430
|
include::{include_path}/{type}.asciidoc[]
|
408
431
|
|
409
|
-
:
|
432
|
+
:no_codec!:
|
@@ -1,10 +1,13 @@
|
|
1
|
-
|
1
|
+
require 'elasticsearch'
|
2
|
+
require 'elasticsearch/transport/transport/connections/selector'
|
3
|
+
|
4
|
+
if Gem.loaded_specs['elasticsearch-transport'].version < Gem::Version.new("7.2.0")
|
2
5
|
# elasticsearch-transport versions prior to 7.2.0 suffered of a race condition on accessing
|
3
|
-
# the connection pool. This issue was fixed
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
# the connection pool. This issue was fixed (in 7.2.0) with
|
7
|
+
# https://github.com/elastic/elasticsearch-ruby/commit/15f9d78591a6e8823948494d94b15b0ca38819d1
|
8
|
+
#
|
9
|
+
# This plugin, at the moment, is using elasticsearch >= 5.0.5
|
10
|
+
# When this requirement ceases, this patch could be removed.
|
8
11
|
module Elasticsearch
|
9
12
|
module Transport
|
10
13
|
module Transport
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "elasticsearch"
|
3
|
+
require "elasticsearch/transport/transport/http/manticore"
|
4
|
+
|
5
|
+
es_client_version = Gem.loaded_specs['elasticsearch-transport'].version
|
6
|
+
if es_client_version >= Gem::Version.new('7.2') && es_client_version < Gem::Version.new('7.16')
|
7
|
+
# elasticsearch-transport 7.2.0 - 7.14.0 had a bug where setting http headers
|
8
|
+
# ES::Client.new ..., transport_options: { headers: { 'Authorization' => ... } }
|
9
|
+
# would be lost https://github.com/elastic/elasticsearch-ruby/issues/1428
|
10
|
+
#
|
11
|
+
# NOTE: needs to be idempotent as filter ES plugin might apply the same patch!
|
12
|
+
#
|
13
|
+
# @private
|
14
|
+
module Elasticsearch
|
15
|
+
module Transport
|
16
|
+
module Transport
|
17
|
+
module HTTP
|
18
|
+
class Manticore
|
19
|
+
|
20
|
+
def apply_headers(request_options, options)
|
21
|
+
headers = (options && options[:headers]) || {}
|
22
|
+
headers[CONTENT_TYPE_STR] = find_value(headers, CONTENT_TYPE_REGEX) || DEFAULT_CONTENT_TYPE
|
23
|
+
|
24
|
+
# this code is necessary to grab the correct user-agent header
|
25
|
+
# when this method is invoked with apply_headers(@request_options, options)
|
26
|
+
# from https://github.com/elastic/elasticsearch-ruby/blob/v7.14.0/elasticsearch-transport/lib/elasticsearch/transport/transport/http/manticore.rb#L113-L114
|
27
|
+
transport_user_agent = nil
|
28
|
+
if (options && options[:transport_options] && options[:transport_options][:headers])
|
29
|
+
transport_headers = options[:transport_options][:headers]
|
30
|
+
transport_user_agent = find_value(transport_headers, USER_AGENT_REGEX)
|
31
|
+
end
|
32
|
+
|
33
|
+
headers[USER_AGENT_STR] = transport_user_agent || find_value(headers, USER_AGENT_REGEX) || user_agent_header
|
34
|
+
headers[ACCEPT_ENCODING] = GZIP if use_compression?
|
35
|
+
(request_options[:headers] ||= {}).merge!(headers) # this line was changed
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -4,9 +4,15 @@ require "logstash/namespace"
|
|
4
4
|
require "logstash/json"
|
5
5
|
require "logstash/util/safe_uri"
|
6
6
|
require 'logstash/plugin_mixins/validator_support/field_reference_validation_adapter'
|
7
|
+
require 'logstash/plugin_mixins/event_support/event_factory_adapter'
|
8
|
+
require 'logstash/plugin_mixins/ecs_compatibility_support'
|
9
|
+
require 'logstash/plugin_mixins/ecs_compatibility_support/target_check'
|
7
10
|
require "base64"
|
8
|
-
require_relative "patch"
|
9
11
|
|
12
|
+
require "elasticsearch"
|
13
|
+
require "elasticsearch/transport/transport/http/manticore"
|
14
|
+
require_relative "elasticsearch/patches/_elasticsearch_transport_http_manticore"
|
15
|
+
require_relative "elasticsearch/patches/_elasticsearch_transport_connections_selector"
|
10
16
|
|
11
17
|
# .Compatibility Note
|
12
18
|
# [NOTE]
|
@@ -63,12 +69,16 @@ require_relative "patch"
|
|
63
69
|
#
|
64
70
|
#
|
65
71
|
class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
|
72
|
+
|
73
|
+
include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled, :v1, :v8 => :v1)
|
74
|
+
include LogStash::PluginMixins::ECSCompatibilitySupport::TargetCheck
|
75
|
+
|
76
|
+
include LogStash::PluginMixins::EventSupport::EventFactoryAdapter
|
77
|
+
|
66
78
|
extend LogStash::PluginMixins::ValidatorSupport::FieldReferenceValidationAdapter
|
67
79
|
|
68
80
|
config_name "elasticsearch"
|
69
81
|
|
70
|
-
default :codec, "json"
|
71
|
-
|
72
82
|
# List of elasticsearch hosts to use for querying.
|
73
83
|
# Each host can be either IP, HOST, IP:port or HOST:port.
|
74
84
|
# Port defaults to 9200
|
@@ -125,8 +135,9 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
|
|
125
135
|
#
|
126
136
|
config :docinfo, :validate => :boolean, :default => false
|
127
137
|
|
128
|
-
# Where to move the Elasticsearch document information.
|
129
|
-
|
138
|
+
# Where to move the Elasticsearch document information.
|
139
|
+
# default: [@metadata][input][elasticsearch] in ECS mode, @metadata field otherwise
|
140
|
+
config :docinfo_target, :validate=> :field_reference
|
130
141
|
|
131
142
|
# List of document metadata to move to the `docinfo_target` field.
|
132
143
|
# To learn more about Elasticsearch metadata fields read
|
@@ -181,10 +192,16 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
|
|
181
192
|
# If set, the _source of each hit will be added nested under the target instead of at the top-level
|
182
193
|
config :target, :validate => :field_reference
|
183
194
|
|
195
|
+
def initialize(params={})
|
196
|
+
super(params)
|
197
|
+
|
198
|
+
if docinfo_target.nil?
|
199
|
+
@docinfo_target = ecs_select[disabled: '@metadata', v1: '[@metadata][input][elasticsearch]']
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
184
203
|
def register
|
185
|
-
require "elasticsearch"
|
186
204
|
require "rufus/scheduler"
|
187
|
-
require "elasticsearch/transport/transport/http/manticore"
|
188
205
|
|
189
206
|
@options = {
|
190
207
|
:index => @index,
|
@@ -205,6 +222,7 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
|
|
205
222
|
transport_options = {:headers => {}}
|
206
223
|
transport_options[:headers].merge!(setup_basic_auth(user, password))
|
207
224
|
transport_options[:headers].merge!(setup_api_key(api_key))
|
225
|
+
transport_options[:headers].merge!({'user-agent' => prepare_user_agent()})
|
208
226
|
transport_options[:request_timeout] = @request_timeout_seconds unless @request_timeout_seconds.nil?
|
209
227
|
transport_options[:connect_timeout] = @connect_timeout_seconds unless @connect_timeout_seconds.nil?
|
210
228
|
transport_options[:socket_timeout] = @socket_timeout_seconds unless @socket_timeout_seconds.nil?
|
@@ -222,10 +240,11 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
|
|
222
240
|
:transport_class => ::Elasticsearch::Transport::Transport::HTTP::Manticore,
|
223
241
|
:ssl => ssl_options
|
224
242
|
)
|
243
|
+
test_connection!
|
244
|
+
@client
|
225
245
|
end
|
226
246
|
|
227
247
|
|
228
|
-
|
229
248
|
def run(output_queue)
|
230
249
|
if @schedule
|
231
250
|
@scheduler = Rufus::Scheduler.new(:max_work_threads => 1)
|
@@ -267,7 +286,6 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
|
|
267
286
|
|
268
287
|
logger.info("Slice starting", slice_id: slice_id, slices: @slices) unless slice_id.nil?
|
269
288
|
|
270
|
-
scroll_id = nil
|
271
289
|
begin
|
272
290
|
r = search_request(slice_options)
|
273
291
|
|
@@ -298,47 +316,41 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
|
|
298
316
|
[r['hits']['hits'].any?, r['_scroll_id']]
|
299
317
|
rescue => e
|
300
318
|
# this will typically be triggered by a scroll timeout
|
301
|
-
logger.error("Scroll request error, aborting scroll",
|
319
|
+
logger.error("Scroll request error, aborting scroll", message: e.message, exception: e.class)
|
302
320
|
# return no hits and original scroll_id so we can try to clear it
|
303
321
|
[false, scroll_id]
|
304
322
|
end
|
305
323
|
|
306
324
|
def push_hit(hit, output_queue)
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
end
|
313
|
-
|
314
|
-
if @docinfo
|
315
|
-
# do not assume event[@docinfo_target] to be in-place updatable. first get it, update it, then at the end set it in the event.
|
316
|
-
docinfo_target = event.get(@docinfo_target) || {}
|
317
|
-
|
318
|
-
unless docinfo_target.is_a?(Hash)
|
319
|
-
@logger.error("Elasticsearch Input: Incompatible Event, incompatible type for the docinfo_target=#{@docinfo_target} field in the `_source` document, expected a hash got:", :docinfo_target_type => docinfo_target.class, :event => event)
|
325
|
+
event = targeted_event_factory.new_event hit['_source']
|
326
|
+
set_docinfo_fields(hit, event) if @docinfo
|
327
|
+
decorate(event)
|
328
|
+
output_queue << event
|
329
|
+
end
|
320
330
|
|
321
|
-
|
322
|
-
|
323
|
-
|
331
|
+
def set_docinfo_fields(hit, event)
|
332
|
+
# do not assume event[@docinfo_target] to be in-place updatable. first get it, update it, then at the end set it in the event.
|
333
|
+
docinfo_target = event.get(@docinfo_target) || {}
|
324
334
|
|
325
|
-
|
326
|
-
|
327
|
-
end
|
335
|
+
unless docinfo_target.is_a?(Hash)
|
336
|
+
@logger.error("Incompatible Event, incompatible type for the docinfo_target=#{@docinfo_target} field in the `_source` document, expected a hash got:", :docinfo_target_type => docinfo_target.class, :event => event.to_hash_with_metadata)
|
328
337
|
|
329
|
-
|
338
|
+
# TODO: (colin) I am not sure raising is a good strategy here?
|
339
|
+
raise Exception.new("Elasticsearch input: incompatible event")
|
330
340
|
end
|
331
341
|
|
332
|
-
|
342
|
+
@docinfo_fields.each do |field|
|
343
|
+
docinfo_target[field] = hit[field]
|
344
|
+
end
|
333
345
|
|
334
|
-
|
346
|
+
event.set(@docinfo_target, docinfo_target)
|
335
347
|
end
|
336
348
|
|
337
349
|
def clear_scroll(scroll_id)
|
338
|
-
@client.clear_scroll(
|
350
|
+
@client.clear_scroll(:body => { :scroll_id => scroll_id }) if scroll_id
|
339
351
|
rescue => e
|
340
352
|
# ignore & log any clear_scroll errors
|
341
|
-
logger.warn("Ignoring clear_scroll exception", message: e.message)
|
353
|
+
logger.warn("Ignoring clear_scroll exception", message: e.message, exception: e.class)
|
342
354
|
end
|
343
355
|
|
344
356
|
def scroll_request scroll_id
|
@@ -374,13 +386,13 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
|
|
374
386
|
|
375
387
|
def setup_hosts
|
376
388
|
@hosts = Array(@hosts).map { |host| host.to_s } # potential SafeURI#to_s
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
389
|
+
@hosts.map do |h|
|
390
|
+
if h.start_with?('http:', 'https:')
|
391
|
+
h
|
392
|
+
else
|
393
|
+
host, port = h.split(':')
|
394
|
+
{ host: host, port: port, scheme: (@ssl ? 'https' : 'http') }
|
381
395
|
end
|
382
|
-
else
|
383
|
-
@hosts
|
384
396
|
end
|
385
397
|
end
|
386
398
|
|
@@ -388,14 +400,26 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
|
|
388
400
|
return {} unless user && password && password.value
|
389
401
|
|
390
402
|
token = ::Base64.strict_encode64("#{user}:#{password.value}")
|
391
|
-
{ Authorization
|
403
|
+
{ 'Authorization' => "Basic #{token}" }
|
392
404
|
end
|
393
405
|
|
394
406
|
def setup_api_key(api_key)
|
395
407
|
return {} unless (api_key && api_key.value)
|
396
408
|
|
397
409
|
token = ::Base64.strict_encode64(api_key.value)
|
398
|
-
{ Authorization
|
410
|
+
{ 'Authorization' => "ApiKey #{token}" }
|
411
|
+
end
|
412
|
+
|
413
|
+
def prepare_user_agent
|
414
|
+
os_name = java.lang.System.getProperty('os.name')
|
415
|
+
os_version = java.lang.System.getProperty('os.version')
|
416
|
+
os_arch = java.lang.System.getProperty('os.arch')
|
417
|
+
jvm_vendor = java.lang.System.getProperty('java.vendor')
|
418
|
+
jvm_version = java.lang.System.getProperty('java.version')
|
419
|
+
|
420
|
+
plugin_version = Gem.loaded_specs["logstash-input-elasticsearch"].version
|
421
|
+
# example: logstash/7.14.1 (OS=Linux-5.4.0-84-generic-amd64; JVM=AdoptOpenJDK-11.0.11) logstash-input-elasticsearch/4.10.0
|
422
|
+
"logstash/#{LOGSTASH_VERSION} (OS=#{os_name}-#{os_version}-#{os_arch}; JVM=#{jvm_vendor}-#{jvm_version}) logstash-#{@plugin_type}-#{config_name}/#{plugin_version}"
|
399
423
|
end
|
400
424
|
|
401
425
|
def fill_user_password_from_cloud_auth
|
@@ -448,6 +472,15 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
|
|
448
472
|
[ cloud_auth.username, cloud_auth.password ]
|
449
473
|
end
|
450
474
|
|
475
|
+
# @private used by unit specs
|
476
|
+
attr_reader :client
|
477
|
+
|
478
|
+
def test_connection!
|
479
|
+
@client.ping
|
480
|
+
rescue Elasticsearch::UnsupportedProductError
|
481
|
+
raise LogStash::ConfigurationError, "Could not connect to a compatible version of Elasticsearch"
|
482
|
+
end
|
483
|
+
|
451
484
|
module URIOrEmptyValidator
|
452
485
|
##
|
453
486
|
# @override to provide :uri_or_empty validator
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-input-elasticsearch'
|
4
|
-
s.version = '4.
|
4
|
+
s.version = '4.12.3'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "Reads query results from an Elasticsearch cluster"
|
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"
|
@@ -20,20 +20,21 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
|
21
21
|
|
22
22
|
# Gem dependencies
|
23
|
-
s.add_runtime_dependency "logstash-mixin-validator_support", '~> 1.0'
|
24
23
|
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
|
24
|
+
s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~> 1.3'
|
25
|
+
s.add_runtime_dependency 'logstash-mixin-event_support', '~> 1.0'
|
26
|
+
s.add_runtime_dependency "logstash-mixin-validator_support", '~> 1.0'
|
25
27
|
|
26
|
-
s.add_runtime_dependency 'elasticsearch', '>=
|
28
|
+
s.add_runtime_dependency 'elasticsearch', '>= 7.17.1'
|
27
29
|
|
28
|
-
s.add_runtime_dependency 'logstash-codec-json'
|
29
|
-
s.add_runtime_dependency 'logstash-codec-plain'
|
30
|
-
s.add_runtime_dependency 'sequel'
|
31
30
|
s.add_runtime_dependency 'tzinfo'
|
32
31
|
s.add_runtime_dependency 'tzinfo-data'
|
33
32
|
s.add_runtime_dependency 'rufus-scheduler'
|
34
|
-
s.add_runtime_dependency 'manticore', "
|
35
|
-
s.add_runtime_dependency 'faraday', "~> 0.15.4"
|
33
|
+
s.add_runtime_dependency 'manticore', ">= 0.7.1"
|
36
34
|
|
35
|
+
s.add_development_dependency 'logstash-codec-plain'
|
37
36
|
s.add_development_dependency 'logstash-devutils'
|
38
37
|
s.add_development_dependency 'timecop'
|
38
|
+
s.add_development_dependency 'cabin', ['~> 0.6']
|
39
|
+
s.add_development_dependency 'webrick'
|
39
40
|
end
|
data/spec/es_helper.rb
CHANGED
@@ -1,30 +1,32 @@
|
|
1
1
|
module ESHelper
|
2
2
|
def self.get_host_port
|
3
|
-
|
4
|
-
|
3
|
+
if ENV["INTEGRATION"] == "true" || ENV["SECURE_INTEGRATION"] == "true"
|
4
|
+
"elasticsearch:9200"
|
5
|
+
else
|
6
|
+
"localhost:9200" # for local running integration specs outside docker
|
7
|
+
end
|
5
8
|
end
|
6
9
|
|
7
|
-
def self.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
hosts.map! do |h|
|
14
|
-
host, port = h.split(":")
|
15
|
-
{ :host => host, :scheme => 'https', :port => port }
|
16
|
-
end
|
10
|
+
def self.curl_and_get_json_response(url, method: :get, args: nil); require 'open3'
|
11
|
+
cmd = "curl -s -v --show-error #{args} -X #{method.to_s.upcase} -k #{url}"
|
12
|
+
begin
|
13
|
+
out, err, status = Open3.capture3(cmd)
|
14
|
+
rescue Errno::ENOENT
|
15
|
+
fail "curl not available, make sure curl binary is installed and available on $PATH"
|
17
16
|
end
|
18
17
|
|
19
|
-
|
18
|
+
if status.success?
|
19
|
+
http_status = err.match(/< HTTP\/1.1 (.*?)/)[1] || '0' # < HTTP/1.1 200 OK\r\n
|
20
|
+
if http_status.strip[0].to_i > 2
|
21
|
+
warn out
|
22
|
+
fail "#{cmd.inspect} unexpected response: #{http_status}\n\n#{err}"
|
23
|
+
end
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
LogStash::Json.load(out)
|
26
|
+
else
|
27
|
+
warn out
|
28
|
+
fail "#{cmd.inspect} process failed: #{status}\n\n#{err}"
|
24
29
|
end
|
25
|
-
|
26
|
-
@client = Elasticsearch::Client.new(:hosts => hosts, :transport_options => transport_options, :ssl => ssl_options,
|
27
|
-
:transport_class => ::Elasticsearch::Transport::Transport::HTTP::Manticore)
|
28
30
|
end
|
29
31
|
|
30
32
|
def self.doc_type
|