logstash-output-elasticsearch 3.0.2-java → 4.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -3
- data/Gemfile +1 -1
- data/lib/logstash/outputs/elasticsearch/common.rb +90 -58
- data/lib/logstash/outputs/elasticsearch/common_configs.rb +12 -32
- data/lib/logstash/outputs/elasticsearch/http_client/manticore_adapter.rb +63 -0
- data/lib/logstash/outputs/elasticsearch/http_client/pool.rb +378 -0
- data/lib/logstash/outputs/elasticsearch/http_client.rb +70 -64
- data/lib/logstash/outputs/elasticsearch/http_client_builder.rb +15 -4
- data/lib/logstash/outputs/elasticsearch/template_manager.rb +1 -1
- data/lib/logstash/outputs/elasticsearch.rb +27 -4
- data/logstash-output-elasticsearch.gemspec +3 -5
- data/spec/es_spec_helper.rb +1 -0
- data/spec/fixtures/5x_node_resp.json +2 -0
- data/spec/integration/outputs/create_spec.rb +2 -5
- data/spec/integration/outputs/index_spec.rb +1 -1
- data/spec/integration/outputs/parent_spec.rb +1 -3
- data/spec/integration/outputs/pipeline_spec.rb +1 -2
- data/spec/integration/outputs/retry_spec.rb +51 -49
- data/spec/integration/outputs/routing_spec.rb +1 -1
- data/spec/integration/outputs/secure_spec.rb +4 -8
- data/spec/integration/outputs/templates_spec.rb +12 -8
- data/spec/integration/outputs/update_spec.rb +13 -27
- data/spec/unit/outputs/elasticsearch/http_client/manticore_adapter_spec.rb +25 -0
- data/spec/unit/outputs/elasticsearch/http_client/pool_spec.rb +142 -0
- data/spec/unit/outputs/elasticsearch/http_client_spec.rb +8 -22
- data/spec/unit/outputs/elasticsearch_proxy_spec.rb +5 -6
- data/spec/unit/outputs/elasticsearch_spec.rb +33 -30
- data/spec/unit/outputs/elasticsearch_ssl_spec.rb +10 -6
- metadata +72 -87
- data/lib/logstash/outputs/elasticsearch/buffer.rb +0 -124
- data/spec/unit/buffer_spec.rb +0 -118
@@ -1,124 +0,0 @@
|
|
1
|
-
require 'concurrent'
|
2
|
-
java_import java.util.concurrent.locks.ReentrantLock
|
3
|
-
|
4
|
-
module LogStash; module Outputs; class ElasticSearch
|
5
|
-
class Buffer
|
6
|
-
def initialize(logger, max_size, flush_interval, &block)
|
7
|
-
@logger = logger
|
8
|
-
# You need to aquire this for anything modifying state generally
|
9
|
-
@operations_mutex = Mutex.new
|
10
|
-
@operations_lock = java.util.concurrent.locks.ReentrantLock.new
|
11
|
-
|
12
|
-
@stopping = Concurrent::AtomicBoolean.new(false)
|
13
|
-
@max_size = max_size
|
14
|
-
@submit_proc = block
|
15
|
-
|
16
|
-
@buffer = []
|
17
|
-
|
18
|
-
@last_flush = Time.now
|
19
|
-
@flush_interval = flush_interval
|
20
|
-
@flush_thread = spawn_interval_flusher
|
21
|
-
end
|
22
|
-
|
23
|
-
def push(item)
|
24
|
-
synchronize do |buffer|
|
25
|
-
push_unsafe(item)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
alias_method :<<, :push
|
29
|
-
|
30
|
-
# Push multiple items onto the buffer in a single operation
|
31
|
-
def push_multi(items)
|
32
|
-
raise ArgumentError, "push multi takes an array!, not an #{items.class}!" unless items.is_a?(Array)
|
33
|
-
synchronize do |buffer|
|
34
|
-
items.each {|item| push_unsafe(item) }
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def flush
|
39
|
-
synchronize { flush_unsafe }
|
40
|
-
end
|
41
|
-
|
42
|
-
def stop(do_flush=true,wait_complete=true)
|
43
|
-
return if stopping?
|
44
|
-
@stopping.make_true
|
45
|
-
|
46
|
-
# No need to acquire a lock in this case
|
47
|
-
return if !do_flush && !wait_complete
|
48
|
-
|
49
|
-
synchronize do
|
50
|
-
flush_unsafe if do_flush
|
51
|
-
@flush_thread.join if wait_complete
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def contents
|
56
|
-
synchronize {|buffer| buffer}
|
57
|
-
end
|
58
|
-
|
59
|
-
# For externally operating on the buffer contents
|
60
|
-
# this takes a block and will yield the internal buffer and executes
|
61
|
-
# the block in a synchronized block from the internal mutex
|
62
|
-
def synchronize
|
63
|
-
@operations_mutex.synchronize { yield(@buffer) }
|
64
|
-
end
|
65
|
-
|
66
|
-
# These methods are private for various reasons, chief among them threadsafety!
|
67
|
-
# Many require the @operations_mutex to be locked to be safe
|
68
|
-
private
|
69
|
-
|
70
|
-
def push_unsafe(item)
|
71
|
-
@buffer << item
|
72
|
-
if @buffer.size >= @max_size
|
73
|
-
flush_unsafe
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def spawn_interval_flusher
|
78
|
-
Thread.new do
|
79
|
-
loop do
|
80
|
-
sleep 0.2
|
81
|
-
break if stopping?
|
82
|
-
synchronize { interval_flush }
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def interval_flush
|
88
|
-
if last_flush_seconds_ago >= @flush_interval
|
89
|
-
begin
|
90
|
-
@logger.debug? && @logger.debug("Flushing buffer at interval",
|
91
|
-
:instance => self.inspect,
|
92
|
-
:interval => @flush_interval)
|
93
|
-
flush_unsafe
|
94
|
-
rescue StandardError => e
|
95
|
-
@logger.warn("Error flushing buffer at interval!",
|
96
|
-
:instance => self.inspect,
|
97
|
-
:message => e.message,
|
98
|
-
:class => e.class.name,
|
99
|
-
:backtrace => e.backtrace
|
100
|
-
)
|
101
|
-
rescue Exception => e
|
102
|
-
@logger.warn("Exception flushing buffer at interval!", :error => e.message, :class => e.class.name)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def flush_unsafe
|
108
|
-
if @buffer.size > 0
|
109
|
-
@submit_proc.call(@buffer)
|
110
|
-
@buffer.clear
|
111
|
-
end
|
112
|
-
|
113
|
-
@last_flush = Time.now # This must always be set to ensure correct timer behavior
|
114
|
-
end
|
115
|
-
|
116
|
-
def last_flush_seconds_ago
|
117
|
-
Time.now - @last_flush
|
118
|
-
end
|
119
|
-
|
120
|
-
def stopping?
|
121
|
-
@stopping.true?
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end end end
|
data/spec/unit/buffer_spec.rb
DELETED
@@ -1,118 +0,0 @@
|
|
1
|
-
require "logstash/outputs/elasticsearch"
|
2
|
-
require "logstash/outputs/elasticsearch/buffer"
|
3
|
-
|
4
|
-
describe LogStash::Outputs::ElasticSearch::Buffer do
|
5
|
-
class OperationTarget # Used to track buffer flushesn
|
6
|
-
attr_reader :buffer, :buffer_history, :receive_count
|
7
|
-
def initialize
|
8
|
-
@buffer = nil
|
9
|
-
@buffer_history = []
|
10
|
-
@receive_count = 0
|
11
|
-
end
|
12
|
-
|
13
|
-
def receive(buffer)
|
14
|
-
@receive_count += 1
|
15
|
-
@buffer_history << buffer.clone
|
16
|
-
@buffer = buffer
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
let(:logger) { Cabin::Channel.get }
|
21
|
-
let(:max_size) { 10 }
|
22
|
-
let(:flush_interval) { 2 }
|
23
|
-
# Used to track flush count
|
24
|
-
let(:operation_target) { OperationTarget.new() }
|
25
|
-
let(:operation) { proc {|buffer| operation_target.receive(buffer) } }
|
26
|
-
subject(:buffer){ LogStash::Outputs::ElasticSearch::Buffer.new(logger, max_size, flush_interval, &operation) }
|
27
|
-
|
28
|
-
after(:each) do
|
29
|
-
buffer.stop(do_flush=false)
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should initialize cleanly" do
|
33
|
-
expect(buffer).to be_a(LogStash::Outputs::ElasticSearch::Buffer)
|
34
|
-
end
|
35
|
-
|
36
|
-
shared_examples("a buffer with two items inside") do
|
37
|
-
it "should add a pushed item to the buffer" do
|
38
|
-
buffer.synchronize do |data|
|
39
|
-
expect(data).to include(item1)
|
40
|
-
expect(data).to include(item2)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe "interval flushing" do
|
45
|
-
before do
|
46
|
-
sleep flush_interval + 1
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should flush the buffer after the interval has passed" do
|
50
|
-
expect(operation_target.receive_count).to eql(1)
|
51
|
-
end
|
52
|
-
|
53
|
-
it "should clear the buffer after a successful flush" do
|
54
|
-
expect(operation_target.buffer).to eql([])
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
describe "interval flushing a stopped buffer" do
|
59
|
-
before do
|
60
|
-
buffer.stop(do_flush=false)
|
61
|
-
sleep flush_interval + 1
|
62
|
-
end
|
63
|
-
|
64
|
-
it "should not flush if the buffer is stopped" do
|
65
|
-
expect(operation_target.receive_count).to eql(0)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe "with a buffer push" do
|
71
|
-
let(:item1) { "foo" }
|
72
|
-
let(:item2) { "bar" }
|
73
|
-
|
74
|
-
describe "a buffer with two items pushed to it separately" do
|
75
|
-
before do
|
76
|
-
buffer << item1
|
77
|
-
buffer << item2
|
78
|
-
end
|
79
|
-
|
80
|
-
include_examples("a buffer with two items inside")
|
81
|
-
end
|
82
|
-
|
83
|
-
describe "a buffer with two items pushed to it in one operation" do
|
84
|
-
before do
|
85
|
-
buffer.push_multi([item1, item2])
|
86
|
-
end
|
87
|
-
|
88
|
-
include_examples("a buffer with two items inside")
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
describe "with an empty buffer" do
|
93
|
-
it "should not perform an operation if the buffer is empty" do
|
94
|
-
buffer.flush
|
95
|
-
expect(operation_target.receive_count).to eql(0)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
describe "flushing with an operation that raises an error" do
|
100
|
-
class TestError < StandardError; end
|
101
|
-
let(:operation) { proc {|buffer| raise TestError, "A test" } }
|
102
|
-
let(:item) { double("item") }
|
103
|
-
|
104
|
-
before do
|
105
|
-
buffer << item
|
106
|
-
end
|
107
|
-
|
108
|
-
it "should raise an exception" do
|
109
|
-
expect { buffer.flush }.to raise_error(TestError)
|
110
|
-
end
|
111
|
-
|
112
|
-
it "should not clear the buffer" do
|
113
|
-
expect do
|
114
|
-
buffer.flush rescue TestError
|
115
|
-
end.not_to change(buffer, :contents)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|