logstash-output-elasticsearch 1.1.0-java → 2.0.0.beta4-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +10 -3
  4. data/README.md +4 -4
  5. data/lib/logstash/outputs/elasticsearch/http_client.rb +144 -0
  6. data/lib/logstash/outputs/elasticsearch.rb +93 -319
  7. data/logstash-output-elasticsearch.gemspec +1 -3
  8. data/spec/es_spec_helper.rb +38 -34
  9. data/spec/integration/outputs/create_spec.rb +56 -0
  10. data/spec/integration/outputs/index_spec.rb +5 -7
  11. data/spec/integration/outputs/retry_spec.rb +118 -126
  12. data/spec/integration/outputs/routing_spec.rb +5 -33
  13. data/spec/integration/outputs/secure_spec.rb +4 -9
  14. data/spec/integration/outputs/templates_spec.rb +85 -91
  15. data/spec/integration/outputs/update_spec.rb +41 -46
  16. data/spec/unit/outputs/elasticsearch/protocol_spec.rb +45 -36
  17. data/spec/unit/outputs/elasticsearch_proxy_spec.rb +3 -4
  18. data/spec/unit/outputs/elasticsearch_spec.rb +2 -151
  19. data/spec/unit/outputs/elasticsearch_ssl_spec.rb +38 -63
  20. metadata +67 -101
  21. data/lib/logstash/outputs/elasticsearch/protocol.rb +0 -333
  22. data/lib/logstash-output-elasticsearch_jars.rb +0 -5
  23. data/spec/integration/outputs/elasticsearch/node_spec.rb +0 -36
  24. data/spec/integration/outputs/transport_create_spec.rb +0 -94
  25. data/vendor/jar-dependencies/runtime-jars/antlr-runtime-3.5.jar +0 -0
  26. data/vendor/jar-dependencies/runtime-jars/asm-4.1.jar +0 -0
  27. data/vendor/jar-dependencies/runtime-jars/asm-commons-4.1.jar +0 -0
  28. data/vendor/jar-dependencies/runtime-jars/elasticsearch-1.7.0.jar +0 -0
  29. data/vendor/jar-dependencies/runtime-jars/lucene-analyzers-common-4.10.4.jar +0 -0
  30. data/vendor/jar-dependencies/runtime-jars/lucene-core-4.10.4.jar +0 -0
  31. data/vendor/jar-dependencies/runtime-jars/lucene-grouping-4.10.4.jar +0 -0
  32. data/vendor/jar-dependencies/runtime-jars/lucene-highlighter-4.10.4.jar +0 -0
  33. data/vendor/jar-dependencies/runtime-jars/lucene-join-4.10.4.jar +0 -0
  34. data/vendor/jar-dependencies/runtime-jars/lucene-memory-4.10.4.jar +0 -0
  35. data/vendor/jar-dependencies/runtime-jars/lucene-misc-4.10.4.jar +0 -0
  36. data/vendor/jar-dependencies/runtime-jars/lucene-queries-4.10.4.jar +0 -0
  37. data/vendor/jar-dependencies/runtime-jars/lucene-queryparser-4.10.4.jar +0 -0
  38. data/vendor/jar-dependencies/runtime-jars/lucene-sandbox-4.10.4.jar +0 -0
  39. data/vendor/jar-dependencies/runtime-jars/lucene-spatial-4.10.4.jar +0 -0
  40. data/vendor/jar-dependencies/runtime-jars/lucene-suggest-4.10.4.jar +0 -0
  41. data/vendor/jar-dependencies/runtime-jars/spatial4j-0.4.1.jar +0 -0
@@ -8,32 +8,20 @@ require "stud/buffer"
8
8
  require "socket" # for Socket.gethostname
9
9
  require "thread" # for safe queueing
10
10
  require "uri" # for escaping user input
11
- require 'logstash-output-elasticsearch_jars.rb'
11
+ require "logstash/outputs/elasticsearch/http_client"
12
12
 
13
13
  # This output lets you store logs in Elasticsearch and is the most recommended
