logstash-output-jut 0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a9eb2e11117af72725830240a0c80dd9ac967620
4
+ data.tar.gz: e0302a18404130b4c21ced3836e7bb91c8d8c03f
5
+ SHA512:
6
+ metadata.gz: d9a292c278f0430a56e0f0f1aa10a4605a357bbe2ef2f24672095bd25213edb94a9d85144c0534fd3a3b192542d52ca218a442b5f592238e17db20602e23345f
7
+ data.tar.gz: d389e4ddb0ca8af5da51525ffbe9e680996130a685eea176dd8f629a4ee716f1c01b423bcacddcf9a7d16d86ee4dab21ad9de58ab6d3862209ad92f6f9925786
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .DS_Store
2
+ *.gem
3
+ Gemfile.lock
4
+ Gemfile.bak
5
+ .bundle
6
+ vendor
data/CONTRIBUTORS ADDED
@@ -0,0 +1,11 @@
1
+ The following is a list of people who have contributed ideas, code, bug
2
+ reports, or in general have helped this plugin along its way.
3
+
4
+ Contributors:
5
+ * Stephan Liu (stephan-x-liu)
6
+ * Jut, Inc.
7
+
8
+ Note: If you've sent us patches, bug reports, or otherwise contributed to
9
+ Logstash, and you aren't on the list above and want to be, please let us know
10
+ and we'll make sure you're here. Contributions from folks like you are what make
11
+ open source awesome.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+ gem "logstash", :github => "elasticsearch/logstash", :branch => "1.5"
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2015 Jut, Inc. <www.jut.io>
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/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # Batch HTTP Plugin
2
+
3
+ This is a plugin for [Logstash](https://github.com/elasticsearch/logstash).
4
+
5
+ ## Documentation
6
+
7
+ This plugin sends events to a [Jut](https://jut.io) data engine.
8
+ Events are formatted to be suitable for
9
+ [direct import via http](http://docs.jut.io/user-guide/#data_ingest_http)
10
+ and are grouped into batches to reduce the total number of http
11
+ transactions required to import many records.
12
+
13
+ ## Developing
14
+
15
+ ### 1. Plugin Developement and Testing
16
+
17
+ #### Code
18
+ - To get started, you'll need JRuby with the Bundler gem installed.
19
+
20
+ - Install dependencies
21
+ ```sh
22
+ bundle install
23
+ ```
24
+
25
+ #### Test
26
+
27
+ - Update your dependencies
28
+
29
+ ```sh
30
+ bundle install
31
+ ```
32
+
33
+ - Run tests
34
+
35
+ ```sh
36
+ bundle exec rspec
37
+ ```
38
+
39
+ ### 2. Running your unpublished Plugin in Logstash
40
+
41
+ #### 2.1 Run in a local Logstash clone
42
+
43
+ ##### 2.1.1 Version 1.5 and above
44
+
45
+ - Edit Logstash `Gemfile` and add the local plugin path, for example:
46
+ ```ruby
47
+ gem "logstash-output-jut", :path => "/your/local/logstash-output-jut"
48
+ ```
49
+ - Install plugin
50
+ ```sh
51
+ bin/plugin install --no-verify
52
+ ```
53
+ - Run Logstash with your plugin
54
+ ```sh
55
+ bin/logstash -e 'input { stdin {} } output { jut { url => URL }}'
56
+ ```
57
+ At this point any modifications to the plugin code will be applied to this local Logstash setup. After modifying the plugin, simply rerun Logstash.
58
+
59
+ ##### 2.1.1 Version 1.4 and below
60
+
61
+ - Copy the files jut.rb and HTTPBatcher.rb into /path/to/logstash-1.4.2/lib/logstash/outputs/
62
+
63
+ - Run Logstash with your plugin
64
+ ```sh
65
+ bin/logstash -e 'input { stdin {} } output { jut { url => URL }}'
66
+ ```
67
+
68
+ #### 2.2 Run in an installed Logstash
69
+
70
+ 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:
71
+
72
+ - Build your plugin gem
73
+ ```sh
74
+ gem build logstash-output-jut.gemspec
75
+ ```
76
+ - Install the plugin from the Logstash home
77
+ ```sh
78
+ bin/plugin install /your/local/plugin/logstash-output-jut.gem
79
+ ```
80
+ - Start Logstash and proceed to test the plugin
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "logstash/devutils/rake"
@@ -0,0 +1,134 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "json"
4
+ require "thread"
5
+ require "work_queue"
6
+ require "net/https"
7
+ require "openssl"
8
+ require "uri"
9
+
10
+ class LogStash::Outputs::HTTPBatcher
11
+ def initialize(url, idle_flush, logger, headers, limit, nthreads, verbose)
12
+ @url = URI.parse(url)
13
+ @idle_flush = idle_flush
14
+ @logger = logger
15
+ @headers = headers
16
+ @limit = limit
17
+ @verbose = verbose
18
+
19
+ @content_type = "application/json"
20
+ @stopped = false
21
+
22
+ @queue_mutex = Mutex.new
23
+ @queue = []
24
+
25
+ @flush_time = nil
26
+ @flush_thread = create_flush_thread()
27
+ @work_queue = WorkQueue.new nthreads, nil
28
+ end # def initialize
29
+
30
+ def stop
31
+ if @verbose
32
+ puts "stopping batcher (have #{@queue.size()} queued message)"
33
+ end
34
+
35
+ @stopped = true
36
+ while @queue.size() > 0 do
37
+ enqueue_batch
38
+ end
39
+
40
+ @flush_thread.join
41
+ @work_queue.join
42
+ end
43
+
44
+ def receive(event)
45
+ size = 0
46
+ @queue_mutex.synchronize do
47
+ @queue << event
48
+ size = @queue.size
49
+ end
50
+
51
+ if size >= @limit
52
+ enqueue_batch
53
+ end
54
+
55
+ @flush_time = Time.now + @idle_flush
56
+ end # def receive
57
+
58
+ def create_flush_thread
59
+ return Thread.new do
60
+ while !@stopped do
61
+ now = Time.now
62
+ if @flush_time != nil && @flush_time <= now
63
+ enqueue_batch
64
+ @flush_time = nil
65
+ end
66
+
67
+ sleep(@flush_time == nil ? @idle_flush : @flush_time - now)
68
+ end
69
+ end
70
+ end
71
+
72
+ def enqueue_batch
73
+ tosend = []
74
+ @queue_mutex.synchronize do
75
+ tosend = @queue.shift(@limit)
76
+ end
77
+
78
+ if tosend.size > 0
79
+ @work_queue.enqueue_b do
80
+ send_batch tosend
81
+ end
82
+ end
83
+ end
84
+
85
+ def send_batch(tosend)
86
+ connection = Thread.current["connection"]
87
+ if connection == nil
88
+ if @verbose
89
+ puts "creating new https connection"
90
+ end
91
+
92
+ connection = Net::HTTP.new(@url.host, @url.port)
93
+ connection.use_ssl = true
94
+ connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
95
+ Thread.current["connection"] = connection
96
+ end
97
+
98
+ beginning = Time.now
99
+ request = Net::HTTP::Post.new(@url.request_uri)
100
+
101
+ request["Content-Type"] = @content_type
102
+ if @headers
103
+ @headers.each do |k,v|
104
+ request.headers[k] = v
105
+ end
106
+ end
107
+
108
+ if @verbose
109
+ puts "posting #{tosend.size} records"
110
+ end
111
+
112
+ request.body = tosend.to_json
113
+ response = connection.request request
114
+
115
+ status = response.code
116
+ rbody = response.read_body
117
+
118
+ if status != "200"
119
+ raise "POST failed with status #{status} (#{rbody})"
120
+ end
121
+
122
+ if @verbose
123
+ time = Time.now - beginning
124
+ puts "POST response in #{time.to_s} #{status} #{rbody}"
125
+ end
126
+
127
+ rescue Exception => e
128
+ if @verbose
129
+ @logger.warn("Unhandled exception", :request => request, :exception => e, :stacktrace => e.backtrace)
130
+ else
131
+ @logger.warn("Unhandled exception", :host => request["host"], :exception => e, :stacktrace => e.backtrace)
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,74 @@
1
+ # encoding: utf-8
2
+ require "logstash/outputs/base"
3
+ require "logstash/namespace"
4
+ require "logstash/outputs/HTTPBatcher"
5
+
6
+ class LogStash::Outputs::Jut < LogStash::Outputs::Base
7
+ # This output lets you batch JSON objects and POSTs them to
8
+ # generic HTTP endpoints. This supports only sending JSON
9
+ # and sends a request every X seconds.
10
+ #
11
+ # Additionally, you are given the option to customize
12
+ # the headers.
13
+
14
+ config_name "jut"
15
+ milestone 1
16
+
17
+ # URL to use
18
+ config :url, :validate => :string, :required => :true
19
+
20
+ # Minimum interval at which requests are made per thread
21
+ config :interval, :validate => :number, :default => 1
22
+
23
+ # Maximum number of events per request
24
+ config :limit, :validate => :number, :default => 200
25
+
26
+ # Number of concurrent threads making requests
27
+ config :threads, :validate => :number, :default => 5
28
+
29
+ # Headers, if necessary, in the form of a hash
30
+ config :headers, :validate => :hash
31
+
32
+ # Verbose error messages
33
+ config :verbose, :validate => :boolean, :default => false
34
+
35
+ public
36
+ def register
37
+ @batcher = LogStash::Outputs::HTTPBatcher.new(@url, @interval, @logger, @headers, @limit, @threads, @verbose)
38
+ end # def register
39
+
40
+ public
41
+ def receive(event)
42
+ return unless output?(event)
43
+
44
+ # logstash wants to create "@timestamp", but jut wants "time"
45
+ # you could of course do this with a mutate filter but lets make
46
+ # the common case easy...
47
+ if event.include?('@timestamp')
48
+ event['time'] = event.remove('@timestamp')
49
+ end
50
+
51
+ if event.include?('@version')
52
+ event.remove('@version')
53
+ end
54
+
55
+ evt = event.to_hash
56
+ @batcher.receive(evt)
57
+
58
+ rescue Exception => e
59
+ @logger.warn("Unhandled exception", :exception => e, :stacktrace => e.backtrace)
60
+ end
61
+
62
+ public
63
+ def teardown
64
+ if @verbose
65
+ puts "tearing down jut output plugin"
66
+ end
67
+
68
+ @batcher.stop
69
+
70
+ if @verbose
71
+ puts "finished"
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,27 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'logstash-output-jut'
3
+ s.version = "0.3"
4
+ s.licenses = ["Apache License (2.0)"]
5
+ s.summary = "sends records to a Jut data engine"
6
+ s.description = "logstash output plugin that sends records to a Jut data engine"
7
+ s.authors = ["Jut, Inc."]
8
+ s.email = "josa@jut.io"
9
+ s.homepage = "https://github.com/jut-io/logstash-output-jut"
10
+ s.require_paths = ["lib"]
11
+
12
+ # Files
13
+ s.files = `git ls-files`.split($\)
14
+ # Tests
15
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
16
+
17
+ # Special flag to let us know this is actually a logstash plugin
18
+ # This metadata attribute blew up for me on Ubuntu 14.04 with the latest rubgems installed
19
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "output" }
20
+
21
+ # Gem dependencies
22
+ s.add_runtime_dependency "logstash-core", ">= 1.4.0", "< 2.0.0"
23
+ s.add_runtime_dependency "logstash-codec-plain"
24
+ s.add_runtime_dependency "work_queue"
25
+
26
+ s.add_development_dependency "logstash-devutils"
27
+ end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+ require "logstash/outputs/jut"
3
+ require "logstash/codecs/plain"
4
+ require "logstash/event"
5
+
6
+ describe LogStash::Outputs::Jut do
7
+ let(:jut_config) {
8
+ {
9
+ 'url' => 'http://localhost:9000/'
10
+ }
11
+ }
12
+ let(:sample_event) { LogStash::Event.new({'message' => 'hello', '@timestamp'=>LogStash::Timestamp.now}) }
13
+
14
+ context 'when intializing' do
15
+ it 'should register' do
16
+ output = LogStash::Outputs::Jut.new(jut_config)
17
+ expect {output.register}.to_not raise_error
18
+ end
19
+
20
+ it 'should populate jut config with default values' do
21
+ cfg = LogStash::Outputs::Jut.new(jut_config)
22
+ insist {cfg.url} == 'http://localhost:9000/'
23
+ insist {cfg.interval} == 1
24
+ insist {cfg.limit} == 200
25
+ insist {cfg.threads} == 5
26
+ insist {cfg.verbose} == false
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+ require "webmock/rspec"
3
+ WebMock.disable_net_connect!(allow_localhost: true)
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-output-jut
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.3'
5
+ platform: ruby
6
+ authors:
7
+ - Jut, Inc.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logstash-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.0
20
+ - - <
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.0
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: logstash-codec-plain
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: work_queue
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: logstash-devutils
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ description: logstash output plugin that sends records to a Jut data engine
76
+ email: josa@jut.io
77
+ executables: []
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - .gitignore
82
+ - CONTRIBUTORS
83
+ - Gemfile
84
+ - LICENSE
85
+ - README.md
86
+ - Rakefile
87
+ - lib/logstash/outputs/HTTPBatcher.rb
88
+ - lib/logstash/outputs/jut.rb
89
+ - logstash-output-jut.gemspec
90
+ - spec/outputs/jut_spec.rb
91
+ - spec/spec_helper.rb
92
+ homepage: https://github.com/jut-io/logstash-output-jut
93
+ licenses:
94
+ - Apache License (2.0)
95
+ metadata:
96
+ logstash_plugin: 'true'
97
+ logstash_group: output
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.0.14
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: sends records to a Jut data engine
118
+ test_files:
119
+ - spec/outputs/jut_spec.rb
120
+ - spec/spec_helper.rb