fluent-plugin-elasticsearch 1.15.2 → 1.16.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/History.md +3 -0
- data/fluent-plugin-elasticsearch.gemspec +1 -1
- data/lib/fluent/plugin/elasticsearch_error_handler.rb +34 -23
- data/lib/fluent/plugin/out_elasticsearch.rb +23 -7
- data/test/plugin/test_elasticsearch_error_handler.rb +75 -176
- data/test/plugin/test_out_elasticsearch.rb +63 -68
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15e80a669ab0e24b83a279e1cbcc3240b76560b445319b7af7b2f719523b86e1
|
4
|
+
data.tar.gz: df01b4f813ffeba65619b778d418384b1cf3df3323929cf2921cf1273a336738
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e44489b1f603ae61d9566c4cd0d6c16a7cec6ee5c701053f884ee284945fa2f48407674108223ec6c4c7127daabcaf17b6eb534b06d8c26339dd3aaba2fa908
|
7
|
+
data.tar.gz: cee4380e5d0aecfd9305bdbc68eaf3c2dbc9fef6b0e8f88f05ad4870a33d3b330983118a6ebe492ac4645805ec23c7acc270b91d37d6a222ed03ebc5ae28c6a5
|
data/History.md
CHANGED
@@ -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.16.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}
|
@@ -1,23 +1,41 @@
|
|
1
|
+
require 'fluent/event'
|
1
2
|
require_relative 'elasticsearch_constants'
|
2
3
|
|
3
4
|
class Fluent::ElasticsearchErrorHandler
|
4
5
|
include Fluent::ElasticsearchConstants
|
5
6
|
|
6
|
-
attr_accessor :
|
7
|
-
class BulkIndexQueueFull < StandardError; end
|
8
|
-
class ElasticsearchOutOfMemory < StandardError; end
|
7
|
+
attr_accessor :bulk_message_count
|
9
8
|
class ElasticsearchVersionMismatch < StandardError; end
|
10
|
-
class UnrecognizedElasticsearchError < StandardError; end
|
11
9
|
class ElasticsearchError < StandardError; end
|
12
|
-
|
10
|
+
|
11
|
+
def initialize(plugin)
|
13
12
|
@plugin = plugin
|
14
|
-
@records = records
|
15
|
-
@bulk_message_count = bulk_message_count
|
16
13
|
end
|
17
14
|
|
18
|
-
def handle_error(response)
|
15
|
+
def handle_error(response, tag, chunk, bulk_message_count)
|
16
|
+
items = response['items']
|
17
|
+
if items.nil? || !items.is_a?(Array)
|
18
|
+
raise ElasticsearchVersionMismatch, "The response format was unrecognized: #{response}"
|
19
|
+
end
|
20
|
+
if bulk_message_count != items.length
|
21
|
+
raise ElasticsearchError, "The number of records submitted #{bulk_message_count} do not match the number returned #{items.length}. Unable to process bulk response."
|
22
|
+
end
|
23
|
+
retry_stream = Fluent::MultiEventStream.new
|
19
24
|
stats = Hash.new(0)
|
20
|
-
|
25
|
+
meta = {}
|
26
|
+
header = {}
|
27
|
+
chunk.msgpack_each do |time, rawrecord|
|
28
|
+
bulk_message = ''
|
29
|
+
next unless rawrecord.is_a? Hash
|
30
|
+
begin
|
31
|
+
# we need a deep copy for process_message to alter
|
32
|
+
processrecord = Marshal.load(Marshal.dump(rawrecord))
|
33
|
+
@plugin.process_message(tag, meta, header, time, processrecord, bulk_message)
|
34
|
+
rescue => e
|
35
|
+
stats[:bad_chunk_record] += 1
|
36
|
+
next
|
37
|
+
end
|
38
|
+
item = items.shift
|
21
39
|
if item.has_key?(@plugin.write_operation)
|
22
40
|
write_operation = @plugin.write_operation
|
23
41
|
elsif INDEX_OP == @plugin.write_operation && item.has_key?(CREATE_OP)
|
@@ -41,13 +59,19 @@ class Fluent::ElasticsearchErrorHandler
|
|
41
59
|
stats[:successes] += 1
|
42
60
|
when CREATE_OP == write_operation && 409 == status
|
43
61
|
stats[:duplicates] += 1
|
62
|
+
when 400 == status
|
63
|
+
stats[:bad_argument] += 1
|
64
|
+
@plugin.router.emit_error_event(tag, time, rawrecord, '400 - Rejected by Elasticsearch')
|
44
65
|
else
|
45
66
|
if item[write_operation].has_key?('error') && item[write_operation]['error'].has_key?('type')
|
46
67
|
type = item[write_operation]['error']['type']
|
68
|
+
stats[type] += 1
|
69
|
+
retry_stream.add(time, rawrecord)
|
47
70
|
else
|
48
71
|
# When we don't have a type field, something changed in the API
|
49
72
|
# expected return values (ES 2.x)
|
50
73
|
stats[:errors_bad_resp] += 1
|
74
|
+
@plugin.router.emit_error_event(tag, time, rawrecord, "#{status} - No error type provided in the response")
|
51
75
|
next
|
52
76
|
end
|
53
77
|
stats[type] += 1
|
@@ -58,19 +82,6 @@ class Fluent::ElasticsearchErrorHandler
|
|
58
82
|
stats.each_pair { |key, value| msg << "#{value} #{key}" }
|
59
83
|
@plugin.log.debug msg.join(', ')
|
60
84
|
end
|
61
|
-
|
62
|
-
when stats[:errors_bad_resp] > 0
|
63
|
-
@plugin.log.on_debug { @plugin.log.debug("Unable to parse response from elasticsearch, likely an API version mismatch: #{response}") }
|
64
|
-
raise ElasticsearchVersionMismatch, "Unable to parse error response from Elasticsearch, likely an API version mismatch. Add '@log_level debug' to your config to see the full response"
|
65
|
-
when stats[:successes] + stats[:duplicates] == bulk_message_count
|
66
|
-
@plugin.log.info("retry succeeded - successes=#{stats[:successes]} duplicates=#{stats[:duplicates]}")
|
67
|
-
when stats['es_rejected_execution_exception'] > 0
|
68
|
-
raise BulkIndexQueueFull, 'Bulk index queue is full, retrying'
|
69
|
-
when stats['out_of_memory_error'] > 0
|
70
|
-
raise ElasticsearchOutOfMemory, 'Elasticsearch has exhausted its heap, retrying'
|
71
|
-
else
|
72
|
-
@plugin.log.on_debug { @plugin.log.debug("Elasticsearch errors returned, retrying: #{response}") }
|
73
|
-
raise ElasticsearchError, "Elasticsearch returned errors, retrying. Add '@log_level debug' to your config to see the full response"
|
74
|
-
end
|
85
|
+
raise Fluent::ElasticsearchOutput::RetryStreamError.new(retry_stream) unless retry_stream.empty?
|
75
86
|
end
|
76
87
|
end
|
@@ -10,6 +10,7 @@ rescue LoadError
|
|
10
10
|
end
|
11
11
|
|
12
12
|
require 'fluent/output'
|
13
|
+
require 'fluent/event'
|
13
14
|
require_relative 'elasticsearch_constants'
|
14
15
|
require_relative 'elasticsearch_error_handler'
|
15
16
|
require_relative 'elasticsearch_index_template'
|
@@ -17,6 +18,16 @@ require_relative 'elasticsearch_index_template'
|
|
17
18
|
class Fluent::ElasticsearchOutput < Fluent::ObjectBufferedOutput
|
18
19
|
class ConnectionFailure < StandardError; end
|
19
20
|
|
21
|
+
# RetryStreamError privides a stream to be
|
22
|
+
# put back in the pipeline for cases where a bulk request
|
23
|
+
# failed (e.g some records succeed while others failed)
|
24
|
+
class RetryStreamError < StandardError
|
25
|
+
attr_reader :retry_stream
|
26
|
+
def initialize(retry_stream)
|
27
|
+
@retry_stream = retry_stream
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
20
31
|
Fluent::Plugin.register_output('elasticsearch', self)
|
21
32
|
|
22
33
|
config_param :host, :string, :default => 'localhost'
|
@@ -314,22 +325,21 @@ class Fluent::ElasticsearchOutput < Fluent::ObjectBufferedOutput
|
|
314
325
|
end
|
315
326
|
|
316
327
|
def write_objects(tag, chunk)
|
328
|
+
bulk_message_count = 0
|
317
329
|
bulk_message = ''
|
318
330
|
header = {}
|
319
331
|
meta = {}
|
320
|
-
@error = Fluent::ElasticsearchErrorHandler.new(self)
|
321
|
-
|
322
332
|
chunk.msgpack_each do |time, record|
|
323
|
-
@error.records += 1
|
324
333
|
next unless record.is_a? Hash
|
325
334
|
begin
|
326
335
|
process_message(tag, meta, header, time, record, bulk_message)
|
336
|
+
bulk_message_count += 1
|
327
337
|
rescue=>e
|
328
338
|
router.emit_error_event(tag, time, record, e)
|
329
339
|
end
|
330
340
|
end
|
331
341
|
|
332
|
-
send_bulk(bulk_message) unless bulk_message.empty?
|
342
|
+
send_bulk(bulk_message, tag, chunk, bulk_message_count) unless bulk_message.empty?
|
333
343
|
bulk_message.clear
|
334
344
|
end
|
335
345
|
|
@@ -398,7 +408,6 @@ class Fluent::ElasticsearchOutput < Fluent::ObjectBufferedOutput
|
|
398
408
|
end
|
399
409
|
|
400
410
|
append_record_to_messages(@write_operation, meta, header, record, bulk_message)
|
401
|
-
@error.bulk_message_count += 1
|
402
411
|
end
|
403
412
|
|
404
413
|
# returns [parent, child_key] of child described by path array in record's tree
|
@@ -408,11 +417,18 @@ class Fluent::ElasticsearchOutput < Fluent::ObjectBufferedOutput
|
|
408
417
|
[parent_object, path[-1]]
|
409
418
|
end
|
410
419
|
|
411
|
-
|
420
|
+
# send_bulk given a specific bulk request, the original tag,
|
421
|
+
# chunk, and bulk_message_count
|
422
|
+
def send_bulk(data, tag, chunk, bulk_message_count)
|
412
423
|
retries = 0
|
413
424
|
begin
|
414
425
|
response = client.bulk body: data
|
415
|
-
|
426
|
+
if response['errors']
|
427
|
+
error = Fluent::ElasticsearchErrorHandler.new(self)
|
428
|
+
error.handle_error(response, tag, chunk, bulk_message_count)
|
429
|
+
end
|
430
|
+
rescue RetryStreamError => e
|
431
|
+
router.emit_stream(tag, e.retry_stream)
|
416
432
|
rescue *client.transport.host_unreachable_exceptions => e
|
417
433
|
if retries < 2
|
418
434
|
retries += 1
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'helper'
|
2
|
+
require 'fluent/plugin/out_elasticsearch'
|
2
3
|
require 'fluent/plugin/elasticsearch_error_handler'
|
3
4
|
require 'json'
|
4
5
|
|
@@ -6,10 +7,35 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
6
7
|
|
7
8
|
class TestPlugin
|
8
9
|
attr_reader :log
|
9
|
-
attr_reader :write_operation
|
10
|
+
attr_reader :write_operation, :error_events
|
10
11
|
def initialize(log)
|
11
12
|
@log = log
|
12
13
|
@write_operation = 'index'
|
14
|
+
@error_events = Fluent::MultiEventStream.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def router
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def emit_error_event(tag, time, record, e)
|
22
|
+
@error_events.add(time, record)
|
23
|
+
end
|
24
|
+
|
25
|
+
def process_message(tag, meta, header, time, record, bulk_message)
|
26
|
+
if record.has_key?('raise') && record['raise']
|
27
|
+
raise Exception('process_message')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class MockChunk
|
33
|
+
def initialize(records)
|
34
|
+
@records = records
|
35
|
+
@index = 0
|
36
|
+
end
|
37
|
+
def msgpack_each
|
38
|
+
@records.each { |item| yield(item[:time],item[:record]) }
|
13
39
|
end
|
14
40
|
end
|
15
41
|
|
@@ -31,7 +57,8 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
31
57
|
JSON.parse(value)
|
32
58
|
end
|
33
59
|
|
34
|
-
def
|
60
|
+
def test_dlq_400_responses
|
61
|
+
records = [{time: 123, record: {"foo" => "bar"}}]
|
35
62
|
response = parse_response(%({
|
36
63
|
"took" : 0,
|
37
64
|
"errors" : true,
|
@@ -39,148 +66,44 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
39
66
|
{
|
40
67
|
"create" : {
|
41
68
|
"_index" : "foo",
|
42
|
-
"_type" : "bar",
|
43
|
-
"_id" : "abc",
|
44
|
-
"status" : 500,
|
45
|
-
"error" : {
|
46
|
-
"type" : "some unrecognized type",
|
47
|
-
"reason":"unrecognized error"
|
48
|
-
}
|
49
|
-
}
|
50
|
-
},
|
51
|
-
{
|
52
|
-
"create" : {
|
53
|
-
"_index" : "foo",
|
54
|
-
"_type" : "bar",
|
55
|
-
"_id" : "abc",
|
56
|
-
"status" : 500,
|
57
|
-
"error" : {
|
58
|
-
"type" : "some unrecognized type",
|
59
|
-
"reason":"unrecognized error"
|
60
|
-
}
|
61
|
-
}
|
62
|
-
},
|
63
|
-
{
|
64
|
-
"create" : {
|
65
|
-
"_index" : "foo",
|
66
|
-
"_type" : "bar",
|
67
|
-
"_id" : "abc",
|
68
|
-
"status" : 201
|
69
|
-
}
|
70
|
-
},
|
71
|
-
{
|
72
|
-
"create" : {
|
73
|
-
"_index" : "foo",
|
74
|
-
"_type" : "bar",
|
75
|
-
"_id" : "abc",
|
76
|
-
"status" : 409
|
77
|
-
}
|
78
|
-
},
|
79
|
-
{
|
80
|
-
"create" : {
|
81
|
-
"_index" : "foo",
|
82
|
-
"_type" : "bar",
|
83
|
-
"_id" : "abc",
|
84
69
|
"status" : 400,
|
85
|
-
"
|
86
|
-
"type" : "some unrecognized type",
|
70
|
+
"_type" : "bar",
|
87
71
|
"reason":"unrecognized error"
|
88
72
|
}
|
89
|
-
}
|
90
73
|
}
|
91
74
|
]
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
|
75
|
+
}))
|
76
|
+
chunk = MockChunk.new(records)
|
77
|
+
@handler.handle_error(response, 'atag', chunk, records.length)
|
78
|
+
assert_equal(1, @plugin.error_events.instance_variable_get(:@time_array).size)
|
98
79
|
end
|
99
80
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
"
|
106
|
-
{
|
107
|
-
"create" : {
|
108
|
-
"_index" : "foo",
|
109
|
-
"_type" : "bar",
|
110
|
-
"_id" : "abc",
|
111
|
-
"status" : 500,
|
112
|
-
"error" : {
|
113
|
-
"reason":"some error to cause version mismatch"
|
114
|
-
}
|
115
|
-
}
|
116
|
-
}
|
117
|
-
]
|
118
|
-
}
|
119
|
-
))
|
120
|
-
|
121
|
-
assert_raise Fluent::ElasticsearchErrorHandler::ElasticsearchVersionMismatch do
|
122
|
-
@handler.handle_error(response)
|
81
|
+
def test_retry_error
|
82
|
+
records = []
|
83
|
+
error_records = Hash.new(false)
|
84
|
+
error_records.merge!({0=>true, 4=>true, 9=>true})
|
85
|
+
10.times do |i|
|
86
|
+
records << {time: 12345, record: {"message"=>"record #{i}","_id"=>i,"raise"=>error_records[i]}}
|
123
87
|
end
|
88
|
+
chunk = MockChunk.new(records)
|
124
89
|
|
125
|
-
end
|
126
|
-
|
127
|
-
def test_retry_with_successes_and_duplicates
|
128
|
-
response = parse_response(%(
|
129
|
-
{
|
130
|
-
"took" : 0,
|
131
|
-
"errors" : true,
|
132
|
-
"items" : [
|
133
|
-
{
|
134
|
-
"create" : {
|
135
|
-
"_index" : "foo",
|
136
|
-
"_type" : "bar",
|
137
|
-
"_id" : "abc",
|
138
|
-
"status" : 409,
|
139
|
-
"error" : {
|
140
|
-
"reason":"duplicate ID"
|
141
|
-
}
|
142
|
-
}
|
143
|
-
},
|
144
|
-
{
|
145
|
-
"create" : {
|
146
|
-
"_index" : "foo",
|
147
|
-
"_type" : "bar",
|
148
|
-
"_id" : "abc",
|
149
|
-
"status" : 201
|
150
|
-
}
|
151
|
-
}
|
152
|
-
]
|
153
|
-
}
|
154
|
-
))
|
155
|
-
|
156
|
-
@plugin.instance_variable_set(:@write_operation, 'create')
|
157
|
-
@handler.instance_variable_set(:@bulk_message_count, 2)
|
158
|
-
@handler.handle_error(response)
|
159
|
-
assert_match /retry succeeded - successes=1 duplicates=1/, @log.out.logs[0]
|
160
|
-
end
|
161
|
-
|
162
|
-
def test_bulk_rejection_errors
|
163
90
|
response = parse_response(%({
|
164
|
-
"took" :
|
91
|
+
"took" : 1,
|
165
92
|
"errors" : true,
|
166
93
|
"items" : [
|
167
94
|
{
|
168
95
|
"create" : {
|
169
96
|
"_index" : "foo",
|
170
97
|
"_type" : "bar",
|
171
|
-
"_id" : "
|
172
|
-
"status" :
|
173
|
-
"error" : {
|
174
|
-
"type" : "some unrecognized type",
|
175
|
-
"reason":"unrecognized error"
|
176
|
-
}
|
98
|
+
"_id" : "1",
|
99
|
+
"status" : 201
|
177
100
|
}
|
178
101
|
},
|
179
102
|
{
|
180
103
|
"create" : {
|
181
104
|
"_index" : "foo",
|
182
105
|
"_type" : "bar",
|
183
|
-
"_id" : "
|
106
|
+
"_id" : "2",
|
184
107
|
"status" : 500,
|
185
108
|
"error" : {
|
186
109
|
"type" : "some unrecognized type",
|
@@ -192,50 +115,39 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
192
115
|
"create" : {
|
193
116
|
"_index" : "foo",
|
194
117
|
"_type" : "bar",
|
195
|
-
"_id" : "
|
196
|
-
"status" :
|
118
|
+
"_id" : "3",
|
119
|
+
"status" : 409
|
197
120
|
}
|
198
121
|
},
|
199
122
|
{
|
200
123
|
"create" : {
|
201
124
|
"_index" : "foo",
|
202
125
|
"_type" : "bar",
|
203
|
-
"_id" : "
|
204
|
-
"status" :
|
126
|
+
"_id" : "5",
|
127
|
+
"status" : 500,
|
128
|
+
"error" : {
|
129
|
+
"reason":"unrecognized error - no type field"
|
130
|
+
}
|
205
131
|
}
|
206
132
|
},
|
207
133
|
{
|
208
134
|
"create" : {
|
209
135
|
"_index" : "foo",
|
210
136
|
"_type" : "bar",
|
211
|
-
"_id" : "
|
137
|
+
"_id" : "6",
|
212
138
|
"status" : 429,
|
213
139
|
"error" : {
|
214
140
|
"type" : "es_rejected_execution_exception",
|
215
|
-
"reason":"
|
141
|
+
"reason":"unable to fulfill request at this time, try again later"
|
216
142
|
}
|
217
143
|
}
|
218
|
-
}
|
219
|
-
]
|
220
|
-
}))
|
221
|
-
|
222
|
-
assert_raise Fluent::ElasticsearchErrorHandler::BulkIndexQueueFull do
|
223
|
-
@handler.handle_error(response)
|
224
|
-
end
|
225
|
-
|
226
|
-
end
|
227
|
-
|
228
|
-
def test_out_of_memory_errors
|
229
|
-
response = parse_response(%({
|
230
|
-
"took" : 0,
|
231
|
-
"errors" : true,
|
232
|
-
"items" : [
|
144
|
+
},
|
233
145
|
{
|
234
146
|
"create" : {
|
235
147
|
"_index" : "foo",
|
236
148
|
"_type" : "bar",
|
237
|
-
"_id" : "
|
238
|
-
"status" :
|
149
|
+
"_id" : "7",
|
150
|
+
"status" : 400,
|
239
151
|
"error" : {
|
240
152
|
"type" : "some unrecognized type",
|
241
153
|
"reason":"unrecognized error"
|
@@ -246,48 +158,35 @@ class TestElasticsearchErrorHandler < Test::Unit::TestCase
|
|
246
158
|
"create" : {
|
247
159
|
"_index" : "foo",
|
248
160
|
"_type" : "bar",
|
249
|
-
"_id" : "
|
161
|
+
"_id" : "8",
|
250
162
|
"status" : 500,
|
251
163
|
"error" : {
|
252
164
|
"type" : "some unrecognized type",
|
253
165
|
"reason":"unrecognized error"
|
254
166
|
}
|
255
167
|
}
|
256
|
-
},
|
257
|
-
{
|
258
|
-
"create" : {
|
259
|
-
"_index" : "foo",
|
260
|
-
"_type" : "bar",
|
261
|
-
"_id" : "abc",
|
262
|
-
"status" : 201
|
263
|
-
}
|
264
|
-
},
|
265
|
-
{
|
266
|
-
"create" : {
|
267
|
-
"_index" : "foo",
|
268
|
-
"_type" : "bar",
|
269
|
-
"_id" : "abc",
|
270
|
-
"status" : 409
|
271
|
-
}
|
272
|
-
},
|
273
|
-
{
|
274
|
-
"create" : {
|
275
|
-
"_index" : "foo",
|
276
|
-
"_type" : "bar",
|
277
|
-
"_id" : "abc",
|
278
|
-
"status" : 400,
|
279
|
-
"error" : {
|
280
|
-
"type" : "out_of_memory_error",
|
281
|
-
"reason":"Elasticsearch exhausted its heap"
|
282
|
-
}
|
283
|
-
}
|
284
168
|
}
|
285
169
|
]
|
286
170
|
}))
|
287
171
|
|
288
|
-
|
289
|
-
|
172
|
+
begin
|
173
|
+
failed = false
|
174
|
+
@handler.handle_error(response, 'atag', chunk, response['items'].length)
|
175
|
+
rescue Fluent::ElasticsearchOutput::RetryStreamError=>e
|
176
|
+
failed = true
|
177
|
+
records = [].tap do |records|
|
178
|
+
e.retry_stream.each {|time, record| records << record}
|
179
|
+
end
|
180
|
+
assert_equal 3, records.length
|
181
|
+
assert_equal 2, records[0]['_id']
|
182
|
+
assert_equal 6, records[1]['_id']
|
183
|
+
assert_equal 8, records[2]['_id']
|
184
|
+
errors = @plugin.error_events.collect {|time, record| record}
|
185
|
+
assert_equal 2, errors.length
|
186
|
+
assert_equal 5, errors[0]['_id']
|
187
|
+
assert_equal 7, errors[1]['_id']
|
290
188
|
end
|
189
|
+
assert_true failed
|
291
190
|
|
292
191
|
end
|
293
192
|
|
@@ -150,33 +150,6 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
150
150
|
stub_request(:post, url).to_return(lambda { |req| { :status => 200, :body => make_response_body(req, 1, 500, error), :headers => { 'Content-Type' => 'json' } } })
|
151
151
|
end
|
152
152
|
|
153
|
-
def stub_elastic_unrecognized_error(url="http://localhost:9200/_bulk")
|
154
|
-
error = {
|
155
|
-
"status" => 500,
|
156
|
-
"type" => "some-other-type",
|
157
|
-
"reason" => "some-other-reason"
|
158
|
-
}
|
159
|
-
stub_request(:post, url).to_return(lambda { |req| { :status => 200, :body => make_response_body(req, 1, 504, error), :headers => { 'Content-Type' => 'json' } } })
|
160
|
-
end
|
161
|
-
|
162
|
-
def stub_elastic_version_mismatch(url="http://localhost:9200/_bulk")
|
163
|
-
error = {
|
164
|
-
"status" => 500,
|
165
|
-
"category" => "some-other-type",
|
166
|
-
"reason" => "some-other-reason"
|
167
|
-
}
|
168
|
-
stub_request(:post, url).to_return(lambda { |req| { :status => 200, :body => make_response_body(req, 1, 500, error), :headers => { 'Content-Type' => 'json' } } })
|
169
|
-
end
|
170
|
-
|
171
|
-
def stub_elastic_index_to_create(url="http://localhost:9200/_bulk")
|
172
|
-
error = {
|
173
|
-
"category" => "some-other-type",
|
174
|
-
"reason" => "some-other-reason",
|
175
|
-
"type" => "some-other-type"
|
176
|
-
}
|
177
|
-
stub_request(:post, url).to_return(lambda { |req| { :status => 200, :body => make_response_body(req, 0, 500, error), :headers => { 'Content-Type' => 'json' } } })
|
178
|
-
end
|
179
|
-
|
180
153
|
def stub_elastic_unexpected_response_op(url="http://localhost:9200/_bulk")
|
181
154
|
error = {
|
182
155
|
"category" => "some-other-type",
|
@@ -1377,47 +1350,68 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
1377
1350
|
|
1378
1351
|
def test_bulk_error
|
1379
1352
|
stub_elastic_ping
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1353
|
+
stub_request(:post, 'http://localhost:9200/_bulk')
|
1354
|
+
.to_return(lambda do |req|
|
1355
|
+
{ :status => 200,
|
1356
|
+
:headers => { 'Content-Type' => 'json' },
|
1357
|
+
:body => %({
|
1358
|
+
"took" : 1,
|
1359
|
+
"errors" : true,
|
1360
|
+
"items" : [
|
1361
|
+
{
|
1362
|
+
"create" : {
|
1363
|
+
"_index" : "foo",
|
1364
|
+
"_type" : "bar",
|
1365
|
+
"_id" : "abc",
|
1366
|
+
"status" : 500,
|
1367
|
+
"error" : {
|
1368
|
+
"type" : "some unrecognized type",
|
1369
|
+
"reason":"some error to cause version mismatch"
|
1370
|
+
}
|
1371
|
+
}
|
1372
|
+
},
|
1373
|
+
{
|
1374
|
+
"create" : {
|
1375
|
+
"_index" : "foo",
|
1376
|
+
"_type" : "bar",
|
1377
|
+
"_id" : "abc",
|
1378
|
+
"status" : 201
|
1379
|
+
}
|
1380
|
+
},
|
1381
|
+
{
|
1382
|
+
"create" : {
|
1383
|
+
"_index" : "foo",
|
1384
|
+
"_type" : "bar",
|
1385
|
+
"_id" : "abc",
|
1386
|
+
"status" : 500,
|
1387
|
+
"error" : {
|
1388
|
+
"type" : "some unrecognized type",
|
1389
|
+
"reason":"some error to cause version mismatch"
|
1390
|
+
}
|
1391
|
+
}
|
1392
|
+
},
|
1393
|
+
{
|
1394
|
+
"create" : {
|
1395
|
+
"_index" : "foo",
|
1396
|
+
"_type" : "bar",
|
1397
|
+
"_id" : "abc",
|
1398
|
+
"_id" : "abc",
|
1399
|
+
"status" : 409
|
1400
|
+
}
|
1401
|
+
}
|
1402
|
+
]
|
1403
|
+
})
|
1404
|
+
}
|
1405
|
+
end)
|
1406
|
+
|
1407
|
+
driver.emit(sample_record, 1)
|
1408
|
+
driver.emit(sample_record, 2)
|
1409
|
+
driver.emit(sample_record, 3)
|
1410
|
+
driver.emit(sample_record, 4)
|
1411
|
+
|
1412
|
+
driver.expect_emit('test', 1, sample_record)
|
1413
|
+
driver.expect_emit('test', 3, sample_record)
|
1414
|
+
driver.run
|
1421
1415
|
end
|
1422
1416
|
|
1423
1417
|
def test_update_should_not_write_if_theres_no_id
|
@@ -1592,4 +1586,5 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
1592
1586
|
driver.run
|
1593
1587
|
assert(index_cmds[0].has_key?("create"))
|
1594
1588
|
end
|
1589
|
+
|
1595
1590
|
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.16.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: 2018-
|
12
|
+
date: 2018-05-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|