14
14
  # output for Logstash. If you plan on using the Kibana web interface, you'll
15
- # need to use this output.
15
+ # want to use this output.
16
16
  #
17
- # *VERSION NOTE*: Your Elasticsearch cluster must be running Elasticsearch 1.0.0 or later.
17
+ # This output only speaks the HTTP, which is the preferred protocol for interacting with Elasticsearch. By default
18
+ # Elasticsearch exposes HTTP on port 9200.
18
19
  #
19
- # If you want to set other Elasticsearch options that are not exposed directly
20
- # as configuration options, there are two methods:
21
- #
22
- # * Create an `elasticsearch.yml` file in the $PWD of the Logstash process
23
- # * Pass in es.* java properties (`java -Des.node.foo=` or `ruby -J-Des.node.foo=`)
24
- #
25
- # With the default `protocol` setting ("node"), this plugin will join your
26
- # Elasticsearch cluster as a client node, so it will show up in Elasticsearch's
27
- # cluster status.
20
+ # We strongly encourage the use of HTTP over the node protocol. It is just as
21
+ # fast and far easier to administer. For those wishing to use the java protocol please see the 'elasticsearch_java' gem.
28
22
  #
29
23
  # You can learn more about Elasticsearch at <https://www.elastic.co/products/elasticsearch>
30
24
  #
31
- # ==== Operational Notes
32
- #
33
- # If using the default `protocol` setting ("node"), your firewalls might need
34
- # to permit port 9300 in *both* directions (from Logstash to Elasticsearch, and
35
- # Elasticsearch to Logstash)
36
- #
37
25
  # ==== Retry Policy
38
26
  #
39
27
  # By default all bulk requests to ES are synchronous. Not all events in the bulk requests
@@ -125,90 +113,24 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
125
113
  # This can be dynamic using the `%{foo}` syntax.
126
114
  config :routing, :validate => :string
127
115
 
128
- # The name of your cluster if you set it on the Elasticsearch side. Useful
129
- # for discovery when using `node` or `transport` protocols.
130
- # By default, it looks for a cluster named 'elasticsearch'.
131
- config :cluster, :validate => :string
132
-
133
- # For the `node` protocol, if you do not specify `host`, it will attempt to use
134
- # multicast discovery to connect to Elasticsearch. If http://www.elastic.co/guide/en/elasticsearch/guide/current/_important_configuration_changes.html#_prefer_unicast_over_multicast[multicast is disabled] in Elasticsearch,
135
- # you must include the hostname or IP address of the host(s) to use for Elasticsearch unicast discovery.
136
- # Remember the `node` protocol uses the http://www.elastic.co/guide/en/elasticsearch/reference/current/modules-transport.html#modules-transport[transport] address (eg. 9300, not 9200).
137
- # `"127.0.0.1"`
138
- # `["127.0.0.1:9300","127.0.0.2:9300"]`
139
- # When setting hosts for `node` protocol, it is important to confirm that at least one non-client
140
- # node is listed in the `host` list. Also keep in mind that the `host` parameter when used with
141
- # the `node` protocol is for *discovery purposes only* (not for load balancing). When multiple hosts
142
- # are specified, it will contact the first host to see if it can use it to discover the cluster. If not,
143
- # then it will contact the second host in the list and so forth. With the `node` protocol,
144
- # Logstash will join the Elasticsearch cluster as a node client (which has a copy of the cluster
145
- # state) and this node client is the one that will automatically handle the load balancing of requests
146
- # across data nodes in the cluster.
147
- # If you are looking for a high availability setup, our recommendation is to use the `transport` protocol (below),
148
- # set up multiple http://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html[client nodes] and list the client nodes in the `host` parameter.
149
- #
150
- # For the `transport` protocol, it will load balance requests across the hosts specified in the `host` parameter.
151
- # Remember the `transport` protocol uses the http://www.elastic.co/guide/en/elasticsearch/reference/current/modules-transport.html#modules-transport[transport] address (eg. 9300, not 9200).
152
- # `"127.0.0.1"`
153
- # `["127.0.0.1:9300","127.0.0.2:9300"]`
154
- # There is also a `sniffing` option (see below) that can be used with the transport protocol to instruct it to use the host to sniff for
155
- # "alive" nodes in the cluster and automatically use it as the hosts list (but will skip the dedicated master nodes).
156
- # If you do not use the sniffing option, it is important to exclude http://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html[dedicated master nodes] from the `host` list
157
- # to prevent Logstash from sending bulk requests to the master nodes. So this parameter should only reference either data or client nodes.
158
- #
159
- # For the `http` protocol, it will load balance requests across the hosts specified in the `host` parameter.
116
+ # Sets the host(s) of the remote instance. If given an array it will load balance requests across the hosts specified in the `host` parameter.
160
117
  # Remember the `http` protocol uses the http://www.elastic.co/guide/en/elasticsearch/reference/current/modules-http.html#modules-http[http] address (eg. 9200, not 9300).
