fluent-plugin-elasticsearch 2.0.0.rc.5 → 2.0.0.rc.6
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/History.md +5 -0
- data/README.md +20 -5
- data/fluent-plugin-elasticsearch.gemspec +1 -1
- data/lib/fluent/plugin/out_elasticsearch.rb +20 -1
- data/lib/fluent/plugin/out_elasticsearch_dynamic.rb +19 -11
- data/test/plugin/test_out_elasticsearch.rb +45 -0
- data/test/plugin/test_out_elasticsearch_dynamic.rb +59 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac60b728ec23b3ba9a24a87f1b58fcf3dbf2376f
|
4
|
+
data.tar.gz: fe9d1c7d1f5c07d84a69e27bc534c6c6db5512b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51b2bf67047821e1d028acdc507d9f1f235444cd6ffa2d0f6dded6284231ef86473aed7e2e448daa89af31ff3a6cbb2a05aa17a36be5a8717a9a1473ad05941d
|
7
|
+
data.tar.gz: b5a8317b90ddd6b52a8c6cdd2fddf7f609682422bcd24308332d1a760acf990851fb3bfde16d7c6ccd7c430aeb0f1b03186e163c21b35d4a00f4b1b87242ad57
|
data/History.md
CHANGED
@@ -4,6 +4,11 @@
|
|
4
4
|
- Log ES response errors (#230)
|
5
5
|
- Use latest elasticsearch-ruby (#240)
|
6
6
|
|
7
|
+
### 2.0.0.rc.6
|
8
|
+
- Improve documentation (#304)
|
9
|
+
- Handle dynamic_config misconfigurations (#305)
|
10
|
+
- Escape basic authentication user information placeholders (#306)
|
11
|
+
|
7
12
|
### 2.0.0.rc.5
|
8
13
|
- make configurable with `ssl_version` parameter (#299)
|
9
14
|
- add `logstash_prefix_separator` config parameter (#297)
|
data/README.md
CHANGED
@@ -109,6 +109,12 @@ You can specify multiple ElasticSearch hosts with separator ",".
|
|
109
109
|
|
110
110
|
If you specify multiple hosts, this plugin will load balance updates to ElasticSearch. This is an [elasticsearch-ruby](https://github.com/elasticsearch/elasticsearch-ruby) feature, the default strategy is round-robin.
|
111
111
|
|
112
|
+
And this plugin will escape required URL encoded characters within `%{}` placeholders.
|
113
|
+
|
114
|
+
```
|
115
|
+
hosts https://%{j+hn}:%{passw@rd}@host1:443/elastic/,http://host2
|
116
|
+
```
|
117
|
+
|
112
118
|
### user, password, path, scheme, ssl_verify
|
113
119
|
|
114
120
|
If you specify this option, host and port options are ignored.
|
@@ -122,6 +128,13 @@ scheme https
|
|
122
128
|
|
123
129
|
You can specify user and password for HTTP basic auth. If used in conjunction with a hosts list, then these options will be used by default i.e. if you do not provide any of these options within the hosts listed.
|
124
130
|
|
131
|
+
And this plugin will escape required URL encoded characters within `%{}` placeholders.
|
132
|
+
|
133
|
+
```
|
134
|
+
user %{demo+}
|
135
|
+
password %{@secret}
|
136
|
+
```
|
137
|
+
|
125
138
|
Specify `ssl_verify false` to skip ssl verification (defaults to true)
|
126
139
|
|
127
140
|
### logstash_format
|
@@ -132,6 +145,8 @@ logstash_format true # defaults to false
|
|
132
145
|
|
133
146
|
This is meant to make writing data into ElasticSearch indices compatible to what [Logstash](https://www.elastic.co/products/logstash) calls them. By doing this, one could take advantage of [Kibana](https://www.elastic.co/products/kibana). See logstash_prefix and logstash_dateformat to customize this index name pattern. The index name will be `#{logstash_prefix}-#{formated_date}`
|
134
147
|
|
148
|
+
:warning: Setting this option to `true` will ignore the `index_name` setting. The default index name prefix is `logstash-`.
|
149
|
+
|
135
150
|
### logstash_prefix
|
136
151
|
|
137
152
|
```
|
@@ -185,7 +200,7 @@ For example, should your input plugin not include a `time_key` in the record but
|
|
185
200
|
By default, when inserting records in [Logstash](https://www.elastic.co/products/logstash) format, `@timestamp` is dynamically created with the time at log ingestion. If you'd like to use a custom time, include an `@timestamp` with your record.
|
186
201
|
|
187
202
|
```
|
188
|
-
{"@timestamp":"2014-04-07T000:00:00-00:00"}
|
203
|
+
{"@timestamp": "2014-04-07T000:00:00-00:00"}
|
189
204
|
```
|
190
205
|
|
191
206
|
You can specify an option `time_key` (like the option described in [tail Input Plugin](http://docs.fluentd.org/articles/in_tail)) to replace `@timestamp` key.
|
@@ -348,7 +363,7 @@ This will add the Fluentd tag in the JSON record. For instance, if you have a co
|
|
348
363
|
The record inserted into ElasticSearch would be
|
349
364
|
|
350
365
|
```
|
351
|
-
{"_key":"my.logs", "name":"Johnny Doeie"}
|
366
|
+
{"_key": "my.logs", "name": "Johnny Doeie"}
|
352
367
|
```
|
353
368
|
|
354
369
|
### id_key
|
@@ -359,10 +374,10 @@ id_key request_id # use "request_id" field as a record id in ES
|
|
359
374
|
|
360
375
|
By default, all records inserted into ElasticSearch get a random _id. This option allows to use a field in the record as an identifier.
|
361
376
|
|
362
|
-
This following record `{"name":"Johnny","request_id":"87d89af7daffad6"}` will trigger the following ElasticSearch command
|
377
|
+
This following record `{"name": "Johnny", "request_id": "87d89af7daffad6"}` will trigger the following ElasticSearch command
|
363
378
|
|
364
379
|
```
|
365
|
-
{ "index" : { "_index"
|
380
|
+
{ "index" : { "_index": "logstash-2013.01.01", "_type": "fluentd", "_id": "87d89af7daffad6" } }
|
366
381
|
{ "name": "Johnny", "request_id": "87d89af7daffad6" }
|
367
382
|
```
|
368
383
|
|
@@ -380,7 +395,7 @@ If your input is
|
|
380
395
|
ElasticSearch command would be
|
381
396
|
|
382
397
|
```
|
383
|
-
{ "index" : { "_index"
|
398
|
+
{ "index" : { "_index": "****", "_type": "****", "_id": "****", "_parent": "my_parent" } }
|
384
399
|
{ "name": "Johnny", "a_parent": "my_parent" }
|
385
400
|
```
|
386
401
|
|
@@ -3,7 +3,7 @@ $:.push File.expand_path('../lib', __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = 'fluent-plugin-elasticsearch'
|
6
|
-
s.version = '2.0.0.rc.
|
6
|
+
s.version = '2.0.0.rc.6'
|
7
7
|
s.authors = ['diogo', 'pitr']
|
8
8
|
s.email = ['pitr.vern@gmail.com', 'me@diogoterror.com']
|
9
9
|
s.description = %q{ElasticSearch output plugin for Fluent event collector}
|
@@ -121,6 +121,13 @@ module Fluent::Plugin
|
|
121
121
|
rescue LoadError
|
122
122
|
@dump_proc = Yajl.method(:dump)
|
123
123
|
end
|
124
|
+
|
125
|
+
if @user && m = @user.match(/%{(?<user>.*)}/)
|
126
|
+
@user = URI.encode_www_form_component(m["user"])
|
127
|
+
end
|
128
|
+
if @password && m = @password.match(/%{(?<password>.*)}/)
|
129
|
+
@password = URI.encode_www_form_component(m["password"])
|
130
|
+
end
|
124
131
|
end
|
125
132
|
|
126
133
|
def create_meta_config_map
|
@@ -188,6 +195,18 @@ module Fluent::Plugin
|
|
188
195
|
end
|
189
196
|
end
|
190
197
|
|
198
|
+
def get_escaped_userinfo(host_str)
|
199
|
+
if m = host_str.match(/(?<scheme>.*)%{(?<user>.*)}:%{(?<password>.*)}(?<path>@.*)/)
|
200
|
+
m["scheme"] +
|
201
|
+
URI.encode_www_form_component(m["user"]) +
|
202
|
+
':' +
|
203
|
+
URI.encode_www_form_component(m["password"]) +
|
204
|
+
m["path"]
|
205
|
+
else
|
206
|
+
host_str
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
191
210
|
def get_connection_options
|
192
211
|
raise "`password` must be present if `user` is present" if @user && !@password
|
193
212
|
|
@@ -202,7 +221,7 @@ module Fluent::Plugin
|
|
202
221
|
}
|
203
222
|
else
|
204
223
|
# New hosts format expects URLs such as http://logs.foo.com,https://john:pass@logs2.foo.com/elastic
|
205
|
-
uri = URI(host_str)
|
224
|
+
uri = URI(get_escaped_userinfo(host_str))
|
206
225
|
%w(user password path).inject(host: uri.host, port: uri.port, scheme: uri.scheme) do |hash, key|
|
207
226
|
hash[key.to_sym] = uri.public_send(key) unless uri.public_send(key).nil? || uri.public_send(key) == ''
|
208
227
|
hash
|
@@ -6,6 +6,8 @@ module Fluent::Plugin
|
|
6
6
|
|
7
7
|
Fluent::Plugin.register_output('elasticsearch_dynamic', self)
|
8
8
|
|
9
|
+
helpers :event_emitter
|
10
|
+
|
9
11
|
config_param :delimiter, :string, :default => "."
|
10
12
|
|
11
13
|
DYNAMIC_PARAM_NAMES = %W[hosts host port logstash_format logstash_prefix logstash_dateformat time_key utc_index index_name tag_key type_name id_key parent_key routing_key write_operation]
|
@@ -81,7 +83,7 @@ module Fluent::Plugin
|
|
81
83
|
}
|
82
84
|
else
|
83
85
|
# New hosts format expects URLs such as http://logs.foo.com,https://john:pass@logs2.foo.com/elastic
|
84
|
-
uri = URI(host_str)
|
86
|
+
uri = URI(get_escaped_userinfo(host_str))
|
85
87
|
%w(user password path).inject(host: uri.host, port: uri.port, scheme: uri.scheme) do |hash, key|
|
86
88
|
hash[key.to_sym] = uri.public_send(key) unless uri.public_send(key).nil? || uri.public_send(key) == ''
|
87
89
|
hash
|
@@ -128,17 +130,23 @@ module Fluent::Plugin
|
|
128
130
|
chunk.msgpack_each do |time, record|
|
129
131
|
next unless record.is_a? Hash
|
130
132
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
133
|
+
begin
|
134
|
+
# evaluate all configurations here
|
135
|
+
DYNAMIC_PARAM_SYMBOLS.each_with_index { |var, i|
|
136
|
+
k = DYNAMIC_PARAM_NAMES[i]
|
137
|
+
v = self.instance_variable_get(var)
|
138
|
+
# check here to determine if we should evaluate
|
139
|
+
if dynamic_conf[k] != v
|
140
|
+
value = expand_param(v, tag, time, record)
|
141
|
+
dynamic_conf[k] = value
|
142
|
+
end
|
143
|
+
}
|
141
144
|
# end eval all configs
|
145
|
+
rescue => e
|
146
|
+
# handle dynamic parameters misconfigurations
|
147
|
+
router.emit_error_event(tag, time, record, e)
|
148
|
+
next
|
149
|
+
end
|
142
150
|
|
143
151
|
if eval_or_val(dynamic_conf['logstash_format'])
|
144
152
|
if record.has_key?("@timestamp")
|
@@ -335,6 +335,32 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
335
335
|
assert_equal '/default_path', host2[:path]
|
336
336
|
end
|
337
337
|
|
338
|
+
def test_hosts_list_with_escape_placeholders
|
339
|
+
config = %{
|
340
|
+
hosts https://%{j+hn}:%{passw@rd}@host1:443/elastic/,http://host2
|
341
|
+
path /default_path
|
342
|
+
user default_user
|
343
|
+
password default_password
|
344
|
+
}
|
345
|
+
instance = driver(config).instance
|
346
|
+
|
347
|
+
assert_equal 2, instance.get_connection_options[:hosts].length
|
348
|
+
host1, host2 = instance.get_connection_options[:hosts]
|
349
|
+
|
350
|
+
assert_equal 'host1', host1[:host]
|
351
|
+
assert_equal 443, host1[:port]
|
352
|
+
assert_equal 'https', host1[:scheme]
|
353
|
+
assert_equal 'j%2Bhn', host1[:user]
|
354
|
+
assert_equal 'passw%40rd', host1[:password]
|
355
|
+
assert_equal '/elastic/', host1[:path]
|
356
|
+
|
357
|
+
assert_equal 'host2', host2[:host]
|
358
|
+
assert_equal 'http', host2[:scheme]
|
359
|
+
assert_equal 'default_user', host2[:user]
|
360
|
+
assert_equal 'default_password', host2[:password]
|
361
|
+
assert_equal '/default_path', host2[:path]
|
362
|
+
end
|
363
|
+
|
338
364
|
def test_single_host_params_and_defaults
|
339
365
|
config = %{
|
340
366
|
host logs.google.com
|
@@ -354,6 +380,25 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
354
380
|
assert_equal nil, host1[:path]
|
355
381
|
end
|
356
382
|
|
383
|
+
def test_single_host_params_and_defaults_with_escape_placeholders
|
384
|
+
config = %{
|
385
|
+
host logs.google.com
|
386
|
+
user %{j+hn}
|
387
|
+
password %{d@e}
|
388
|
+
}
|
389
|
+
instance = driver(config).instance
|
390
|
+
|
391
|
+
assert_equal 1, instance.get_connection_options[:hosts].length
|
392
|
+
host1 = instance.get_connection_options[:hosts][0]
|
393
|
+
|
394
|
+
assert_equal 'logs.google.com', host1[:host]
|
395
|
+
assert_equal 9200, host1[:port]
|
396
|
+
assert_equal 'http', host1[:scheme]
|
397
|
+
assert_equal 'j%2Bhn', host1[:user]
|
398
|
+
assert_equal 'd%40e', host1[:password]
|
399
|
+
assert_equal nil, host1[:path]
|
400
|
+
end
|
401
|
+
|
357
402
|
def test_content_type_header
|
358
403
|
stub_request(:head, "http://localhost:9200/").
|
359
404
|
to_return(:status => 200, :body => "", :headers => {})
|
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'helper'
|
2
2
|
require 'date'
|
3
3
|
require 'fluent/test/driver/output'
|
4
|
+
require 'flexmock/test_unit'
|
4
5
|
|
5
6
|
class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
7
|
+
include FlexMock::TestCase
|
8
|
+
|
6
9
|
attr_accessor :index_cmds, :index_command_counts
|
7
10
|
|
8
11
|
def setup
|
@@ -140,6 +143,32 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
|
140
143
|
assert_equal '/default_path', host2[:path]
|
141
144
|
end
|
142
145
|
|
146
|
+
def test_hosts_list_with_escape_placeholders
|
147
|
+
config = %{
|
148
|
+
hosts https://%{j+hn}:%{passw@rd}@host1:443/elastic/,http://host2
|
149
|
+
path /default_path
|
150
|
+
user default_user
|
151
|
+
password default_password
|
152
|
+
}
|
153
|
+
instance = driver(config).instance
|
154
|
+
|
155
|
+
assert_equal 2, instance.get_connection_options(nil)[:hosts].length
|
156
|
+
host1, host2 = instance.get_connection_options(nil)[:hosts]
|
157
|
+
|
158
|
+
assert_equal 'host1', host1[:host]
|
159
|
+
assert_equal 443, host1[:port]
|
160
|
+
assert_equal 'https', host1[:scheme]
|
161
|
+
assert_equal 'j%2Bhn', host1[:user]
|
162
|
+
assert_equal 'passw%40rd', host1[:password]
|
163
|
+
assert_equal '/elastic/', host1[:path]
|
164
|
+
|
165
|
+
assert_equal 'host2', host2[:host]
|
166
|
+
assert_equal 'http', host2[:scheme]
|
167
|
+
assert_equal 'default_user', host2[:user]
|
168
|
+
assert_equal 'default_password', host2[:password]
|
169
|
+
assert_equal '/default_path', host2[:path]
|
170
|
+
end
|
171
|
+
|
143
172
|
def test_single_host_params_and_defaults
|
144
173
|
config = %{
|
145
174
|
host logs.google.com
|
@@ -159,6 +188,25 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
|
159
188
|
assert_equal nil, host1[:path]
|
160
189
|
end
|
161
190
|
|
191
|
+
def test_single_host_params_and_defaults_with_escape_placeholders
|
192
|
+
config = %{
|
193
|
+
host logs.google.com
|
194
|
+
user %{j+hn}
|
195
|
+
password %{d@e}
|
196
|
+
}
|
197
|
+
instance = driver(config).instance
|
198
|
+
|
199
|
+
assert_equal 1, instance.get_connection_options(nil)[:hosts].length
|
200
|
+
host1 = instance.get_connection_options(nil)[:hosts][0]
|
201
|
+
|
202
|
+
assert_equal 'logs.google.com', host1[:host]
|
203
|
+
assert_equal 9200, host1[:port]
|
204
|
+
assert_equal 'http', host1[:scheme]
|
205
|
+
assert_equal 'j%2Bhn', host1[:user]
|
206
|
+
assert_equal 'd%40e', host1[:password]
|
207
|
+
assert_equal nil, host1[:path]
|
208
|
+
end
|
209
|
+
|
162
210
|
def test_content_type_header
|
163
211
|
stub_request(:head, "http://localhost:9200/").
|
164
212
|
to_return(:status => 200, :body => "", :headers => {})
|
@@ -566,6 +614,17 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
|
566
614
|
}
|
567
615
|
end
|
568
616
|
|
617
|
+
def test_tag_parts_index_error_event
|
618
|
+
stub_elastic_ping
|
619
|
+
stub_elastic
|
620
|
+
driver.configure("logstash_prefix ${tag_parts[1]}\n")
|
621
|
+
flexmock(driver.instance.router).should_receive(:emit_error_event)
|
622
|
+
.with('test', Fluent::EventTime, Hash, TypeError).once
|
623
|
+
driver.run(default_tag: 'test') do
|
624
|
+
driver.feed(sample_record)
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
569
628
|
def test_connection_failed_retry
|
570
629
|
connection_resets = 0
|
571
630
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-elasticsearch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.rc.
|
4
|
+
version: 2.0.0.rc.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- diogo
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|
@@ -170,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
170
|
version: 1.3.1
|
171
171
|
requirements: []
|
172
172
|
rubyforge_project:
|
173
|
-
rubygems_version: 2.6.
|
173
|
+
rubygems_version: 2.6.13
|
174
174
|
signing_key:
|
175
175
|
specification_version: 4
|
176
176
|
summary: ElasticSearch output plugin for Fluent event collector
|