logstash-output-elasticsearch_java 2.0.2 → 2.1.1.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile +1 -1
  4. data/lib/logstash/outputs/elasticsearch_java.rb +37 -386
  5. data/lib/logstash/outputs/elasticsearch_java/protocol.rb +201 -228
  6. data/logstash-output-elasticsearch_java.gemspec +2 -1
  7. data/spec/integration/outputs/elasticsearch/node_spec.rb +0 -25
  8. data/spec/integration/outputs/index_spec.rb +2 -4
  9. data/spec/integration/outputs/retry_spec.rb +24 -14
  10. data/spec/integration/outputs/routing_spec.rb +1 -2
  11. data/spec/integration/outputs/secure_spec.rb +4 -4
  12. data/spec/integration/outputs/templates_spec.rb +13 -11
  13. data/spec/integration/outputs/transport_create_spec.rb +5 -6
  14. data/spec/integration/outputs/update_spec.rb +5 -6
  15. data/spec/unit/outputs/elasticsearch/protocol_spec.rb +6 -3
  16. data/spec/unit/outputs/elasticsearch_spec.rb +0 -1
  17. data/vendor/jar-dependencies/runtime-jars/{elasticsearch-2.0.0.jar → elasticsearch-2.1.0.jar} +0 -0
  18. data/vendor/jar-dependencies/runtime-jars/jackson-core-2.6.2.jar +0 -0
  19. data/vendor/jar-dependencies/runtime-jars/jackson-dataformat-cbor-2.6.2.jar +0 -0
  20. data/vendor/jar-dependencies/runtime-jars/jackson-dataformat-smile-2.6.2.jar +0 -0
  21. data/vendor/jar-dependencies/runtime-jars/jackson-dataformat-yaml-2.6.2.jar +0 -0
  22. data/vendor/jar-dependencies/runtime-jars/{lucene-analyzers-common-5.2.1.jar → lucene-analyzers-common-5.3.1.jar} +0 -0
  23. data/vendor/jar-dependencies/runtime-jars/{lucene-backward-codecs-5.2.1.jar → lucene-backward-codecs-5.3.1.jar} +0 -0
  24. data/vendor/jar-dependencies/runtime-jars/{lucene-core-5.2.1.jar → lucene-core-5.3.1.jar} +0 -0
  25. data/vendor/jar-dependencies/runtime-jars/{lucene-expressions-5.2.1.jar → lucene-expressions-5.3.1.jar} +0 -0
  26. data/vendor/jar-dependencies/runtime-jars/{lucene-grouping-5.2.1.jar → lucene-grouping-5.3.1.jar} +0 -0
  27. data/vendor/jar-dependencies/runtime-jars/{lucene-highlighter-5.2.1.jar → lucene-highlighter-5.3.1.jar} +0 -0
  28. data/vendor/jar-dependencies/runtime-jars/lucene-join-5.3.1.jar +0 -0
  29. data/vendor/jar-dependencies/runtime-jars/lucene-memory-5.3.1.jar +0 -0
  30. data/vendor/jar-dependencies/runtime-jars/{lucene-misc-5.2.1.jar → lucene-misc-5.3.1.jar} +0 -0
  31. data/vendor/jar-dependencies/runtime-jars/{lucene-queries-5.2.1.jar → lucene-queries-5.3.1.jar} +0 -0
  32. data/vendor/jar-dependencies/runtime-jars/{lucene-queryparser-5.2.1.jar → lucene-queryparser-5.3.1.jar} +0 -0
  33. data/vendor/jar-dependencies/runtime-jars/lucene-sandbox-5.3.1.jar +0 -0
  34. data/vendor/jar-dependencies/runtime-jars/{lucene-spatial-5.2.1.jar → lucene-spatial-5.3.1.jar} +0 -0
  35. data/vendor/jar-dependencies/runtime-jars/lucene-spatial3d-5.3.1.jar +0 -0
  36. data/vendor/jar-dependencies/runtime-jars/lucene-suggest-5.3.1.jar +0 -0
  37. data/vendor/jar-dependencies/runtime-jars/snakeyaml-1.15.jar +0 -0
  38. data/vendor/jar-dependencies/runtime-jars/spatial4j-0.5.jar +0 -0
  39. metadata +105 -91
  40. data/lib/logstash/outputs/elasticsearch_java/elasticsearch-template.json +0 -93
  41. data/vendor/jar-dependencies/runtime-jars/jackson-core-2.5.3.jar +0 -0
  42. data/vendor/jar-dependencies/runtime-jars/jackson-dataformat-cbor-2.5.3.jar +0 -0
  43. data/vendor/jar-dependencies/runtime-jars/jackson-dataformat-smile-2.5.3.jar +0 -0
  44. data/vendor/jar-dependencies/runtime-jars/jackson-dataformat-yaml-2.5.3.jar +0 -0
  45. data/vendor/jar-dependencies/runtime-jars/lucene-join-5.2.1.jar +0 -0
  46. data/vendor/jar-dependencies/runtime-jars/lucene-memory-5.2.1.jar +0 -0
  47. data/vendor/jar-dependencies/runtime-jars/lucene-sandbox-5.2.1.jar +0 -0
  48. data/vendor/jar-dependencies/runtime-jars/lucene-suggest-5.2.1.jar +0 -0
  49. data/vendor/jar-dependencies/runtime-jars/snakeyaml-1.12.jar +0 -0
  50. data/vendor/jar-dependencies/runtime-jars/spatial4j-0.4.1.jar +0 -0