161
118
  # `"127.0.0.1"`
162
119
  # `["127.0.0.1:9200","127.0.0.2:9200"]`
163
120
  # It is important to exclude http://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html[dedicated master nodes] from the `host` list
164
121
  # to prevent LS from sending bulk requests to the master nodes. So this parameter should only reference either data or client nodes.
165
122
 
166
- config :host, :validate => :array
167
-
168
- # The port for Elasticsearch transport to use.
169
- #
170
- # If you do not set this, the following defaults are used:
171
- # * `protocol => http` - port 9200
172
- # * `protocol => transport` - port 9300-9305
173
- # * `protocol => node` - port 9300-9305
174
- config :port, :validate => :string
123
+ config :hosts, :validate => :array
175
124
 
176
- # The name/address of the host to bind to for Elasticsearch clustering
177
- config :bind_host, :validate => :string
178
-
179
- # This is only valid for the 'node' protocol.
180
- #
181
- # The port for the node to listen on.
182
- config :bind_port, :validate => :number
183
-
184
- # Run the Elasticsearch server embedded in this process.
185
- # This option is useful if you want to run a single Logstash process that
186
- # handles log processing and indexing; it saves you from needing to run
187
- # a separate Elasticsearch process. An example use case is
188
- # proof-of-concept testing.
189
- # WARNING: This is not recommended for production use!
190
- config :embedded, :validate => :boolean, :default => false
191
-
192
- # If you are running the embedded Elasticsearch server, you can set the http
193
- # port it listens on here; it is not common to need this setting changed from
194
- # default.
195
- config :embedded_http_port, :validate => :string, :default => "9200-9300"
196
-
197
- # This setting no longer does anything. It exists to keep config validation
198
- # from failing. It will be removed in future versions.
199
- config :max_inflight_requests, :validate => :number, :default => 50, :deprecated => true
200
-
201
- # The node name Elasticsearch will use when joining a cluster.
202
- #
203
- # By default, this is generated internally by the ES client.
204
- config :node_name, :validate => :string
125
+ # You can set the remote port as part of the host, or explicitly here as well
126
+ config :port, :validate => :string, :default => 9200
205
127
 
206
128
  # This plugin uses the bulk index api for improved indexing performance.
207
129
  # To make efficient bulk api calls, we will buffer a certain number of
208
130
  # events before flushing that out to Elasticsearch. This setting
209
131
  # controls how many events will be buffered before sending a batch
210
132
  # of events.
211
- config :flush_size, :validate => :number, :default => 5000
133
+ config :flush_size, :validate => :number, :default => 500
212
134
 
213
135
  # The amount of time since last flush before a flush is forced.
214
136
  #
@@ -221,32 +143,6 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
221
143
  # near-real-time.
222
144
  config :idle_flush_time, :validate => :number, :default => 1
223
145
 
