logstash-output-kafka 2.0.5 → 3.0.0.beta1
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/CHANGELOG.md +10 -6
- data/lib/logstash/outputs/kafka.rb +104 -70
- data/lib/logstash-output-kafka_jars.rb +5 -0
- data/logstash-output-kafka.gemspec +3 -4
- data/spec/integration/outputs/kafka_spec.rb +84 -17
- data/spec/unit/outputs/kafka_spec.rb +13 -7
- data/vendor/jar-dependencies/runtime-jars/kafka-clients-0.9.0.1.jar +0 -0
- data/vendor/jar-dependencies/runtime-jars/slf4j-api-1.7.13.jar +0 -0
- data/vendor/jar-dependencies/runtime-jars/slf4j-noop-1.7.13.jar +0 -0
- metadata +32 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4566180256b76a147bc313ba93a53ea87f0dd6b5
|
4
|
+
data.tar.gz: 01199234963282f640588f6e13ca5fa725d18313
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f438f87c576958d1d7d1bcf1aeae82be404120b26e27cb64ccbd659b13fa149bfc88b74cfe75df0c9727b6f776bdf2ca3339c9ff0e7574027b54bc5a2d8318b8
|
7
|
+
data.tar.gz: 1297979da8c0d1bcad6f739f5c6e7fb8d5af9cafb64c441ba08ec1dbf8c6ef194c7c231dec9d23a39fd371f162c9594faca3a5733c4497fdb68b2a6e98ef743b
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
-
|
2
|
-
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
## 3.0.0.beta1
|
2
|
+
- Note: breaking changes in this version, and not backward compatible with Kafka 0.8 broker.
|
3
|
+
Please read carefully before installing
|
4
|
+
- Breaking: Changed default codec from json to plain. Json codec is really slow when used
|
5
|
+
with inputs because inputs by default are single threaded. This makes it a bad
|
6
|
+
first user experience. Plain codec is a much better default.
|
7
|
+
- Moved internal APIs to use Kafka's Java API directly instead of jruby-kafka. This
|
8
|
+
makes it consistent with logstash-input-kafka
|
9
|
+
- Breaking: Change in configuration options
|
10
|
+
- Added SSL options so you can connect securely to a 0.9 Kafka broker
|
7
11
|
|
8
12
|
## 2.0.2
|
9
13
|
- [Internal] Pin jruby-kafka to v1.5
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'logstash/namespace'
|
2
2
|
require 'logstash/outputs/base'
|
3
|
-
require '
|
3
|
+
require 'java'
|
4
|
+
require 'logstash-output-kafka_jars.rb'
|
4
5
|
|
5
6
|
# Write events to a Kafka topic. This uses the Kafka Producer API to write messages to a topic on
|
6
7
|
# the broker.
|
@@ -24,25 +25,8 @@ require 'jruby-kafka'
|
|
24
25
|
class LogStash::Outputs::Kafka < LogStash::Outputs::Base
|
25
26
|
config_name 'kafka'
|
26
27
|
|
27
|
-
default :codec, '
|
28
|
+
default :codec, 'plain'
|
28
29
|
|
29
|
-
# The topic to produce messages to
|
30
|
-
config :topic_id, :validate => :string, :required => true
|
31
|
-
# This is for bootstrapping and the producer will only use it for getting metadata (topics,
|
32
|
-
# partitions and replicas). The socket connections for sending the actual data will be
|
33
|
-
# established based on the broker information returned in the metadata. The format is
|
34
|
-
# `host1:port1,host2:port2`, and the list can be a subset of brokers or a VIP pointing to a
|
35
|
-
# subset of brokers.
|
36
|
-
config :bootstrap_servers, :validate => :string, :default => 'localhost:9092'
|
37
|
-
# Serializer class for the key of the message
|
38
|
-
config :key_serializer, :validate => :string, :default => 'org.apache.kafka.common.serialization.StringSerializer'
|
39
|
-
# Serializer class for the value of the message
|
40
|
-
config :value_serializer, :validate => :string, :default => 'org.apache.kafka.common.serialization.StringSerializer'
|
41
|
-
# The key that will be included with the record
|
42
|
-
#
|
43
|
-
# If a `message_key` is present, a partition will be chosen using a hash of the key.
|
44
|
-
# If not present, a partition for the message will be assigned in a round-robin fashion.
|
45
|
-
config :message_key, :validate => :string
|
46
30
|
# The number of acknowledgments the producer requires the leader to have received
|
47
31
|
# before considering a request complete.
|
48
32
|
#
|
@@ -51,22 +35,31 @@ class LogStash::Outputs::Kafka < LogStash::Outputs::Base
|
|
51
35
|
# will respond without awaiting full acknowledgement from all followers.
|
52
36
|
# acks=all, This means the leader will wait for the full set of in-sync replicas to acknowledge the record.
|
53
37
|
config :acks, :validate => ["0", "1", "all"], :default => "1"
|
38
|
+
# The producer will attempt to batch records together into fewer requests whenever multiple
|
39
|
+
# records are being sent to the same partition. This helps performance on both the client
|
40
|
+
# and the server. This configuration controls the default batch size in bytes.
|
41
|
+
config :batch_size, :validate => :number, :default => 16384
|
42
|
+
# This is for bootstrapping and the producer will only use it for getting metadata (topics,
|
43
|
+
# partitions and replicas). The socket connections for sending the actual data will be
|
44
|
+
# established based on the broker information returned in the metadata. The format is
|
45
|
+
# `host1:port1,host2:port2`, and the list can be a subset of brokers or a VIP pointing to a
|
46
|
+
# subset of brokers.
|
47
|
+
config :bootstrap_servers, :validate => :string, :default => 'localhost:9092'
|
48
|
+
# When our memory buffer is exhausted we must either stop accepting new
|
49
|
+
# records (block) or throw errors. By default this setting is true and we block,
|
50
|
+
# however in some scenarios blocking is not desirable and it is better to immediately give an error.
|
51
|
+
config :block_on_buffer_full, :validate => :boolean, :default => true, :deprecated => "This config will be removed in a future release"
|
54
52
|
# The total bytes of memory the producer can use to buffer records waiting to be sent to the server.
|
55
53
|
config :buffer_memory, :validate => :number, :default => 33554432
|
56
54
|
# The compression type for all data generated by the producer.
|
57
55
|
# The default is none (i.e. no compression). Valid values are none, gzip, or snappy.
|
58
56
|
config :compression_type, :validate => ["none", "gzip", "snappy"], :default => "none"
|
59
|
-
# Setting a value greater than zero will cause the client to
|
60
|
-
# resend any record whose send fails with a potentially transient error.
|
61
|
-
config :retries, :validate => :number, :default => 0
|
62
|
-
# The producer will attempt to batch records together into fewer requests whenever multiple
|
63
|
-
# records are being sent to the same partition. This helps performance on both the client
|
64
|
-
# and the server. This configuration controls the default batch size in bytes.
|
65
|
-
config :batch_size, :validate => :number, :default => 16384
|
66
57
|
# The id string to pass to the server when making requests.
|
67
58
|
# The purpose of this is to be able to track the source of requests beyond just
|
68
59
|
# ip/port by allowing a logical application name to be included with the request
|
69
60
|
config :client_id, :validate => :string
|
61
|
+
# Serializer class for the key of the message
|
62
|
+
config :key_serializer, :validate => :string, :default => 'org.apache.kafka.common.serialization.StringSerializer'
|
70
63
|
# The producer groups together any records that arrive in between request
|
71
64
|
# transmissions into a single batched request. Normally this occurs only under
|
72
65
|
# load when records arrive faster than they can be sent out. However in some circumstances
|
@@ -77,63 +70,61 @@ class LogStash::Outputs::Kafka < LogStash::Outputs::Base
|
|
77
70
|
config :linger_ms, :validate => :number, :default => 0
|
78
71
|
# The maximum size of a request
|
79
72
|
config :max_request_size, :validate => :number, :default => 1048576
|
73
|
+
# The key for the message
|
74
|
+
config :message_key, :validate => :string
|
75
|
+
# the timeout setting for initial metadata request to fetch topic metadata.
|
76
|
+
config :metadata_fetch_timeout_ms, :validate => :number, :default => 60000
|
77
|
+
# the max time in milliseconds before a metadata refresh is forced.
|
78
|
+
config :metadata_max_age_ms, :validate => :number, :default => 300000
|
80
79
|
# The size of the TCP receive buffer to use when reading data
|
81
80
|
config :receive_buffer_bytes, :validate => :number, :default => 32768
|
81
|
+
# The amount of time to wait before attempting to reconnect to a given host when a connection fails.
|
82
|
+
config :reconnect_backoff_ms, :validate => :number, :default => 10
|
83
|
+
# The configuration controls the maximum amount of time the client will wait
|
84
|
+
# for the response of a request. If the response is not received before the timeout
|
85
|
+
# elapses the client will resend the request if necessary or fail the request if
|
86
|
+
# retries are exhausted.
|
87
|
+
config :request_timeout_ms, :validate => :string
|
88
|
+
# Setting a value greater than zero will cause the client to
|
89
|
+
# resend any record whose send fails with a potentially transient error.
|
90
|
+
config :retries, :validate => :number, :default => 0
|
91
|
+
# The amount of time to wait before attempting to retry a failed produce request to a given topic partition.
|
92
|
+
config :retry_backoff_ms, :validate => :number, :default => 100
|
82
93
|
# The size of the TCP send buffer to use when sending data.
|
83
94
|
config :send_buffer_bytes, :validate => :number, :default => 131072
|
95
|
+
# Enable SSL/TLS secured communication to Kafka broker. Note that secure communication
|
96
|
+
# is only available with a broker running v0.9 of Kafka.
|
97
|
+
config :ssl, :validate => :boolean, :default => false
|
98
|
+
# The JKS truststore path to validate the Kafka broker's certificate.
|
99
|
+
config :ssl_truststore_location, :validate => :path
|
100
|
+
# The truststore password
|
101
|
+
config :ssl_truststore_password, :validate => :password
|
102
|
+
# If client authentication is required, this setting stores the keystore path.
|
103
|
+
config :ssl_keystore_location, :validate => :path
|
104
|
+
# If client authentication is required, this setting stores the keystore password
|
105
|
+
config :ssl_keystore_password, :validate => :password
|
84
106
|
# The configuration controls the maximum amount of time the server will wait for acknowledgments
|
85
107
|
# from followers to meet the acknowledgment requirements the producer has specified with the
|
86
108
|
# acks configuration. If the requested number of acknowledgments are not met when the timeout
|
87
109
|
# elapses an error will be returned. This timeout is measured on the server side and does not
|
88
110
|
# include the network latency of the request.
|
89
|
-
config :timeout_ms, :validate => :number, :default => 30000
|
90
|
-
#
|
91
|
-
|
92
|
-
#
|
93
|
-
config :
|
94
|
-
# the timeout setting for initial metadata request to fetch topic metadata.
|
95
|
-
config :metadata_fetch_timeout_ms, :validate => :number, :default => 60000
|
96
|
-
# the max time in milliseconds before a metadata refresh is forced.
|
97
|
-
config :metadata_max_age_ms, :validate => :number, :default => 300000
|
98
|
-
# The amount of time to wait before attempting to reconnect to a given host when a connection fails.
|
99
|
-
config :reconnect_backoff_ms, :validate => :number, :default => 10
|
100
|
-
# The amount of time to wait before attempting to retry a failed produce request to a given topic partition.
|
101
|
-
config :retry_backoff_ms, :validate => :number, :default => 100
|
111
|
+
config :timeout_ms, :validate => :number, :default => 30000, :deprecated => "This config will be removed in a future release. Please use request_timeout_ms"
|
112
|
+
# The topic to produce messages to
|
113
|
+
config :topic_id, :validate => :string, :required => true
|
114
|
+
# Serializer class for the value of the message
|
115
|
+
config :value_serializer, :validate => :string, :default => 'org.apache.kafka.common.serialization.StringSerializer'
|
102
116
|
|
103
117
|
public
|
104
118
|
def register
|
105
|
-
|
106
|
-
|
107
|
-
options = {
|
108
|
-
:key_serializer => @key_serializer,
|
109
|
-
:value_serializer => @value_serializer,
|
110
|
-
:bootstrap_servers => @bootstrap_servers,
|
111
|
-
:acks => @acks,
|
112
|
-
:buffer_memory => @buffer_memory,
|
113
|
-
:compression_type => @compression_type,
|
114
|
-
:retries => @retries,
|
115
|
-
:batch_size => @batch_size,
|
116
|
-
:client_id => @client_id,
|
117
|
-
:linger_ms => @linger_ms,
|
118
|
-
:max_request_size => @max_request_size,
|
119
|
-
:receive_buffer_bytes => @receive_buffer_bytes,
|
120
|
-
:send_buffer_bytes => @send_buffer_bytes,
|
121
|
-
:timeout_ms => @timeout_ms,
|
122
|
-
:block_on_buffer_full => @block_on_buffer_full,
|
123
|
-
:metadata_fetch_timeout_ms => @metadata_fetch_timeout_ms,
|
124
|
-
:metadata_max_age_ms => @metadata_max_age_ms,
|
125
|
-
:reconnect_backoff_ms => @reconnect_backoff_ms,
|
126
|
-
:retry_backoff_ms => @retry_backoff_ms
|
127
|
-
}
|
128
|
-
@producer = Kafka::KafkaProducer.new(options)
|
129
|
-
@producer.connect
|
130
|
-
|
131
|
-
@logger.info('Registering kafka producer', :topic_id => @topic_id, :bootstrap_servers => @bootstrap_servers)
|
132
|
-
|
119
|
+
@producer = create_producer
|
133
120
|
@codec.on_event do |event, data|
|
134
121
|
begin
|
135
|
-
|
136
|
-
|
122
|
+
if @message_key.nil?
|
123
|
+
record = org.apache.kafka.clients.producer.ProducerRecord.new(event.sprintf(@topic_id), data)
|
124
|
+
else
|
125
|
+
record = org.apache.kafka.clients.producer.ProducerRecord.new(event.sprintf(@topic_id), event.sprintf(@message_key), data)
|
126
|
+
end
|
127
|
+
@producer.send(record)
|
137
128
|
rescue LogStash::ShutdownSignal
|
138
129
|
@logger.info('Kafka producer got shutdown signal')
|
139
130
|
rescue => e
|
@@ -141,10 +132,10 @@ class LogStash::Outputs::Kafka < LogStash::Outputs::Base
|
|
141
132
|
:exception => e)
|
142
133
|
end
|
143
134
|
end
|
135
|
+
|
144
136
|
end # def register
|
145
137
|
|
146
138
|
def receive(event)
|
147
|
-
|
148
139
|
if event == LogStash::SHUTDOWN
|
149
140
|
return
|
150
141
|
end
|
@@ -154,4 +145,47 @@ class LogStash::Outputs::Kafka < LogStash::Outputs::Base
|
|
154
145
|
def close
|
155
146
|
@producer.close
|
156
147
|
end
|
148
|
+
|
149
|
+
private
|
150
|
+
def create_producer
|
151
|
+
begin
|
152
|
+
props = java.util.Properties.new
|
153
|
+
kafka = org.apache.kafka.clients.producer.ProducerConfig
|
154
|
+
|
155
|
+
props.put(kafka::ACKS_CONFIG, acks)
|
156
|
+
props.put(kafka::BATCH_SIZE_CONFIG, batch_size.to_s)
|
157
|
+
props.put(kafka::BOOTSTRAP_SERVERS_CONFIG, bootstrap_servers)
|
158
|
+
props.put(kafka::BUFFER_MEMORY_CONFIG, buffer_memory.to_s)
|
159
|
+
props.put(kafka::COMPRESSION_TYPE_CONFIG, compression_type)
|
160
|
+
props.put(kafka::CLIENT_ID_CONFIG, client_id) unless client_id.nil?
|
161
|
+
props.put(kafka::KEY_SERIALIZER_CLASS_CONFIG, key_serializer)
|
162
|
+
props.put(kafka::LINGER_MS_CONFIG, linger_ms.to_s)
|
163
|
+
props.put(kafka::MAX_REQUEST_SIZE_CONFIG, max_request_size.to_s)
|
164
|
+
props.put(kafka::RECONNECT_BACKOFF_MS_CONFIG, reconnect_backoff_ms) unless reconnect_backoff_ms.nil?
|
165
|
+
props.put(kafka::REQUEST_TIMEOUT_MS_CONFIG, request_timeout_ms) unless request_timeout_ms.nil?
|
166
|
+
props.put(kafka::RETRIES_CONFIG, retries.to_s)
|
167
|
+
props.put(kafka::RETRY_BACKOFF_MS_CONFIG, retry_backoff_ms.to_s)
|
168
|
+
props.put(kafka::SEND_BUFFER_CONFIG, send_buffer_bytes.to_s)
|
169
|
+
props.put(kafka::VALUE_SERIALIZER_CLASS_CONFIG, value_serializer)
|
170
|
+
|
171
|
+
if ssl
|
172
|
+
if ssl_truststore_location.nil?
|
173
|
+
raise LogStash::ConfigurationError, "ssl_truststore_location must be set when SSL is enabled"
|
174
|
+
end
|
175
|
+
props.put("security.protocol", "SSL")
|
176
|
+
props.put("ssl.truststore.location", ssl_truststore_location)
|
177
|
+
props.put("ssl.truststore.password", ssl_truststore_password.value) unless ssl_truststore_password.nil?
|
178
|
+
|
179
|
+
#Client auth stuff
|
180
|
+
props.put("ssl.keystore.location", ssl_keystore_location) unless ssl_keystore_location.nil?
|
181
|
+
props.put("ssl.keystore.password", ssl_keystore_password.value) unless ssl_keystore_password.nil?
|
182
|
+
end
|
183
|
+
|
184
|
+
org.apache.kafka.clients.producer.KafkaProducer.new(props)
|
185
|
+
rescue => e
|
186
|
+
logger.error("Unable to create Kafka producer from given configuration", :kafka_error_message => e)
|
187
|
+
raise e
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
157
191
|
end #class LogStash::Outputs::Kafka
|
@@ -1,7 +1,8 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-output-kafka'
|
4
|
-
s.version = '2.0.
|
4
|
+
s.version = '2.0.2'
|
5
|
+
s.version = '3.0.0.beta1'
|
5
6
|
s.licenses = ['Apache License (2.0)']
|
6
7
|
s.summary = 'Output events to a Kafka topic. This uses the Kafka Producer API to write messages to a topic on the broker'
|
7
8
|
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
|
@@ -20,12 +21,10 @@ Gem::Specification.new do |s|
|
|
20
21
|
s.metadata = { 'logstash_plugin' => 'true', 'group' => 'output'}
|
21
22
|
|
22
23
|
# Gem dependencies
|
23
|
-
s.add_runtime_dependency "logstash-core
|
24
|
+
s.add_runtime_dependency "logstash-core", ">= 2.0.0", "< 3.0.0"
|
24
25
|
s.add_runtime_dependency 'logstash-codec-plain'
|
25
26
|
s.add_runtime_dependency 'logstash-codec-json'
|
26
27
|
|
27
|
-
s.add_runtime_dependency 'jruby-kafka', '1.5.0'
|
28
|
-
|
29
28
|
s.add_development_dependency 'logstash-devutils'
|
30
29
|
s.add_development_dependency 'poseidon'
|
31
30
|
end
|
@@ -2,20 +2,22 @@
|
|
2
2
|
|
3
3
|
require "logstash/devutils/rspec/spec_helper"
|
4
4
|
require 'logstash/outputs/kafka'
|
5
|
-
require 'jruby-kafka'
|
6
5
|
require 'json'
|
7
6
|
require 'poseidon'
|
8
7
|
|
9
8
|
describe "outputs/kafka", :integration => true do
|
10
|
-
let(:
|
11
|
-
let(:
|
12
|
-
let(:
|
9
|
+
let(:kafka_host) { 'localhost' }
|
10
|
+
let(:kafka_port) { 9092 }
|
11
|
+
let(:num_events) { 10 }
|
12
|
+
let(:base_config) { {'client_id' => 'kafkaoutputspec'} }
|
13
|
+
let(:event) { LogStash::Event.new({'message' => '183.60.215.50 - - [11/Sep/2014:22:00:00 +0000] "GET /scripts/netcat-webserver HTTP/1.1" 200 182 "-" "Mozilla/5.0 (compatible; EasouSpider; +http://www.easou.com/search/spider.html)"', '@timestamp' => LogStash::Timestamp.at(0) }) }
|
13
14
|
|
14
15
|
|
15
16
|
context 'when outputting messages' do
|
17
|
+
let(:test_topic) { 'topic1' }
|
16
18
|
let(:num_events) { 3 }
|
17
19
|
let(:consumer) do
|
18
|
-
Poseidon::PartitionConsumer.new("my_test_consumer",
|
20
|
+
Poseidon::PartitionConsumer.new("my_test_consumer", kafka_host, kafka_port,
|
19
21
|
test_topic, 0, :earliest_offset)
|
20
22
|
end
|
21
23
|
subject do
|
@@ -24,42 +26,107 @@ describe "outputs/kafka", :integration => true do
|
|
24
26
|
|
25
27
|
before :each do
|
26
28
|
config = base_config.merge({"topic_id" => test_topic})
|
27
|
-
|
28
|
-
kafka.register
|
29
|
-
num_events.times do kafka.receive(event) end
|
30
|
-
kafka.close
|
29
|
+
load_kafka_data(config)
|
31
30
|
end
|
32
31
|
|
33
32
|
it 'should have data integrity' do
|
34
33
|
expect(subject.size).to eq(num_events)
|
35
34
|
subject.each do |m|
|
36
|
-
expect(m.value).to eq(event.
|
35
|
+
expect(m.value).to eq(event.to_s)
|
37
36
|
end
|
38
37
|
end
|
38
|
+
|
39
39
|
end
|
40
40
|
|
41
41
|
context 'when setting message_key' do
|
42
42
|
let(:num_events) { 10 }
|
43
|
-
let(:test_topic) { '
|
43
|
+
let(:test_topic) { 'topic2' }
|
44
44
|
let!(:consumer0) do
|
45
|
-
Poseidon::PartitionConsumer.new("
|
45
|
+
Poseidon::PartitionConsumer.new("my_test_consumer", kafka_host, kafka_port,
|
46
46
|
test_topic, 0, :earliest_offset)
|
47
47
|
end
|
48
48
|
let!(:consumer1) do
|
49
|
-
Poseidon::PartitionConsumer.new("
|
49
|
+
Poseidon::PartitionConsumer.new("my_test_consumer", kafka_host, kafka_port,
|
50
50
|
test_topic, 1, :earliest_offset)
|
51
51
|
end
|
52
52
|
|
53
53
|
before :each do
|
54
54
|
config = base_config.merge({"topic_id" => test_topic, "message_key" => "static_key"})
|
55
|
-
|
56
|
-
kafka.register
|
57
|
-
num_events.times do kafka.receive(event) end
|
58
|
-
kafka.close
|
55
|
+
load_kafka_data(config)
|
59
56
|
end
|
60
57
|
|
61
58
|
it 'should send all events to one partition' do
|
62
59
|
expect(consumer0.fetch.size == num_events || consumer1.fetch.size == num_events).to be true
|
63
60
|
end
|
64
61
|
end
|
62
|
+
|
63
|
+
context 'when using gzip compression' do
|
64
|
+
let(:test_topic) { 'gzip_topic' }
|
65
|
+
let!(:consumer) do
|
66
|
+
Poseidon::PartitionConsumer.new("my_test_consumer", kafka_host, kafka_port,
|
67
|
+
test_topic, 0, :earliest_offset)
|
68
|
+
end
|
69
|
+
subject do
|
70
|
+
consumer.fetch
|
71
|
+
end
|
72
|
+
|
73
|
+
before :each do
|
74
|
+
config = base_config.merge({"topic_id" => test_topic, "compression_type" => "gzip"})
|
75
|
+
load_kafka_data(config)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should have data integrity' do
|
79
|
+
expect(subject.size).to eq(num_events)
|
80
|
+
subject.each do |m|
|
81
|
+
expect(m.value).to eq(event.to_s)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when using multi partition topic' do
|
87
|
+
let(:num_events) { 10 }
|
88
|
+
let(:test_topic) { 'topic3' }
|
89
|
+
let!(:consumer0) do
|
90
|
+
Poseidon::PartitionConsumer.new("my_test_consumer", kafka_host, kafka_port,
|
91
|
+
test_topic, 0, :earliest_offset)
|
92
|
+
end
|
93
|
+
let!(:consumer1) do
|
94
|
+
Poseidon::PartitionConsumer.new("my_test_consumer", kafka_host, kafka_port,
|
95
|
+
test_topic, 1, :earliest_offset)
|
96
|
+
end
|
97
|
+
|
98
|
+
let!(:consumer2) do
|
99
|
+
Poseidon::PartitionConsumer.new("my_test_consumer", kafka_host, kafka_port,
|
100
|
+
test_topic, 2, :earliest_offset)
|
101
|
+
end
|
102
|
+
|
103
|
+
before :each do
|
104
|
+
config = base_config.merge({"topic_id" => test_topic})
|
105
|
+
load_kafka_data(config)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should distribute events to all partition' do
|
109
|
+
consumer0_records = consumer0.fetch
|
110
|
+
consumer1_records = consumer1.fetch
|
111
|
+
consumer2_records = consumer2.fetch
|
112
|
+
|
113
|
+
expect(consumer0_records.size > 1 &&
|
114
|
+
consumer1_records.size > 1 &&
|
115
|
+
consumer2_records.size > 1).to be true
|
116
|
+
|
117
|
+
all_records = consumer0_records + consumer1_records + consumer2_records
|
118
|
+
expect(all_records.size).to eq(num_events)
|
119
|
+
all_records.each do |m|
|
120
|
+
expect(m.value).to eq(event.to_s)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def load_kafka_data(config)
|
126
|
+
kafka = LogStash::Outputs::Kafka.new(config)
|
127
|
+
kafka.register
|
128
|
+
num_events.times do kafka.receive(event) end
|
129
|
+
kafka.close
|
130
|
+
end
|
131
|
+
|
65
132
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require "logstash/devutils/rspec/spec_helper"
|
3
3
|
require 'logstash/outputs/kafka'
|
4
|
-
require 'jruby-kafka'
|
5
4
|
require 'json'
|
6
5
|
|
7
6
|
describe "outputs/kafka" do
|
@@ -25,8 +24,8 @@ describe "outputs/kafka" do
|
|
25
24
|
|
26
25
|
context 'when outputting messages' do
|
27
26
|
it 'should send logstash event to kafka broker' do
|
28
|
-
expect_any_instance_of(
|
29
|
-
.with(
|
27
|
+
expect_any_instance_of(org.apache.kafka.clients.producer.KafkaProducer).to receive(:send)
|
28
|
+
.with(an_instance_of(org.apache.kafka.clients.producer.ProducerRecord))
|
30
29
|
kafka = LogStash::Outputs::Kafka.new(simple_kafka_config)
|
31
30
|
kafka.register
|
32
31
|
kafka.receive(event)
|
@@ -34,19 +33,26 @@ describe "outputs/kafka" do
|
|
34
33
|
|
35
34
|
it 'should support Event#sprintf placeholders in topic_id' do
|
36
35
|
topic_field = 'topic_name'
|
37
|
-
|
38
|
-
.with(
|
36
|
+
expect(org.apache.kafka.clients.producer.ProducerRecord).to receive(:new)
|
37
|
+
.with("my_topic", event.to_s)
|
38
|
+
expect_any_instance_of(org.apache.kafka.clients.producer.KafkaProducer).to receive(:send)
|
39
39
|
kafka = LogStash::Outputs::Kafka.new({'topic_id' => "%{#{topic_field}}"})
|
40
40
|
kafka.register
|
41
41
|
kafka.receive(event)
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'should support field referenced message_keys' do
|
45
|
-
|
46
|
-
.with(
|
45
|
+
expect(org.apache.kafka.clients.producer.ProducerRecord).to receive(:new)
|
46
|
+
.with("test", "172.0.0.1", event.to_s)
|
47
|
+
expect_any_instance_of(org.apache.kafka.clients.producer.KafkaProducer).to receive(:send)
|
47
48
|
kafka = LogStash::Outputs::Kafka.new(simple_kafka_config.merge({"message_key" => "%{host}"}))
|
48
49
|
kafka.register
|
49
50
|
kafka.receive(event)
|
50
51
|
end
|
52
|
+
|
53
|
+
it 'should raise config error when truststore location is not set and ssl is enabled' do
|
54
|
+
kafka = LogStash::Outputs::Kafka.new(simple_kafka_config.merge({"ssl" => "true"}))
|
55
|
+
expect { kafka.register }.to raise_error(LogStash::ConfigurationError, /ssl_truststore_location must be set when SSL is enabled/)
|
56
|
+
end
|
51
57
|
end
|
52
58
|
end
|
Binary file
|
Binary file
|
Binary file
|
metadata
CHANGED
@@ -1,99 +1,91 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-output-kafka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elasticsearch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: logstash-core-plugin-api
|
15
|
-
version_requirements: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ~>
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.0'
|
20
14
|
requirement: !ruby/object:Gem::Requirement
|
21
15
|
requirements:
|
22
|
-
- -
|
16
|
+
- - '>='
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: 2.0.0
|
19
|
+
- - <
|
23
20
|
- !ruby/object:Gem::Version
|
24
|
-
version:
|
21
|
+
version: 3.0.0
|
22
|
+
name: logstash-core
|
25
23
|
prerelease: false
|
26
24
|
type: :runtime
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: logstash-codec-plain
|
29
25
|
version_requirements: !ruby/object:Gem::Requirement
|
30
26
|
requirements:
|
31
27
|
- - '>='
|
32
28
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
29
|
+
version: 2.0.0
|
30
|
+
- - <
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
35
35
|
requirements:
|
36
36
|
- - '>='
|
37
37
|
- !ruby/object:Gem::Version
|
38
38
|
version: '0'
|
39
|
+
name: logstash-codec-plain
|
39
40
|
prerelease: false
|
40
41
|
type: :runtime
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: logstash-codec-json
|
43
42
|
version_requirements: !ruby/object:Gem::Requirement
|
44
43
|
requirements:
|
45
44
|
- - '>='
|
46
45
|
- !ruby/object:Gem::Version
|
47
46
|
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
requirements:
|
50
50
|
- - '>='
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: '0'
|
53
|
+
name: logstash-codec-json
|
53
54
|
prerelease: false
|
54
55
|
type: :runtime
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: jruby-kafka
|
57
|
-
version_requirements: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - '='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 1.5.0
|
62
|
-
requirement: !ruby/object:Gem::Requirement
|
63
|
-
requirements:
|
64
|
-
- - '='
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: 1.5.0
|
67
|
-
prerelease: false
|
68
|
-
type: :runtime
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: logstash-devutils
|
71
56
|
version_requirements: !ruby/object:Gem::Requirement
|
72
57
|
requirements:
|
73
58
|
- - '>='
|
74
59
|
- !ruby/object:Gem::Version
|
75
60
|
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
76
62
|
requirement: !ruby/object:Gem::Requirement
|
77
63
|
requirements:
|
78
64
|
- - '>='
|
79
65
|
- !ruby/object:Gem::Version
|
80
66
|
version: '0'
|
67
|
+
name: logstash-devutils
|
81
68
|
prerelease: false
|
82
69
|
type: :development
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: poseidon
|
85
70
|
version_requirements: !ruby/object:Gem::Requirement
|
86
71
|
requirements:
|
87
72
|
- - '>='
|
88
73
|
- !ruby/object:Gem::Version
|
89
74
|
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
90
76
|
requirement: !ruby/object:Gem::Requirement
|
91
77
|
requirements:
|
92
78
|
- - '>='
|
93
79
|
- !ruby/object:Gem::Version
|
94
80
|
version: '0'
|
81
|
+
name: poseidon
|
95
82
|
prerelease: false
|
96
83
|
type: :development
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
97
89
|
description: This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program
|
98
90
|
email: info@elastic.co
|
99
91
|
executables: []
|
@@ -107,10 +99,14 @@ files:
|
|
107
99
|
- LICENSE
|
108
100
|
- NOTICE.TXT
|
109
101
|
- README.md
|
102
|
+
- lib/logstash-output-kafka_jars.rb
|
110
103
|
- lib/logstash/outputs/kafka.rb
|
111
104
|
- logstash-output-kafka.gemspec
|
112
105
|
- spec/integration/outputs/kafka_spec.rb
|
113
106
|
- spec/unit/outputs/kafka_spec.rb
|
107
|
+
- vendor/jar-dependencies/runtime-jars/kafka-clients-0.9.0.1.jar
|
108
|
+
- vendor/jar-dependencies/runtime-jars/slf4j-api-1.7.13.jar
|
109
|
+
- vendor/jar-dependencies/runtime-jars/slf4j-noop-1.7.13.jar
|
114
110
|
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
115
111
|
licenses:
|
116
112
|
- Apache License (2.0)
|
@@ -128,12 +124,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
124
|
version: '0'
|
129
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
126
|
requirements:
|
131
|
-
- - '
|
127
|
+
- - '>'
|
132
128
|
- !ruby/object:Gem::Version
|
133
|
-
version:
|
129
|
+
version: 1.3.1
|
134
130
|
requirements: []
|
135
131
|
rubyforge_project:
|
136
|
-
rubygems_version: 2.4.
|
132
|
+
rubygems_version: 2.4.5
|
137
133
|
signing_key:
|
138
134
|
specification_version: 4
|
139
135
|
summary: Output events to a Kafka topic. This uses the Kafka Producer API to write messages to a topic on the broker
|