@@ -3,263 +3,236 @@ require "base64"
3
3
  require 'logstash-output-elasticsearch_java_jars.rb'
4
4
  require 'logstash/outputs/elasticsearch_java'
5
5
 
6
- module LogStash
7
- module Outputs
8
- module ElasticSearchJavaPlugins
9
- module Protocols
10
- class Base
11
- private
12
- def initialize(options={})
13
- # host(s), port, cluster
14
- @logger = Cabin::Channel.get
15
- end
6
+ module LogStash module Outputs module ElasticSearchJavaPlugins module Protocols
7
+ DEFAULT_OPTIONS = {
8
+ :port => 9300,
9
+ }
16
10
 
17
- def template_install(name, template, force=false)
18
- if template_exists?(name) && !force
19
- @logger.debug("Found existing Elasticsearch template. Skipping template management", :name => name)
20
- return
21
- end
22
- template_put(name, template)
23
- end
11
+ class NodeClient
12
+ attr_reader :settings, :client_options
24
13
 
25
- # Do a bulk request with the given actions.
26
- #
27
- # 'actions' is expected to be an array of bulk requests as string json
28
- # values.
29
- #
30
- # Each 'action' becomes a single line in the bulk api call. For more
31
- # details on the format of each.
32
- def bulk(actions)
33
- raise NotImplemented, "You must implement this yourself"
34
- # bulk([
35
- # '{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } }',
36
- # '{ "field1" : "value1" }'
37
- #])
38
- end
14
+ CLIENT_MUTEX = Mutex.new
39
15
 
40
- public(:initialize, :template_install)
41
- end
16
+ def initialize(options={})
17
+ @logger = Cabin::Channel.get
18
+ @client_options = DEFAULT_OPTIONS.merge(options)
19
+ create_settings
20
+ end
21
+
22
+ def client_mutex_synchronize
23
+ CLIENT_MUTEX.synchronize { yield }
24
+ end
42
25
 
43
- class NodeClient < Base
44
- CLIENT_MUTEX = Mutex.new
26
+ def client
27
+ client_mutex_synchronize { @@client ||= make_client }
28
+ end
45
29
 
46
- def self.get_client(settings)
47
- CLIENT_MUTEX.synchronize {
48
- if @client
49
- @client
50
- else
51
- nodebuilder = org.elasticsearch.node.NodeBuilder.nodeBuilder
52
- @client = nodebuilder.settings(settings.build).node().client()
53
- end
54
- }
55
- end
30
+ # For use in test helpers
31
+ def self.clear_node_client
32
+ client_mutex_synchronize { @@client = nil }
33
+ end
56
34
 
57
- def self.clear_client()
58
- CLIENT_MUTEX.synchronize {
59
- @client = null
60
- }
61
- end
35
+ def create_settings
36
+ @settings = org.elasticsearch.common.settings.Settings.settingsBuilder()
37
+ if @client_options[:hosts]
38
+ @settings.put("discovery.zen.ping.multicast.enabled", false)
39
+ @settings.put("discovery.zen.ping.unicast.hosts", hosts(@client_options))
40
+ end
62
41
 
63
- private
42
+ @settings.put("node.client", true)
43
+ @settings.put("http.enabled", false)
44
+ @settings.put("path.home", Dir.pwd)
64
45
 
65
- DEFAULT_OPTIONS = {
66
- :port => 9300,
67
- }
46
+ if @client_options[:client_settings]
47
+ @client_options[:client_settings].each do |key, value|
48
+ @settings.put(key, value)
49
+ end
50
+ end
68
51
 
69
- def initialize(options={})
70
- super
71
- require "java"
72
- @options = DEFAULT_OPTIONS.merge(options)
73
- setup(@options)
74
- end # def initialize
52
+ @settings
53
+ end
75
54
 