224
- # Choose the protocol used to talk to Elasticsearch.
225
- #
226
- # The 'node' protocol (default) will connect to the cluster as a normal Elasticsearch
227
- # node (but will not store data). If you use the `node` protocol, you must permit
228
- # bidirectional communication on the port 9300 (or whichever port you have
229
- # configured).
230
- #
231
- # If you do not specify the `host` parameter, it will use multicast for http://www.elastic.co/guide/en/elasticsearch/reference/current/modules-discovery-zen.html[Elasticsearch discovery]. While this may work in a test/dev environment where multicast is enabled in
232
- # Elasticsearch, we strongly recommend http://www.elastic.co/guide/en/elasticsearch/guide/current/_important_configuration_changes.html#_prefer_unicast_over_multicast[disabling multicast]
233
- # in Elasticsearch. To connect to an Elasticsearch cluster with multicast disabled,
234
- # you must include the `host` parameter (see relevant section above).
235
- #
236
- # The 'transport' protocol will connect to the host you specify and will
237
- # not show up as a 'node' in the Elasticsearch cluster. This is useful
238
- # in situations where you cannot permit connections outbound from the
239
- # Elasticsearch cluster to this Logstash server.
240
- #
241
- # The 'http' protocol will use the Elasticsearch REST/HTTP interface to talk
242
- # to elasticsearch.
243
- #
244
- # All protocols will use bulk requests when talking to Elasticsearch.
245
- #
246
- # The default `protocol` setting under java/jruby is "node". The default
247
- # `protocol` on non-java rubies is "http"
248
- config :protocol, :validate => [ "node", "transport", "http" ]
249
-
250
146
  # The Elasticsearch action to perform. Valid actions are: `index`, `delete`.
251
147
  #
252
148
  # Use of this setting *REQUIRES* you also configure the `document_id` setting
@@ -259,10 +155,9 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
259
155
  # - create: indexes a document, fails if a document by that id already exists in the index.
260
156
  # - update: updates a document by id
261
157
  # following action is not supported by HTTP protocol
262
- # - create_unless_exists: creates a document, fails if no id is provided
263
158
  #
264
159
  # For more details on actions, check out the http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-bulk.html[Elasticsearch bulk API documentation]
265
- config :action, :validate => :string, :default => "index"
160
+ config :action, :validate => %w(index delete create update), :default => "index"
266
161
 
267
162
  # Username and password (only valid when protocol is HTTP; this setting works with HTTP or HTTPS auth)
268
163
  config :user, :validate => :string
@@ -299,10 +194,16 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
299
194
  # Set the truststore password
300
195
  config :keystore_password, :validate => :password
301
196
 
302
- # Enable cluster sniffing (transport only)
197
+ # Enable cluster sniffing
303
198
  # Asks host for the list of all cluster nodes and adds them to the hosts list
199
+ # Will return ALL nodes with HTTP enabled (including master nodes!). If you use
200
+ # this with master nodes, you probably want to disable HTTP on them by setting
201
+ # `http.enabled` to false in their elasticsearch.yml.
304
202
  config :sniffing, :validate => :boolean, :default => false
305
203
 
204
+ # How long to wait, in seconds, between sniffing attempts
205
+ config :sniffing_delay, :validate => :number, :default => 30
206
+
306
207
  # Set max retry for each event
307
208
  config :max_retries, :validate => :number, :default => 3
308
209
 
@@ -326,14 +227,9 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
326
227
  # create a new document with this parameter as json string if document_id doesn't exists
327
228
  config :upsert, :validate => :string, :default => ""
328
229
 
329
-
330
- # Set the timeout for network operations and requests sent Elasticsearch. If
331
- # a timeout occurs, the request will be retried.
332
- config :timeout, :validate => :number
333
-
334
230
  public
335
231
  def register
336
- @submit_mutex = Mutex.new
232
+ @hosts = Array(@hosts)
337
233
  # retry-specific variables
338
234
  @retry_flush_mutex = Mutex.new
339
235
  @retry_teardown_requested = Concurrent::AtomicBoolean.new(false)
@@ -341,67 +237,25 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
341
237
  @retry_queue_needs_flushing = ConditionVariable.new
342
238
  @retry_queue_not_full = ConditionVariable.new
343
239
  @retry_queue = Queue.new
