logstash-output-elasticsearch_java 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/CHANGELOG.md +2 -0
  4. data/CONTRIBUTORS +31 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +13 -0
  7. data/NOTICE.TXT +5 -0
  8. data/README.md +98 -0
  9. data/Rakefile +1 -0
  10. data/lib/logstash/outputs/elasticsearch_java/elasticsearch-template.json +41 -0
  11. data/lib/logstash/outputs/elasticsearch_java/protocol.rb +258 -0
  12. data/lib/logstash/outputs/elasticsearch_java.rb +545 -0
  13. data/lib/logstash-output-elasticsearch_java_jars.rb +5 -0
  14. data/logstash-output-elasticsearch_java.gemspec +32 -0
  15. data/spec/es_spec_helper.rb +81 -0
  16. data/spec/integration/outputs/elasticsearch/node_spec.rb +36 -0
  17. data/spec/integration/outputs/index_spec.rb +90 -0
  18. data/spec/integration/outputs/retry_spec.rb +148 -0
  19. data/spec/integration/outputs/routing_spec.rb +60 -0
  20. data/spec/integration/outputs/secure_spec.rb +113 -0
  21. data/spec/integration/outputs/templates_spec.rb +97 -0
  22. data/spec/integration/outputs/transport_create_spec.rb +94 -0
  23. data/spec/integration/outputs/update_spec.rb +88 -0
  24. data/spec/unit/outputs/elasticsearch/protocol_spec.rb +32 -0
  25. data/spec/unit/outputs/elasticsearch_spec.rb +79 -0
  26. data/vendor/jar-dependencies/runtime-jars/antlr-runtime-3.5.jar +0 -0
  27. data/vendor/jar-dependencies/runtime-jars/asm-4.1.jar +0 -0
  28. data/vendor/jar-dependencies/runtime-jars/asm-commons-4.1.jar +0 -0
  29. data/vendor/jar-dependencies/runtime-jars/elasticsearch-1.7.0.jar +0 -0
  30. data/vendor/jar-dependencies/runtime-jars/lucene-analyzers-common-4.10.4.jar +0 -0
  31. data/vendor/jar-dependencies/runtime-jars/lucene-core-4.10.4.jar +0 -0
  32. data/vendor/jar-dependencies/runtime-jars/lucene-grouping-4.10.4.jar +0 -0
  33. data/vendor/jar-dependencies/runtime-jars/lucene-highlighter-4.10.4.jar +0 -0
  34. data/vendor/jar-dependencies/runtime-jars/lucene-join-4.10.4.jar +0 -0
  35. data/vendor/jar-dependencies/runtime-jars/lucene-memory-4.10.4.jar +0 -0
  36. data/vendor/jar-dependencies/runtime-jars/lucene-misc-4.10.4.jar +0 -0
  37. data/vendor/jar-dependencies/runtime-jars/lucene-queries-4.10.4.jar +0 -0
  38. data/vendor/jar-dependencies/runtime-jars/lucene-queryparser-4.10.4.jar +0 -0
  39. data/vendor/jar-dependencies/runtime-jars/lucene-sandbox-4.10.4.jar +0 -0
  40. data/vendor/jar-dependencies/runtime-jars/lucene-spatial-4.10.4.jar +0 -0
  41. data/vendor/jar-dependencies/runtime-jars/lucene-suggest-4.10.4.jar +0 -0
  42. data/vendor/jar-dependencies/runtime-jars/spatial4j-0.4.1.jar +0 -0
  43. metadata +241 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3f3598838ddd3f3b31bb2fd185b947913d8abf21