76
- def settings
77
- return @settings
55
+ def hosts(options)
56
+ # http://www.elasticsearch.org/guide/reference/modules/discovery/zen/
57
+ result = Array.new
58
+ if options[:hosts].class == Array
59
+ options[:hosts].each do |host|
60
+ if host.to_s =~ /^.+:.+$/
61
+ # For host in format: host:port, ignore options[:port]
62
+ result << host
63
+ else
64
+ if options[:port].to_s =~ /^\d+-\d+$/
65
+ # port ranges are 'host[port1-port2]'b
66
+ result << Range.new(*options[:port].split("-")).collect { |p| "#{host}:#{p}" }
67
+ else
68
+ result << "#{host}:#{options[:port]}"
69
+ end
78
70
  end
79
-
80
- def client
81
- self.class.get_client(settings)
71
+ end
72
+ else
73
+ if options[:hosts].to_s =~ /^.+:.+$/
74
+ # For host in format: host:port, ignore options[:port]
75
+ result << options[:hosts]
76
+ else
77
+ if options[:port].to_s =~ /^\d+-\d+$/
78
+ # port ranges are 'host[port1-port2]' according to
79
+ # http://www.elasticsearch.org/guide/reference/modules/discovery/zen/
80
+ # However, it seems to only query the first port.
81
+ # So generate our own list of unicast hosts to scan.
82
+ range = Range.new(*options[:port].split("-"))
83
+ result << range.collect { |p| "#{options[:hosts]}:#{p}" }
84
+ else
85
+ result << "#{options[:hosts]}:#{options[:port]}"
82
86
  end
87
+ end
88
+ end
89
+ result.flatten.join(",")
90
+ end
83
91
 
84
- def setup(options={})
85
- @settings = org.elasticsearch.common.settings.Settings.settingsBuilder()
86
- if options[:hosts]
87
- @settings.put("discovery.zen.ping.multicast.enabled", false)
88
- @settings.put("discovery.zen.ping.unicast.hosts", NodeClient.hosts(options))
89
- end
92
+ # Normalizes the Java response to a reasonable approximation of the HTTP datastructure for interop
93
+ # with the HTTP code
94
+ def normalize_bulk_response(bulk_response)
95
+ # TODO(talevy): parse item response objects to retrieve correct 200 (OK) or 201(created) status codes + items = bulk_response.map {|i|
96
+ items = bulk_response.map { |i|
97
+ if i.is_failed
98
+ [[i.get_op_type, {"status" => i.get_failure.get_status.get_status, "message" => i.failureMessage}]]
99
+ else
100
+ [[i.get_op_type, {"status" => 200, "message" => "OK"}]]
101
+ end
102
+ }
103
+ if bulk_response.has_failures()
104
+ {"errors" => true, "items" => items}
105
+ else
106
+ {"errors" => false}
107
+ end
108
+ end
90
109
 
91
- @settings.put("node.client", true)
92
- @settings.put("http.enabled", false)
93
- @settings.put("path.home", Dir.pwd)
110
+ def make_client
111
+ nodebuilder = org.elasticsearch.node.NodeBuilder.nodeBuilder
112
+ nodebuilder.settings(settings.build).node().client()
113
+ end
94
114
 
95
- if options[:client_settings]
96
- options[:client_settings].each do |key, value|
97
- @settings.put(key, value)
98
- end
99
- end
115
+ def bulk(actions)
116
+ # Actions an array of [ action, action_metadata, source ]
117
+ prep = client.prepareBulk
118
+ actions.each do |action, args, source|
119
+ prep.add(build_request(action, args, source))
120
+ end
121
+ response = prep.execute.actionGet()
100
122
 
101
- return @settings
102
- end
123
+ self.normalize_bulk_response(response)
124
+ end
103
125
 
