fluent-plugin-elasticsearch 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +2 -0
- data/.travis.yml +1 -0
- data/Gemfile +1 -0
- data/History.md +2 -1
- data/README.md +20 -5
- data/Rakefile +2 -3
- data/fluent-plugin-elasticsearch.gemspec +3 -3
- data/lib/fluent/plugin/out_elasticsearch.rb +23 -5
- data/lib/fluent/plugin/out_elasticsearch_dynamic.rb +4 -6
- data/test/helper.rb +23 -0
- data/test/plugin/test_out_elasticsearch.rb +62 -13
- data/test/plugin/test_out_elasticsearch_dynamic.rb +61 -13
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e5c36c889794052ff9bab9d9b6e69aa8d937eed
|
4
|
+
data.tar.gz: a719c42134c8d53969abe517a47f47a6936d092d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e75bdccd2859b063eb1fc48fdce8394e43648ff05b4d25214b66b85111482c1d8d671e24d3a5376d37f0f1093fbefb2866afc5e9882728df2b09c2147cf16a90
|
7
|
+
data.tar.gz: 3393dce7f111c75ce16b8b4af7fff51064870cb1033bf446701180cf0c84458ffc3a8ea3f6a58503eff46d1d7e414e588073497fd5e6a20becc036971ddb40d8
|
data/.coveralls.yml
ADDED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/History.md
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# Fluent::Plugin::Elasticsearch, a plugin for [Fluentd](http://fluentd.org)
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/fluent-plugin-elasticsearch.png)](http://badge.fury.io/rb/fluent-plugin-elasticsearch)
|
4
|
-
[![Dependency Status](https://gemnasium.com/uken/guard-sidekiq.png)](https://gemnasium.com/uken/fluent-plugin-elasticsearch)
|
5
4
|
[![Build Status](https://travis-ci.org/uken/fluent-plugin-elasticsearch.png?branch=master)](https://travis-ci.org/uken/fluent-plugin-elasticsearch)
|
6
5
|
[![Coverage Status](https://coveralls.io/repos/uken/fluent-plugin-elasticsearch/badge.png)](https://coveralls.io/r/uken/fluent-plugin-elasticsearch)
|
7
6
|
[![Code Climate](https://codeclimate.com/github/uken/fluent-plugin-elasticsearch.png)](https://codeclimate.com/github/uken/fluent-plugin-elasticsearch)
|
7
|
+
[![Issue Stats](http://issuestats.com/github/uken/fluent-plugin-elasticsearch/badge/pr)](http://issuestats.com/github/uken/fluent-plugin-elasticsearch)
|
8
|
+
[![Issue Stats](http://issuestats.com/github/uken/fluent-plugin-elasticsearch/badge/issue)](http://issuestats.com/github/uken/fluent-plugin-elasticsearch)
|
8
9
|
|
9
10
|
Send your logs to ElasticSearch (and search them with Kibana maybe?)
|
10
11
|
|
@@ -27,6 +28,7 @@ Note: For Amazon Elasticsearch Service please consider using [fluent-plugin-aws-
|
|
27
28
|
+ [resurrect_after](#resurrect_after)
|
28
29
|
+ [include_tag_key, tag_key](#include_tag_key-tag_key)
|
29
30
|
+ [id_key](#id_key)
|
31
|
+
+ [write_operation](#write_operation)
|
30
32
|
+ [Client/host certificate options](#clienthost-certificate-options)
|
31
33
|
+ [Buffered output options](#buffered-output-options)
|
32
34
|
+ [Not seeing a config you need?](#not-seeing-a-config-you-need)
|
@@ -164,21 +166,21 @@ request_timeout 15s # defaults to 5s
|
|
164
166
|
|
165
167
|
### reload_connections
|
166
168
|
|
169
|
+
You can tune how the elasticsearch-transport host reloading feature works. By default it will reload the host list from the server every 10,000th request to spread the load. This can be an issue if your ElasticSearch cluster is behind a Reverse Proxy, as Fluentd process may not have direct network access to the ElasticSearch nodes.
|
170
|
+
|
167
171
|
```
|
168
172
|
reload_connections false # defaults to true
|
169
173
|
```
|
170
174
|
|
171
175
|
### reload_on_failure
|
172
176
|
|
173
|
-
|
177
|
+
Indicates that the elasticsearch-transport will try to reload the nodes addresses if there is a failure while making the
|
178
|
+
request, this can be useful to quickly remove a dead node from the list of addresses.
|
174
179
|
|
175
180
|
```
|
176
181
|
reload_on_failure true # defaults to false
|
177
182
|
```
|
178
183
|
|
179
|
-
Indicates that the elasticsearch-transport will try to reload the nodes addresses if there is a failure while making the
|
180
|
-
request, this can be useful to quickly remove a dead node from the list of addresses.
|
181
|
-
|
182
184
|
### resurrect_after
|
183
185
|
|
184
186
|
You can set in the elasticsearch-transport how often dead connections from the elasticsearch-transport's pool will be resurrected.
|
@@ -225,6 +227,19 @@ This following record `{"name":"Johnny","request_id":"87d89af7daffad6"}` will tr
|
|
225
227
|
{ "name": "Johnny", "request_id": "87d89af7daffad6" }
|
226
228
|
```
|
227
229
|
|
230
|
+
### write_operation
|
231
|
+
|
232
|
+
The write_operation can be any of:
|
233
|
+
|
234
|
+
| Operation | Description |
|
235
|
+
| ------------- | ----------- |
|
236
|
+
| index (default) | new data is added while existing data (based on its id) is replaced (reindexed).|
|
237
|
+
| create | adds new data - if the data already exists (based on its id), the op is skipped.|
|
238
|
+
| update | updates existing data (based on its id). If no data is found, the op is skipped.|
|
239
|
+
| upsert | known as merge or insert if the data does not exist, updates if the data exists (based on its id).|
|
240
|
+
|
241
|
+
**Please note, id is required in create, update, and upsert scenario. Without id, the message will be dropped.**
|
242
|
+
|
228
243
|
### Client/host certificate options
|
229
244
|
|
230
245
|
Need to verify ElasticSearch's certificate? You can use the following parameter to specify a CA instead of using an environment variable.
|
data/Rakefile
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
2
|
require 'rake/testtask'
|
3
3
|
|
4
4
|
Rake::TestTask.new(:test) do |test|
|
5
|
-
test.libs << '
|
5
|
+
test.libs << 'test'
|
6
6
|
test.pattern = 'test/**/test_*.rb'
|
7
7
|
test.verbose = true
|
8
8
|
end
|
9
9
|
|
10
10
|
task :default => :test
|
11
|
-
|
@@ -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 = '1.
|
6
|
+
s.version = '1.3.0'
|
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}
|
@@ -21,8 +21,8 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_runtime_dependency 'elasticsearch', '>= 0'
|
22
22
|
|
23
23
|
|
24
|
-
s.add_development_dependency 'rake', '
|
24
|
+
s.add_development_dependency 'rake', '>= 0'
|
25
25
|
s.add_development_dependency 'webmock', '~> 1'
|
26
26
|
s.add_development_dependency 'test-unit', '~> 3.1.0'
|
27
|
-
s.add_development_dependency 'minitest', '~> 5.
|
27
|
+
s.add_development_dependency 'minitest', '~> 5.8'
|
28
28
|
end
|
@@ -23,6 +23,7 @@ class Fluent::ElasticsearchOutput < Fluent::BufferedOutput
|
|
23
23
|
config_param :type_name, :string, :default => "fluentd"
|
24
24
|
config_param :index_name, :string, :default => "fluentd"
|
25
25
|
config_param :id_key, :string, :default => nil
|
26
|
+
config_param :write_operation, :string, :default => "index"
|
26
27
|
config_param :parent_key, :string, :default => nil
|
27
28
|
config_param :request_timeout, :time, :default => 5
|
28
29
|
config_param :reload_connections, :bool, :default => true
|
@@ -127,6 +128,24 @@ class Fluent::ElasticsearchOutput < Fluent::BufferedOutput
|
|
127
128
|
super
|
128
129
|
end
|
129
130
|
|
131
|
+
def append_record_to_messages(op, meta, record, msgs)
|
132
|
+
case op
|
133
|
+
when "update", "upsert"
|
134
|
+
if meta.has_key?("_id")
|
135
|
+
msgs << { "update" => meta }
|
136
|
+
msgs << { "doc" => record, "doc_as_upsert" => op == "upsert" }
|
137
|
+
end
|
138
|
+
when "create"
|
139
|
+
if meta.has_key?("_id")
|
140
|
+
msgs << { "create" => meta }
|
141
|
+
msgs << record
|
142
|
+
end
|
143
|
+
when "index"
|
144
|
+
msgs << { "index" => meta }
|
145
|
+
msgs << record
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
130
149
|
def write(chunk)
|
131
150
|
bulk_message = []
|
132
151
|
|
@@ -154,17 +173,16 @@ class Fluent::ElasticsearchOutput < Fluent::BufferedOutput
|
|
154
173
|
record.merge!(@tag_key => tag)
|
155
174
|
end
|
156
175
|
|
157
|
-
meta = {
|
176
|
+
meta = {"_index" => target_index, "_type" => type_name}
|
158
177
|
if @id_key && record[@id_key]
|
159
|
-
meta['
|
178
|
+
meta['_id'] = record[@id_key]
|
160
179
|
end
|
161
180
|
|
162
181
|
if @parent_key && record[@parent_key]
|
163
|
-
meta['
|
182
|
+
meta['_parent'] = record[@parent_key]
|
164
183
|
end
|
165
184
|
|
166
|
-
|
167
|
-
bulk_message << record
|
185
|
+
append_record_to_messages(@write_operation, meta, record, bulk_message)
|
168
186
|
end
|
169
187
|
|
170
188
|
send(bulk_message) unless bulk_message.empty?
|
@@ -149,13 +149,13 @@ class Fluent::ElasticsearchOutputDynamic < Fluent::ElasticsearchOutput
|
|
149
149
|
record.merge!(dynamic_conf['tag_key'] => tag)
|
150
150
|
end
|
151
151
|
|
152
|
-
meta = {
|
152
|
+
meta = {"_index" => target_index, "_type" => dynamic_conf['type_name']}
|
153
153
|
if dynamic_conf['id_key'] && record[dynamic_conf['id_key']]
|
154
|
-
meta['
|
154
|
+
meta['_id'] = record[dynamic_conf['id_key']]
|
155
155
|
end
|
156
156
|
|
157
157
|
if dynamic_conf['parent_key'] && record[dynamic_conf['parent_key']]
|
158
|
-
meta['
|
158
|
+
meta['_parent'] = record[dynamic_conf['parent_key']]
|
159
159
|
end
|
160
160
|
|
161
161
|
if dynamic_conf['hosts']
|
@@ -164,9 +164,7 @@ class Fluent::ElasticsearchOutputDynamic < Fluent::ElasticsearchOutput
|
|
164
164
|
host = "#{dynamic_conf['host']}:#{dynamic_conf['port']}"
|
165
165
|
end
|
166
166
|
|
167
|
-
bulk_message[host]
|
168
|
-
bulk_message[host] << record
|
169
|
-
|
167
|
+
append_record_to_messages(dynamic_conf["write_operation"], meta, record, bulk_message[host])
|
170
168
|
end
|
171
169
|
|
172
170
|
bulk_message.each do | hKey, array |
|
data/test/helper.rb
CHANGED
@@ -1 +1,24 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start do
|
3
|
+
add_filter do |src|
|
4
|
+
!(src.filename =~ /^#{SimpleCov.root}\/lib/)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'coveralls'
|
9
|
+
Coveralls.wear!
|
10
|
+
|
11
|
+
# needs to be after simplecov but before test/unit, because fluentd sets default
|
12
|
+
# encoding to ASCII-8BIT, but coverall might load git data which could contain a
|
13
|
+
# UTF-8 character
|
14
|
+
at_exit do
|
15
|
+
Encoding.default_internal = 'UTF-8' if defined?(Encoding) && Encoding.respond_to?(:default_internal)
|
16
|
+
Encoding.default_external = 'UTF-8' if defined?(Encoding) && Encoding.respond_to?(:default_external)
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'test/unit'
|
20
|
+
require 'fluent/test'
|
1
21
|
require 'minitest/pride'
|
22
|
+
|
23
|
+
require 'webmock/test_unit'
|
24
|
+
WebMock.disable_net_connect!
|
@@ -1,23 +1,12 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
|
3
|
-
require 'fluent/test'
|
4
|
-
require 'fluent/plugin/out_elasticsearch'
|
5
|
-
|
6
|
-
require 'webmock/test_unit'
|
7
|
-
require 'date'
|
8
|
-
|
9
|
-
$:.push File.expand_path("../..", __FILE__)
|
10
|
-
$:.push File.dirname(__FILE__)
|
11
|
-
|
12
1
|
require 'helper'
|
13
|
-
|
14
|
-
WebMock.disable_net_connect!
|
2
|
+
require 'date'
|
15
3
|
|
16
4
|
class ElasticsearchOutput < Test::Unit::TestCase
|
17
5
|
attr_accessor :index_cmds, :index_command_counts
|
18
6
|
|
19
7
|
def setup
|
20
8
|
Fluent::Test.setup
|
9
|
+
require 'fluent/plugin/out_elasticsearch'
|
21
10
|
@driver = nil
|
22
11
|
end
|
23
12
|
|
@@ -449,4 +438,64 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
449
438
|
}
|
450
439
|
assert_equal(connection_resets, 3)
|
451
440
|
end
|
441
|
+
|
442
|
+
def test_update_should_not_write_if_theres_no_id
|
443
|
+
driver.configure("write_operation update\n")
|
444
|
+
stub_elastic_ping
|
445
|
+
stub_elastic
|
446
|
+
driver.emit(sample_record)
|
447
|
+
driver.run
|
448
|
+
assert_nil(index_cmds)
|
449
|
+
end
|
450
|
+
|
451
|
+
def test_upsert_should_not_write_if_theres_no_id
|
452
|
+
driver.configure("write_operation upsert\n")
|
453
|
+
stub_elastic_ping
|
454
|
+
stub_elastic
|
455
|
+
driver.emit(sample_record)
|
456
|
+
driver.run
|
457
|
+
assert_nil(index_cmds)
|
458
|
+
end
|
459
|
+
|
460
|
+
def test_create_should_not_write_if_theres_no_id
|
461
|
+
driver.configure("write_operation create\n")
|
462
|
+
stub_elastic_ping
|
463
|
+
stub_elastic
|
464
|
+
driver.emit(sample_record)
|
465
|
+
driver.run
|
466
|
+
assert_nil(index_cmds)
|
467
|
+
end
|
468
|
+
|
469
|
+
def test_update_should_write_update_op_and_doc_as_upsert_is_false
|
470
|
+
driver.configure("write_operation update
|
471
|
+
id_key request_id")
|
472
|
+
stub_elastic_ping
|
473
|
+
stub_elastic
|
474
|
+
driver.emit(sample_record)
|
475
|
+
driver.run
|
476
|
+
assert(index_cmds[0].has_key?("update"))
|
477
|
+
assert(!index_cmds[1]["doc_as_upsert"])
|
478
|
+
end
|
479
|
+
|
480
|
+
def test_upsert_should_write_update_op_and_doc_as_upsert_is_true
|
481
|
+
driver.configure("write_operation upsert
|
482
|
+
id_key request_id")
|
483
|
+
stub_elastic_ping
|
484
|
+
stub_elastic
|
485
|
+
driver.emit(sample_record)
|
486
|
+
driver.run
|
487
|
+
assert(index_cmds[0].has_key?("update"))
|
488
|
+
assert(index_cmds[1]["doc_as_upsert"])
|
489
|
+
end
|
490
|
+
|
491
|
+
def test_create_should_write_create_op
|
492
|
+
driver.configure("write_operation create
|
493
|
+
id_key request_id")
|
494
|
+
stub_elastic_ping
|
495
|
+
stub_elastic
|
496
|
+
driver.emit(sample_record)
|
497
|
+
driver.run
|
498
|
+
assert(index_cmds[0].has_key?("create"))
|
499
|
+
end
|
500
|
+
|
452
501
|
end
|
@@ -1,23 +1,12 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
|
3
|
-
require 'fluent/test'
|
4
|
-
require 'fluent/plugin/out_elasticsearch_dynamic'
|
5
|
-
|
6
|
-
require 'webmock/test_unit'
|
7
|
-
require 'date'
|
8
|
-
|
9
|
-
$:.push File.expand_path("../..", __FILE__)
|
10
|
-
$:.push File.dirname(__FILE__)
|
11
|
-
|
12
1
|
require 'helper'
|
13
|
-
|
14
|
-
WebMock.disable_net_connect!
|
2
|
+
require 'date'
|
15
3
|
|
16
4
|
class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
17
5
|
attr_accessor :index_cmds, :index_command_counts
|
18
6
|
|
19
7
|
def setup
|
20
8
|
Fluent::Test.setup
|
9
|
+
require 'fluent/plugin/out_elasticsearch_dynamic'
|
21
10
|
@driver = nil
|
22
11
|
end
|
23
12
|
|
@@ -449,4 +438,63 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
|
449
438
|
}
|
450
439
|
assert_equal(connection_resets, 3)
|
451
440
|
end
|
441
|
+
|
442
|
+
def test_update_should_not_write_if_theres_no_id
|
443
|
+
driver.configure("write_operation update\n")
|
444
|
+
stub_elastic_ping
|
445
|
+
stub_elastic
|
446
|
+
driver.emit(sample_record)
|
447
|
+
driver.run
|
448
|
+
assert_nil(index_cmds)
|
449
|
+
end
|
450
|
+
|
451
|
+
def test_upsert_should_not_write_if_theres_no_id
|
452
|
+
driver.configure("write_operation upsert\n")
|
453
|
+
stub_elastic_ping
|
454
|
+
stub_elastic
|
455
|
+
driver.emit(sample_record)
|
456
|
+
driver.run
|
457
|
+
assert_nil(index_cmds)
|
458
|
+
end
|
459
|
+
|
460
|
+
def test_create_should_not_write_if_theres_no_id
|
461
|
+
driver.configure("write_operation create\n")
|
462
|
+
stub_elastic_ping
|
463
|
+
stub_elastic
|
464
|
+
driver.emit(sample_record)
|
465
|
+
driver.run
|
466
|
+
assert_nil(index_cmds)
|
467
|
+
end
|
468
|
+
|
469
|
+
def test_update_should_write_update_op_and_doc_as_upsert_is_false
|
470
|
+
driver.configure("write_operation update
|
471
|
+
id_key request_id")
|
472
|
+
stub_elastic_ping
|
473
|
+
stub_elastic
|
474
|
+
driver.emit(sample_record)
|
475
|
+
driver.run
|
476
|
+
assert(index_cmds[0].has_key?("update"))
|
477
|
+
assert(!index_cmds[1]["doc_as_upsert"])
|
478
|
+
end
|
479
|
+
|
480
|
+
def test_upsert_should_write_update_op_and_doc_as_upsert_is_true
|
481
|
+
driver.configure("write_operation upsert
|
482
|
+
id_key request_id")
|
483
|
+
stub_elastic_ping
|
484
|
+
stub_elastic
|
485
|
+
driver.emit(sample_record)
|
486
|
+
driver.run
|
487
|
+
assert(index_cmds[0].has_key?("update"))
|
488
|
+
assert(index_cmds[1]["doc_as_upsert"])
|
489
|
+
end
|
490
|
+
|
491
|
+
def test_create_should_write_create_op
|
492
|
+
driver.configure("write_operation create
|
493
|
+
id_key request_id")
|
494
|
+
stub_elastic_ping
|
495
|
+
stub_elastic
|
496
|
+
driver.emit(sample_record)
|
497
|
+
driver.run
|
498
|
+
assert(index_cmds[0].has_key?("create"))
|
499
|
+
end
|
452
500
|
end
|
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: 1.
|
4
|
+
version: 1.3.0
|
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:
|
12
|
+
date: 2016-01-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|
@@ -57,14 +57,14 @@ dependencies:
|
|
57
57
|
name: rake
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- - "
|
60
|
+
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: '0'
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- - "
|
67
|
+
- - ">="
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
70
|
- !ruby/object:Gem::Dependency
|
@@ -101,14 +101,14 @@ dependencies:
|
|
101
101
|
requirements:
|
102
102
|
- - "~>"
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version: 5.
|
104
|
+
version: '5.8'
|
105
105
|
type: :development
|
106
106
|
prerelease: false
|
107
107
|
version_requirements: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
109
|
- - "~>"
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version: 5.
|
111
|
+
version: '5.8'
|
112
112
|
description: ElasticSearch output plugin for Fluent event collector
|
113
113
|
email:
|
114
114
|
- pitr.vern@gmail.com
|
@@ -117,6 +117,7 @@ executables: []
|
|
117
117
|
extensions: []
|
118
118
|
extra_rdoc_files: []
|
119
119
|
files:
|
120
|
+
- ".coveralls.yml"
|
120
121
|
- ".editorconfig"
|
121
122
|
- ".gitignore"
|
122
123
|
- ".travis.yml"
|