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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9cc6bc3f6b89a0735bf96c5c0575d39e58458746
4
- data.tar.gz: ee98c63584d8249795b5e4c1e1a75fcc2059b2ab
3
+ metadata.gz: ac60b728ec23b3ba9a24a87f1b58fcf3dbf2376f
4
+ data.tar.gz: fe9d1c7d1f5c07d84a69e27bc534c6c6db5512b6
5
5
  SHA512:
6
- metadata.gz: eb6c6cb81709dc0b7aa2845e64346621db2cfed45ff16d75cb2384e669cfe8e0497efb8b1d36ea94dbc82da40397347662c118afeaef91347f30b73d93ec940f
7
- data.tar.gz: e7eef17ef1e8cab63f79baebba312410455c997c1a5a2128416b48b5bf26c47320c93835e70167b8e218dc022b9171b9d7e802653e205c76dfc81018cfbf3689
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" : "logstash-2013.01.01, "_type" : "fluentd", "_id" : "87d89af7daffad6" } }
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" : "****", "_type" : "****", "_id" : "****", "_parent" : "my_parent" } }
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.5'
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
- # evaluate all configurations here
132
- DYNAMIC_PARAM_SYMBOLS.each_with_index { |var, i|
133
- k = DYNAMIC_PARAM_NAMES[i]
134
- v = self.instance_variable_get(var)
135
- # check here to determine if we should evaluate
136
- if dynamic_conf[k] != v
137
- value = expand_param(v, tag, time, record)
138
- dynamic_conf[k] = value
139
- end
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.5
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-09-25 00:00:00.000000000 Z
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.11
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