104
- def self.hosts(options)
105
- # http://www.elasticsearch.org/guide/reference/modules/discovery/zen/
106
- result = Array.new
107
- if options[:hosts].class == Array
108
- options[:hosts].each do |host|
109
- if host.to_s =~ /^.+:.+$/
110
- # For host in format: host:port, ignore options[:port]
111
- result << host
112
- else
113
- if options[:port].to_s =~ /^\d+-\d+$/
114
- # port ranges are 'host[port1-port2]'
115
- result << Range.new(*options[:port].split("-")).collect { |p| "#{host}:#{p}" }
116
- else
117
- result << "#{host}:#{options[:port]}"
118
- end
119
- end
120
- end
121
- else
122
- if options[:hosts].to_s =~ /^.+:.+$/
123
- # For host in format: host:port, ignore options[:port]
124
- result << options[:hosts]
125
- else
126
- if options[:port].to_s =~ /^\d+-\d+$/
127
- # port ranges are 'host[port1-port2]' according to
128
- # http://www.elasticsearch.org/guide/reference/modules/discovery/zen/
129
- # However, it seems to only query the first port.
130
- # So generate our own list of unicast hosts to scan.
131
- range = Range.new(*options[:port].split("-"))
132
- result << range.collect { |p| "#{options[:hosts]}:#{p}" }
133
- else
134
- result << "#{options[:hosts]}:#{options[:port]}"
135
- end
136
- end
137
- end
138
- result.flatten.join(",")
126
+ # def bulk
127
+
128
+ def build_request(action, args, source)
129
+ case action
130
+ when "index"
131
+ request = org.elasticsearch.action.index.IndexRequest.new(args[:_index])
132
+ request.id(args[:_id]) if args[:_id]
133
+ request.routing(args[:_routing]) if args[:_routing]
134
+ request.source(source)
135
+ when "delete"
136
+ request = org.elasticsearch.action.delete.DeleteRequest.new(args[:_index])
137
+ request.id(args[:_id])
138
+ request.routing(args[:_routing]) if args[:_routing]
139
+ when "create"
140
+ request = org.elasticsearch.action.index.IndexRequest.new(args[:_index])
141
+ request.id(args[:_id]) if args[:_id]
142
+ request.routing(args[:_routing]) if args[:_routing]
143
+ request.source(source)
144
+ request.opType("create")
145
+ when "create_unless_exists"
146
+ unless args[:_id].nil?
147
+ request = org.elasticsearch.action.index.IndexRequest.new(args[:_index])
148
+ request.id(args[:_id])
149
+ request.routing(args[:_routing]) if args[:_routing]
150
+ request.source(source)
151
+ request.opType("create")
152
+ else
153
+ raise(LogStash::ConfigurationError, "Specifying action => 'create_unless_exists' without a document '_id' is not supported.")
139
154
  end
140
-
141
- def self.normalize_bulk_response(bulk_response)
142
- # TODO(talevy): parse item response objects to retrieve correct 200 (OK) or 201(created) status codes
143
- if bulk_response.has_failures()
144
- {"errors" => true,
145
- "statuses" => bulk_response.map { |i| (i.is_failed && i.get_failure.get_status.get_status) || 200 }}
155
+ when "update"
156
+ unless args[:_id].nil?
157
+ request = org.elasticsearch.action.update.UpdateRequest.new(args[:_index], args[:_type], args[:_id])
158
+ request.routing(args[:_routing]) if args[:_routing]
159
+ request.doc(source)
160
+ if @client_options[:doc_as_upsert]
161
+ request.docAsUpsert(true)
146
162
  else
147
- {"errors" => false}
163
+ request.upsert(args[:_upsert]) if args[:_upsert]
148
164
  end
165
+ else
166
+ raise(LogStash::ConfigurationError, "Specifying action => 'update' without a document '_id' is not supported.")
149
167
  end
168
+ else
169
+ raise(LogStash::ConfigurationError, "action => '#{action_name}' is not currently supported.")
170
+ end # case action
150
171
 