240
+ @submit_mutex = Mutex.new
344
241
 
345
242
  client_settings = {}
243
+ common_options = {
244
+ :client_settings => client_settings,
245
+ :sniffing => @sniffing,
246
+ :sniffing_delay => @sniffing_delay
247
+ }
346
248
 
249
+ client_settings[:path] = "/#{@path}/".gsub(/\/+/, "/") # Normalize slashes
250
+ @logger.debug? && @logger.debug("Normalizing http path", :path => @path, :normalized => client_settings[:path])
347
251
 
348
- if @protocol.nil?
349
- @protocol = LogStash::Environment.jruby? ? "node" : "http"
350
- end
351
-
352
- if @protocol == "http"
353
- if @action == "create_unless_exists"
354
- raise(LogStash::ConfigurationError, "action => 'create_unless_exists' is not supported under the HTTP protocol");
355
- end
356
-
357
- client_settings[:path] = "/#{@path}/".gsub(/\/+/, "/") # Normalize slashes
358
- @logger.debug? && @logger.debug("Normalizing http path", :path => @path, :normalized => client_settings[:path])
359
- end
360
-
361
- if ["node", "transport"].include?(@protocol)
362
- # Node or TransportClient; requires JRuby
363
- raise(LogStash::PluginLoadingError, "This configuration requires JRuby. If you are not using JRuby, you must set 'protocol' to 'http'. For example: output { elasticsearch { protocol => \"http\" } }") unless LogStash::Environment.jruby?
364
-
365
- client_settings["cluster.name"] = @cluster if @cluster
366
- client_settings["network.host"] = @bind_host if @bind_host
367
- client_settings["transport.tcp.port"] = @bind_port if @bind_port
368
- client_settings["client.transport.sniff"] = @sniffing
369
-
370
- if @node_name
371
- client_settings["node.name"] = @node_name
372
- else
373
- client_settings["node.name"] = "logstash-#{Socket.gethostname}-#{$$}-#{object_id}"
374
- end
375
-
376
- @@plugins.each do |plugin|
377
- name = plugin.name.split('-')[-1]
378
- client_settings.merge!(LogStash::Outputs::ElasticSearch.const_get(name.capitalize).create_client_config(self))
379
- end
380
- end
381
-
382
- require "logstash/outputs/elasticsearch/protocol"
383
-
384
- if @port.nil?
385
- @port = case @protocol
386
- when "http"; "9200"
387
- when "transport", "node"; "9300-9305"
388
- end
389
- end
390
-
391
- if @host.nil? && @protocol != "node" # node can use zen discovery
252
+ if @hosts.nil? || @hosts.empty?
392
253
  @logger.info("No 'host' set in elasticsearch output. Defaulting to localhost")
393
- @host = ["localhost"]
254
+ @hosts = ["localhost"]
394
255
  end
395
256
 
396
257
  client_settings.merge! setup_ssl()
397
258
  client_settings.merge! setup_proxy()
398
-
399
- common_options = {
400
- :protocol => @protocol,
401
- :client_settings => client_settings
402
- }
403
-
404
- common_options[:timeout] = @timeout if @timeout
405
259
  common_options.merge! setup_basic_auth()
406
260
 
407
261
  # Update API setup
@@ -411,61 +265,22 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
411
265
  }
412
266
  common_options.merge! update_options if @action == 'update'
413
267
 