4
+ data.tar.gz: b360525c05bd16bff468a8c0d93257e966926d36
5
+ SHA512:
6
+ metadata.gz: dc56371b39b232bb78bc6369fc98e7976b9ec4f91a64ae5876b3207d58e29c941dd5e896693f801cfe30be5dfc136d105c8be26b410118f7b57eee0525c0d5f1
7
+ data.tar.gz: 24e90919491c6d754cc9c08f6d1d90bd178a5883d1692c516a0bcba2e276ccea1e61221f6871ce1847ec58dca23daa295498ceae08717512433085822a77831a
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ Gemfile.lock
3
+ .bundle
4
+ .idea
5
+ *~
data/CHANGELOG.md ADDED
@@ -0,0 +1,2 @@
1
+ ## 1.0.0
2
+ - Initial Release.
data/CONTRIBUTORS ADDED
@@ -0,0 +1,31 @@
1
+ The following is a list of people who have contributed ideas, code, bug
2
+ reports, or in general have helped logstash along its way.
3
+
4
+ Contributors:
5
+ * Aaron Mildenstein (untergeek)
6
+ * Bob Corsaro (dokipen)
7
+ * Colin Surprenant (colinsurprenant)
8
+ * Dmitry Koprov (dkoprov)
9
+ * Graham Bleach (bleach)
10
+ * Hao Chen (haoch)
11
+ * James Turnbull (jamtur01)
12
+ * John E. Vincent (lusis)
13
+ * Jordan Sissel (jordansissel)
14
+ * João Duarte (jsvd)
15
+ * Kurt Hurtado (kurtado)
16
+ * Miah Johnson (miah)
17
+ * Pere Urbón (purbon)
18
+ * Pete Fritchman (fetep)
19
+ * Pier-Hugues Pellerin (ph)
20
+ * Raymond Feng (raymondfeng)
21
+ * Richard Pijnenburg (electrical)
22
+ * Spenser Jones (SpenserJ)
23
+ * Suyog Rao (suyograo)
24
+ * Tal Levy (talevy)
25
+ * Tom Hodder (tolland)
26
+ * jimmyjones2
27
+
28
+ Note: If you've sent us patches, bug reports, or otherwise contributed to
29
+ Logstash, and you aren't on the list above and want to be, please let us know
30
+ and we'll make sure you're here. Contributions from folks like you are what make
31
+ open source awesome.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012–2015 Elasticsearch <http://www.elastic.co>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/NOTICE.TXT ADDED
@@ -0,0 +1,5 @@
1
+ Elasticsearch
2
+ Copyright 2012-2015 Elasticsearch
3
+
4
+ This product includes software developed by The Apache Software
5
+ Foundation (http://www.apache.org/).
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Logstash Plugin
2
+
3
+ This is a plugin for [Logstash](https://github.com/elastic/logstash).
4
+
5
+ It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
6
+
7
+ ## Documentation
8
+
9
+ Logstash provides infrastructure to automatically generate documentation for this plugin. We use the asciidoc format to write documentation so any comments in the source code will be first converted into asciidoc and then into html. All plugin documentation are placed under one [central location](http://www.elastic.co/guide/en/logstash/current/).
10
+
11
+ - For formatting code or config example, you can use the asciidoc `[source,ruby]` directive
12
+ - For more asciidoc formatting tips, see the excellent reference here https://github.com/elastic/docs#asciidoc-guide
13
+
14
+ ## Need Help?
15
+
16
+ Need help? Try #logstash on freenode IRC or the https://discuss.elastic.co/c/logstash discussion forum.
17
+
18
+ ## Developing
19
+
20
+ ### 1. Plugin Developement and Testing
21
+
22
+ #### Code
23
+ - To get started, you'll need JRuby with the Bundler gem installed.
24
+
25
+ - Create a new plugin or clone and existing from the GitHub [logstash-plugins](https://github.com/logstash-plugins) organization. We also provide [example plugins](https://github.com/logstash-plugins?query=example).
26
+
27
+ - Install dependencies
28
+ ```sh
29
+ bundle install
30
+ ```
31
+
32
+ #### Test
33
+
34
+ - Update your dependencies
35
+
36
+ ```sh
37
+ bundle install
38
+ ```
39
+
40
+ - Run unit tests
41
+
42
+ ```sh
43
+ bundle exec rspec
44
+ ```
45
+
46
+ - Run integration tests
47
+
48
+ Dependencies: [Docker](http://docker.com)
49
+
50
+ Before the test suite is run, we will load and run an
51
+ Elasticsearch instance within a docker container. This container
52
+ will be cleaned up when suite has finished.
53
+
54
+ ```sh
55
+ bundle exec rspec --tag integration
56
+ ```
57
+
58
+ ### 2. Running your unpublished Plugin in Logstash
59
+
60
+ #### 2.1 Run in a local Logstash clone
61
+
62
+ - Edit Logstash `Gemfile` and add the local plugin path, for example:
63
+ ```ruby
64
+ gem "logstash-filter-awesome", :path => "/your/local/logstash-filter-awesome"
65
+ ```
66
+ - Install plugin
67
+ ```sh
68
+ bin/plugin install --no-verify
69
+ ```
70
+ - Run Logstash with your plugin
71
+ ```sh
72
+ bin/logstash -e 'filter {awesome {}}'
73
+ ```
74
+ At this point any modifications to the plugin code will be applied to this local Logstash setup. After modifying the plugin, simply rerun Logstash.
75
+
76
+ #### 2.2 Run in an installed Logstash
77
+
78
+ You can use the same **2.1** method to run your plugin in an installed Logstash by editing its `Gemfile` and pointing the `:path` to your local plugin development directory or you can build the gem and install it using:
79
+
80
+ - Build your plugin gem
81
+ ```sh
82
+ gem build logstash-filter-awesome.gemspec
83
+ ```
84
+ - Install the plugin from the Logstash home
85
+ ```sh
86
+ bin/plugin install /your/local/plugin/logstash-filter-awesome.gem
87
+ ```
88
+ - Start Logstash and proceed to test the plugin
89
+
90
+ ## Contributing
91
+
92
+ All contributions are welcome: ideas, patches, documentation, bug reports, complaints, and even something you drew up on a napkin.
93
+
94
+ Programming is not a required skill. Whatever you've seen about open source and maintainers or community members saying "send patches or die" - you will not see that here.
95
+
96
+ It is more important to the community that you are able to contribute.
97
+
98
+ For more information about contributing, see the [CONTRIBUTING](https://github.com/elastic/logstash/blob/master/CONTRIBUTING.md) file.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "logstash/devutils/rake"
@@ -0,0 +1,41 @@
1
+ {
2
+ "template" : "logstash-*",
3
+ "settings" : {
4
+ "index.refresh_interval" : "5s"
5
+ },
6
+ "mappings" : {
7
+ "_default_" : {
8
+ "_all" : {"enabled" : true, "omit_norms" : true},
9
+ "dynamic_templates" : [ {
10
+ "message_field" : {
11
+ "match" : "message",
12
+ "match_mapping_type" : "string",
13
+ "mapping" : {
14
+ "type" : "string", "index" : "analyzed", "omit_norms" : true
15
+ }
16
+ }
17
+ }, {
18
+ "string_fields" : {
19
+ "match" : "*",
20
+ "match_mapping_type" : "string",
21
+ "mapping" : {
22
+ "type" : "string", "index" : "analyzed", "omit_norms" : true,
23
+ "fields" : {
24
+ "raw" : {"type": "string", "index" : "not_analyzed", "ignore_above" : 256}
25
+ }
26
+ }
27
+ }
28
+ } ],
29
+ "properties" : {
30
+ "@version": { "type": "string", "index": "not_analyzed" },
31
+ "geoip" : {
32
+ "type" : "object",
33
+ "dynamic": true,
34
+ "properties" : {
35
+ "location" : { "type" : "geo_point" }
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,258 @@
1
+ require "cabin"
2
+ require "base64"
3
+ require 'logstash-output-elasticsearch_java_jars.rb'
4
+ require 'logstash/outputs/elasticsearch_java'
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
16
+
17
+ def client
18
+ return @client if @client
19
+ @client = build_client(@options)
20
+ return @client
21
+ end
22
+
23
+ def template_install(name, template, force=false)
24
+ if template_exists?(name) && !force
25
+ @logger.debug("Found existing Elasticsearch template. Skipping template management", :name => name)
26
+ return
27
+ end
28
+ template_put(name, template)
29
+ end
30
+
31
+ # Do a bulk request with the given actions.
32
+ #
33
+ # 'actions' is expected to be an array of bulk requests as string json
34
+ # values.
35
+ #
36
+ # Each 'action' becomes a single line in the bulk api call. For more
37
+ # details on the format of each.
38
+ def bulk(actions)
39
+ raise NotImplemented, "You must implement this yourself"
40
+ # bulk([
41
+ # '{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } }',
42
+ # '{ "field1" : "value1" }'
43
+ #])
44
+ end
45
+
46
+ public(:initialize, :template_install)
47
+ end
48
+
49
+ class NodeClient < Base
50
+ CLIENT_MUTEX = Mutex.new
51
+
52
+ def self.get_client(settings)
53
+ CLIENT_MUTEX.synchronize {
54
+ if @client
55
+ @client
56
+ else
57
+ nodebuilder = org.elasticsearch.node.NodeBuilder.nodeBuilder
58
+ @client = nodebuilder.settings(settings.build).node().client()
59
+ end
60
+ }
61
+ end
62
+
63
+ def self.clear_client()
64
+ CLIENT_MUTEX.synchronize {
65
+ @client = nil
66
+ }
67
+ end
68
+
69
+ private
70
+
71
+ DEFAULT_OPTIONS = {
72
+ :port => 9300,
73
+ }
74
+
75
+ def initialize(options={})
76
+ super
77
+ require "java"
78
+ @options = DEFAULT_OPTIONS.merge(options)
79
+ setup(@options)
80
+ end # def initialize
81
+
82
+ def settings
83
+ return @settings
84
+ end
85
+
86
+ def client
87
+ self.class.get_client(settings)
88
+ end
89
+
90
+ def setup(options={})
91
+ @settings = org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder
92
+ if options[:hosts]
93
+ @settings.put("discovery.zen.ping.multicast.enabled", false)
94
+ @settings.put("discovery.zen.ping.unicast.hosts", NodeClient.hosts(options))
95
+ end
96
+
97
+ @settings.put("node.client", true)
98
+ @settings.put("http.enabled", false)
99
+
100
+ if options[:client_settings]
101
+ options[:client_settings].each do |key, value|
102
+ @settings.put(key, value)
103
+ end
104
+ end
105
+
106
+ return @settings
107
+ end
108
+
109
+ def self.hosts(options)
110
+ # http://www.elasticsearch.org/guide/reference/modules/discovery/zen/
111
+ result = Array.new
112
+ if options[:hosts].class == Array
113
+ options[:hosts].each do |host|
114
+ if host.to_s =~ /^.+:.+$/
115
+ # For host in format: host:port, ignore options[:port]
116
+ result << host
117
+ else
118
+ if options[:port].to_s =~ /^\d+-\d+$/
119
+ # port ranges are 'host[port1-port2]'
120
+ result << Range.new(*options[:port].split("-")).collect { |p| "#{host}:#{p}" }
121
+ else
122
+ result << "#{host}:#{options[:port]}"
123
+ end
124
+ end
125
+ end
126
+ else
127
+ if options[:hosts].to_s =~ /^.+:.+$/
128
+ # For host in format: host:port, ignore options[:port]
129
+ result << options[:hosts]
130
+ else
131
+ if options[:port].to_s =~ /^\d+-\d+$/
132
+ # port ranges are 'host[port1-port2]' according to
133
+ # http://www.elasticsearch.org/guide/reference/modules/discovery/zen/
134
+ # However, it seems to only query the first port.
135
+ # So generate our own list of unicast hosts to scan.
136
+ range = Range.new(*options[:port].split("-"))
137
+ result << range.collect { |p| "#{options[:hosts]}:#{p}" }
138
+ else
139
+ result << "#{options[:hosts]}:#{options[:port]}"
140
+ end
141
+ end
142
+ end
143
+ result.flatten.join(",")
144
+ end
145
+
146
+ def self.normalize_bulk_response(bulk_response)
147
+ # TODO(talevy): parse item response objects to retrieve correct 200 (OK) or 201(created) status codes
148
+ if bulk_response.has_failures()
149
+ {"errors" => true,
150
+ "statuses" => bulk_response.map { |i| (i.is_failed && i.get_failure.get_status.get_status) || 200 }}
151
+ else
152
+ {"errors" => false}
153
+ end
154
+ end
155
+
156
+ def bulk(actions)
157
+ # Actions an array of [ action, action_metadata, source ]
158
+ prep = client.prepareBulk
159
+ actions.each do |action, args, source|
160
+ prep.add(build_request(action, args, source))
161
+ end
162
+ response = prep.execute.actionGet()
163
+
164
+ self.class.normalize_bulk_response(response)
165
+ end # def bulk
166
+
167
+ def build_request(action, args, source)
168
+ case action
169
+ when "index"
170
+ request = org.elasticsearch.action.index.IndexRequest.new(args[:_index])
171
+ request.id(args[:_id]) if args[:_id]
172
+ request.routing(args[:_routing]) if args[:_routing]
173
+ request.source(source)
174
+ when "delete"
175
+ request = org.elasticsearch.action.delete.DeleteRequest.new(args[:_index])
176
+ request.id(args[:_id])
177
+ request.routing(args[:_routing]) if args[:_routing]
178
+ when "create"
179
+ request = org.elasticsearch.action.index.IndexRequest.new(args[:_index])
180
+ request.id(args[:_id]) if args[:_id]
181
+ request.routing(args[:_routing]) if args[:_routing]
182
+ request.source(source)
183
+ request.opType("create")
184
+ when "create_unless_exists"
185
+ unless args[:_id].nil?
186
+ request = org.elasticsearch.action.index.IndexRequest.new(args[:_index])
187
+ request.id(args[:_id])
188
+ request.routing(args[:_routing]) if args[:_routing]
189
+ request.source(source)
190
+ request.opType("create")
191
+ else
192
+ raise(LogStash::ConfigurationError, "Specifying action => 'create_unless_exists' without a document '_id' is not supported.")
193
+ end
194
+ when "update"
195
+ unless args[:_id].nil?
196
+ request = org.elasticsearch.action.update.UpdateRequest.new(args[:_index], args[:_type], args[:_id])
197
+ request.routing(args[:_routing]) if args[:_routing]
198
+ request.doc(source)
199
+ if @options[:doc_as_upsert]
200
+ request.docAsUpsert(true)
201
+ else
202
+ request.upsert(args[:_upsert]) if args[:_upsert]
203
+ end
204
+ else
205
+ raise(LogStash::ConfigurationError, "Specifying action => 'update' without a document '_id' is not supported.")
206
+ end
207
+ else
208
+ raise(LogStash::ConfigurationError, "action => '#{action_name}' is not currently supported.")
209
+ end # case action
210
+
211
+ request.type(args[:_type]) if args[:_type]
212
+ return request
213
+ end # def build_request
214
+
215
+ def template_exists?(name)
216
+ request = org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequestBuilder.new(client.admin.indices, name)
217
+ response = request.get
218
+ return !response.getIndexTemplates.isEmpty
219
+ end
220
+
221
+ def template_put(name, template)
222
+ request = org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequestBuilder.new(client.admin.indices, name)
223
+ request.setSource(LogStash::Json.dump(template))
224
+
225
+ # execute the request and get the response, if it fails, we'll get an exception.
226
+ request.get
227
+ end
228
+
229
+ public(:initialize, :bulk)
230
+ end # class NodeClient
231
+
232
+ class TransportClient < NodeClient
233
+ private
234
+ def build_client(options)
235
+ client = org.elasticsearch.client.transport.TransportClient.
236
+ builder().
237
+ settings((settings.build)).
238
+ build()
239
+
240
+ options[:hosts].each do |host|
241
+ matches = host.match /(.+)(?:.*)/
242
+
243
+ inet_addr = java.net.InetAddress.getByName(matches[1])
244
+ port = (matches[2] || options[:port]).to_i
245
+ client.addTransportAddress(
246
+ org.elasticsearch.common.transport.InetSocketTransportAddress.new(
247
+ inet_addr, port
248
+ )
249
+ )
250
+ end
251
+
252
+ return client
253
+ end
254
+ end
255
+ end
256
+ end
257
+ end
258
+ end