151
- def bulk(actions)
152
- # Actions an array of [ action, action_metadata, source ]
153
- prep = client.prepareBulk
154
- actions.each do |action, args, source|
155
- prep.add(build_request(action, args, source))
156
- end
157
- response = prep.execute.actionGet()
158
-
159
- self.class.normalize_bulk_response(response)
160
- end # def bulk
161
-
162
- def build_request(action, args, source)
163
- case action
164
- when "index"
165
- request = org.elasticsearch.action.index.IndexRequest.new(args[:_index])
166
- request.id(args[:_id]) if args[:_id]
167
- request.routing(args[:_routing]) if args[:_routing]
168
- request.source(source)
169
- when "delete"
170
- request = org.elasticsearch.action.delete.DeleteRequest.new(args[:_index])
171
- request.id(args[:_id])
172
- request.routing(args[:_routing]) if args[:_routing]
173
- when "create"
174
- request = org.elasticsearch.action.index.IndexRequest.new(args[:_index])
175
- request.id(args[:_id]) if args[:_id]
176
- request.routing(args[:_routing]) if args[:_routing]
177
- request.source(source)
178
- request.opType("create")
179
- when "create_unless_exists"
180
- unless args[:_id].nil?
181
- request = org.elasticsearch.action.index.IndexRequest.new(args[:_index])
182
- request.id(args[:_id])
183
- request.routing(args[:_routing]) if args[:_routing]
184
- request.source(source)
185
- request.opType("create")
186
- else
187
- raise(LogStash::ConfigurationError, "Specifying action => 'create_unless_exists' without a document '_id' is not supported.")
188
- end
189
- when "update"
190
- unless args[:_id].nil?
191
- request = org.elasticsearch.action.update.UpdateRequest.new(args[:_index], args[:_type], args[:_id])
192
- request.routing(args[:_routing]) if args[:_routing]
193
- request.doc(source)
194
- if @options[:doc_as_upsert]
195
- request.docAsUpsert(true)
196
- else
197
- request.upsert(args[:_upsert]) if args[:_upsert]
198
- end
199
- else
200
- raise(LogStash::ConfigurationError, "Specifying action => 'update' without a document '_id' is not supported.")
201
- end
202
- else
203
- raise(LogStash::ConfigurationError, "action => '#{action_name}' is not currently supported.")
204
- end # case action
205
-
206
- request.type(args[:_type]) if args[:_type]
207
- return request
208
- end # def build_request
209
-
210
- def template_exists?(name)
211
- return !client.admin.indices.
212
- prepareGetTemplates(name).
213
- execute().
214
- actionGet().
215
- getIndexTemplates().
216
- isEmpty
217
- end # def template_exists?
218
-
219
- def template_put(name, template)
220
- response = client.admin.indices.
221
- preparePutTemplate(name).
222
- setSource(LogStash::Json.dump(template)).
223
- execute().
224
- actionGet()
172
+ request.type(args[:_type]) if args[:_type]
173
+ return request
174
+ end
225
175
 
226
- raise "Could not index template!" unless response.isAcknowledged
227
- end # template_put
176
+ # def build_request
228
177
 
229
- public(:initialize, :bulk)
230
- end # class NodeClient
178
+ def template_exists?(name)
179
+ return !client.admin.indices.
180
+ prepareGetTemplates(name).
181
+ execute().
182
+ actionGet().
183
+ getIndexTemplates().
184
+ isEmpty
185
+ end
231
186
 
232
- class TransportClient < NodeClient
233
- def client
234
- return @client if @client
235
- @client = build_client(@options)
236
- return @client
237
- end
187
+ def template_install(name, template, force=false)
188
+ if template_exists?(name) && !force
189
+ @logger.debug("Found existing Elasticsearch template. Skipping template management", :name => name)
190
+ return
191
+ end
192
+ template_put(name, template)
193
+ end
238
194
 
195
+ def template_put(name, template)
196
+ response = client.admin.indices.
197
+ preparePutTemplate(name).
198
+ setSource(LogStash::Json.dump(template)).
199
+ execute().
200
+ actionGet()
239
201
 
240
- private
241
- def build_client(options)
242
- client = org.elasticsearch.client.transport.TransportClient.
243
- builder().
244
- settings((settings.build)).
245
- build()
202
+ raise "Could not index template!" unless response.isAcknowledged
203
+ end
204
+ end # class NodeClient
205
+
206
+ class TransportClient < NodeClient
207
+ private
208
+ def make_client
209
+ client = org.elasticsearch.client.transport.TransportClient.
210
+ builder().
211
+ settings((settings.build)).
212
+ build()
213
+
214
+ client_options[:hosts].each do |host|
215
+ matches = host.match /([^:+]+)(:(\d+))?/
216
+
217
+ inet_addr = java.net.InetAddress.getByName(matches[1])
218
+ port = (matches[3] || 9300).to_i
219
+ client.addTransportAddress(
220
+ org.elasticsearch.common.transport.InetSocketTransportAddress.new(
221
+ inet_addr, port
222
+ )
223
+ )
224
+ end
246
225
 
247
- options[:hosts].each do |host|
248
- matches = host.match /(.+)(?:.*)/
226
+ return client
227
+ end
249
228
 
250
- inet_addr = java.net.InetAddress.getByName(matches[1])
251
- port = (matches[2] || options[:port]).to_i
252
- client.addTransportAddress(
253
- org.elasticsearch.common.transport.InetSocketTransportAddress.new(
254
- inet_addr, port
255
- )
256
- )
257
- end
229
+ # We want a separate client per instance for transport
230
+ def client
231
+ client_mutex_synchronize { @client ||= make_client }
232
+ end
258
233
 
259
- return client
260
- end
261
- end
262
- end
234
+ def clear_client()
235
+ client_mutex_synchronize { @client = nil }
263
236
  end
264
237
  end
265
- end
238
+ end end end end