414
- client_class = case @protocol
415
- when "transport"
416
- LogStash::Outputs::Elasticsearch::Protocols::TransportClient
417
- when "node"
418
- LogStash::Outputs::Elasticsearch::Protocols::NodeClient
419
- when /http/
420
- LogStash::Outputs::Elasticsearch::Protocols::HTTPClient
421
- end
422
-
423
- if @embedded
424
- raise(LogStash::ConfigurationError, "The 'embedded => true' setting is only valid for the elasticsearch output under JRuby. You are running #{RUBY_DESCRIPTION}") unless LogStash::Environment.jruby?
425
- @logger.warn("The 'embedded => true' setting is enabled. This is not recommended for production use!!!")
426
- # LogStash::Environment.load_elasticsearch_jars!
427
-
428
- # Default @host with embedded to localhost. This should help avoid
429
- # newbies tripping on ubuntu and other distros that have a default
430
- # firewall that blocks multicast.
431
- @host ||= ["localhost"]
432
-
433
- # Start Elasticsearch local.
434
- start_local_elasticsearch
435
- end
436
-
437
- @client = Array.new
438
-
439
- if protocol == "node" || @host.nil? # if @protocol is "node" or @host is not set
440
- options = { :host => @host, :port => @port }.merge(common_options)
441
- @client = [client_class.new(options)]
442
- else # if @protocol in ["transport","http"]
443
- @client = @host.map do |host|
444
- (_host,_port) = host.split ":"
445
- options = { :host => _host, :port => _port || @port }.merge(common_options)
446
- @logger.info "Create client to elasticsearch server on #{_host}:#{_port}"
447
- client_class.new(options)
448
- end # @host.map
449
- end
268
+ @client = LogStash::Outputs::Elasticsearch::HttpClient.new(
269
+ common_options.merge(:hosts => @hosts, :port => @port)
270
+ )
450
271
 
451
272
  if @manage_template
452
- for client in @client
453
- begin
454
- @logger.info("Automatic template management enabled", :manage_template => @manage_template.to_s)
455
- client.template_install(@template_name, get_template, @template_overwrite)
456
- break
457
- rescue => e
458
- @logger.error("Failed to install template: #{e.message}")
459
- end
460
- end # for @client loop
461
- end # if @manage_templates
273
+ begin
274
+ @logger.info("Automatic template management enabled", :manage_template => @manage_template.to_s)
275
+ @client.template_install(@template_name, get_template, @template_overwrite)
276
+ rescue => e
277
+ @logger.error("Failed to install template: #{e.message}")
278
+ end
279
+ end
462
280
 
463
- @logger.info("New Elasticsearch output", :cluster => @cluster,
464
- :host => @host, :port => @port, :embedded => @embedded,
465
- :protocol => @protocol)
281
+ @logger.info("New Elasticsearch output", :hosts => @hosts, :port => @port)
466
282
 
467
283
  @client_idx = 0
468
- @current_client = @client[@client_idx]
469
284
 
470
285
  buffer_initialize(
471
286
  :max_items => @flush_size,
@@ -488,7 +303,6 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
488
303
  end
489
304
  end # def register
490
305
 
491
-
492
306
  public
493
307
  def get_template
494
308
  if @template.nil?
@@ -538,29 +352,27 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
538
352
  end # def receive
539
353
 
540
354
  public
541
- # synchronize the @current_client.bulk call to avoid concurrency/thread safety issues with the
542
- # # client libraries which might not be thread safe. the submit method can be called from both the
543
- # # Stud::Buffer flush thread and from our own retry thread.
355
+ # The submit method can be called from both the
356
+ # Stud::Buffer flush thread and from our own retry thread.
544
357
  def submit(actions)
545
- es_actions = actions.map { |a, doc, event| [a, doc, event.to_hash] }
546
- @submit_mutex.lock
547
- begin
548
- bulk_response = @current_client.bulk(es_actions)
549
- ensure
550
- @submit_mutex.unlock
551
- end
552
- if bulk_response["errors"]
553
- actions_with_responses = actions.zip(bulk_response['statuses'])
554
- actions_to_retry = []
555
- actions_with_responses.each do |action, resp_code|
556
- if RETRYABLE_CODES.include?(resp_code)
557
- @logger.warn "retrying failed action with response code: #{resp_code}"
558
- actions_to_retry << action
559
- elsif not SUCCESS_CODES.include?(resp_code)
560
- @logger.warn "failed action with response of #{resp_code}, dropping action: #{action}"
358
+ @submit_mutex.synchronize do
359
+ es_actions = actions.map { |a, doc, event| [a, doc, event.to_hash] }
360
+
361
+ bulk_response = @client.bulk(es_actions)
362
+
363
+ if bulk_response["errors"]
364
+ actions_with_responses = actions.zip(bulk_response['statuses'])
365
+ actions_to_retry = []
366
+ actions_with_responses.each do |action, resp_code|
367
+ if RETRYABLE_CODES.include?(resp_code)
368
+ @logger.warn "retrying failed action with response code: #{resp_code}"
369
+ actions_to_retry << action
370
+ elsif not SUCCESS_CODES.include?(resp_code)
371
+ @logger.warn "failed action with response of #{resp_code}, dropping action: #{action}"
372
+ end
561
373
  end
374
+ retry_push(actions_to_retry) unless actions_to_retry.empty?
562
375
  end
563
- retry_push(actions_to_retry) unless actions_to_retry.empty?
564
376
  end
565
377
  end
566
378
 
@@ -570,22 +382,37 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
570
382
  def flush(actions, teardown = false)
571
383
  begin
572
384
  submit(actions)
385
+ rescue Manticore::SocketException => e
386
+ # If we can't even connect to the server let's just print out the URL (:hosts is actually a URL)
387
+ # and let the user sort it out from there
388
+ @logger.error(
389
+ "Attempted to send a bulk request to Elasticsearch configured at '#{@client.client_options[:hosts]}',"+
390
+ " but Elasticsearch appears to be unreachable or down!",
391
+ :client_config => @client.client_options,
392
+ :error_message => e.message
393
+ )
394
+ @logger.debug("Failed actions for last bad bulk request!", :actions => actions)
573
395
  rescue => e
574
- @logger.error "Got error to send bulk of actions: #{e.message}"
396
+ # For all other errors print out full connection issues
397
+ @logger.error(
398
+ "Attempted to send a bulk request to Elasticsearch configured at '#{@client.client_options[:hosts]}'," +
399
+ " but an error occurred and it failed! Are you sure you can reach elasticsearch from this machine using " +
400
+ "the configuration provided?",
401
+ :client_config => @client.client_options,
402
+ :error_message => e.message,
403
+ :error_class => e.class.name,
404
+ :backtrace => e.backtrace
405
+ )
406
+
407
+ @logger.debug("Failed actions for last bad bulk request!", :actions => actions)
408
+
575
409
  raise e
576
- ensure
577
- unless @protocol == "node"
578
- @logger.debug? and @logger.debug "Shifting current elasticsearch client"
579
- shift_client
580
- end
581
410
  end
582
411
  end # def flush
583
412
 
584
413
  public
585
414
  def teardown
586
- if @cacert # remove temporary jks store created from the cacert
587
- File.delete(@truststore)
588
- end
415
+ @client.stop_sniffing!
589
416
 
590
417
  @retry_teardown_requested.make_true
591
418
  # First, make sure retry_timer_thread is stopped
@@ -607,36 +434,10 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
607
434
  retry_flush
608
435
  end
609
436
 
610
- protected
611
- def start_local_elasticsearch
612
- @logger.info("Starting embedded Elasticsearch local node.")
613
- builder = org.elasticsearch.node.NodeBuilder.nodeBuilder
614
- # Disable 'local only' - LOGSTASH-277
615
- #builder.local(true)
616
- builder.settings.put("cluster.name", @cluster) if @cluster
617
- builder.settings.put("node.name", @node_name) if @node_name
618
- builder.settings.put("network.host", @bind_host) if @bind_host
619
- builder.settings.put("http.port", @embedded_http_port)
620
-
621
- @embedded_elasticsearch = builder.node
622
- @embedded_elasticsearch.start
623
- end # def start_local_elasticsearch
624
-
625
- protected
626
- def shift_client
627
- @client_idx = (@client_idx+1) % @client.length
628
- @current_client = @client[@client_idx]
629
- @logger.debug? and @logger.debug("Switched current elasticsearch client to ##{@client_idx} at #{@host[@client_idx]}")
630
- end
631
-
632
437
  private
633
438
  def setup_proxy
634
439
  return {} unless @proxy
635
440
 
636
- if @protocol != "http"
637
- raise(LogStash::ConfigurationError, "Proxy is not supported for '#{@protocol}'. Change the protocol to 'http' if you need HTTP proxy.")
638
- end
639
-
640
441
  # Symbolize keys
641
442
  proxy = if @proxy.is_a?(Hash)
642
443
  Hash[@proxy.map {|k,v| [k.to_sym, v]}]
@@ -652,19 +453,19 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
652
453
  private
653
454
  def setup_ssl
654
455
  return {} unless @ssl
655
- if @protocol != "http"
656
- raise(LogStash::ConfigurationError, "SSL is not supported for '#{@protocol}'. Change the protocol to 'http' if you need SSL.")
657
- end
658
- @protocol = "https"
456
+
659
457
  if @cacert && @truststore
660
458
  raise(LogStash::ConfigurationError, "Use either \"cacert\" or \"truststore\" when configuring the CA certificate") if @truststore
661
459
  end
460
+
662
461
  ssl_options = {}
663
- if @cacert then
664
- @truststore, ssl_options[:truststore_password] = generate_jks @cacert
462
+
463
+ if @cacert
464
+ ssl_options[:ca_file] = @cacert
665
465
  elsif @truststore
666
466
  ssl_options[:truststore_password] = @truststore_password.value if @truststore_password
667
467
  end
468
+
668
469
  ssl_options[:truststore] = @truststore if @truststore
669
470
  if @keystore
670
471
  ssl_options[:keystore] = @keystore
@@ -685,37 +486,10 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
685
486
  def setup_basic_auth
686
487
  return {} unless @user && @password
687
488
 
688
- if @protocol =~ /http/
689
- {
690
- :user => ::URI.escape(@user, "@:"),
691
- :password => ::URI.escape(@password.value, "@:")
692
- }
693
- else
694
- raise(LogStash::ConfigurationError, "User and password parameters are not supported for '#{@protocol}'. Change the protocol to 'http' if you need them.")
695
- end
696
- end
697
-
698
- private
699
- def generate_jks cert_path
700
-
701
- require 'securerandom'
702
- require 'tempfile'
703
- require 'java'
704
- import java.io.FileInputStream
705
- import java.io.FileOutputStream
706
- import java.security.KeyStore
707
- import java.security.cert.CertificateFactory
708
-
709
- jks = java.io.File.createTempFile("cert", ".jks")
710
-
711
- ks = KeyStore.getInstance "JKS"
712
- ks.load nil, nil
713
- cf = CertificateFactory.getInstance "X.509"
714
- cert = cf.generateCertificate FileInputStream.new(cert_path)
715
- ks.setCertificateEntry "cacert", cert
716
- pwd = SecureRandom.urlsafe_base64(9)
717
- ks.store FileOutputStream.new(jks), pwd.to_java.toCharArray
718
- [jks.path, pwd]
489
+ {
490
+ :user => ::URI.escape(@user, "@:"),
491
+ :password => ::URI.escape(@password.value, "@:")
492
+ }
719
493
  end
720
494
 
721
495
  private
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-output-elasticsearch'
4
- s.version = '1.1.0'
4
+ s.version = '2.0.0.beta4'
5
5
  s.licenses = ['apache-2.0']
6
6
  s.summary = "Logstash Output to Elasticsearch"
7
7
  s.description = "Output events to elasticsearch"
@@ -29,7 +29,6 @@ Gem::Specification.new do |s|
29
29
  s.add_development_dependency 'ftw', '~> 0.0.42'
30
30
  s.add_development_dependency 'logstash-input-generator'
31
31
 
32
-
33
32
  if RUBY_PLATFORM == 'java'
34
33
  s.platform = RUBY_PLATFORM
35
34
  s.add_runtime_dependency "manticore", '~> 0.4.2'
@@ -37,5 +36,4 @@ Gem::Specification.new do |s|
37
36
 
38
37
  s.add_development_dependency 'logstash-devutils'
39
38
  s.add_development_dependency 'longshoreman'
40
- s.add_development_dependency 'flores'
41
39
  end