logstash-output-seq 0.0.3 → 0.2.0
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 +7 -7
- data/CONTRIBUTORS +11 -10
- data/DEVELOPER.md +2 -2
- data/DEVELOPING.md +69 -69
- data/Gemfile +11 -2
- data/LICENSE +22 -22
- data/README.md +37 -37
- data/lib/logstash/outputs/seq.rb +145 -145
- data/lib/version-info.rb +7 -7
- data/logstash-output-seq.gemspec +42 -39
- data/spec/outputs/seq_spec.rb +240 -239
- data/spec/spec_helper.rb +5 -4
- metadata +48 -52
data/lib/version-info.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
module LogStash
|
2
|
-
module Output
|
3
|
-
module Seq
|
4
|
-
VERSION = '0.0
|
5
|
-
end
|
6
|
-
end
|
7
|
-
end
|
1
|
+
module LogStash
|
2
|
+
module Output
|
3
|
+
module Seq
|
4
|
+
VERSION = '0.2.0'
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
data/logstash-output-seq.gemspec
CHANGED
@@ -1,39 +1,42 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
|
5
|
-
require 'version-info'
|
6
|
-
|
7
|
-
Gem::Specification.new do |spec|
|
8
|
-
spec.name = 'logstash-output-seq'
|
9
|
-
spec.version = LogStash::Output::Seq::VERSION
|
10
|
-
spec.licenses = ["MIT"]
|
11
|
-
spec.summary = "This plugin outputs log entries to Seq (https://getseq.net)."
|
12
|
-
spec.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install logstash-output-seq. This gem is not a stand-alone program"
|
13
|
-
spec.authors = ["tintoy"]
|
14
|
-
spec.email = "tintoy@tintoy.io"
|
15
|
-
spec.homepage = "https://github.com/tintoy/logstash-output-seq"
|
16
|
-
spec.require_paths = ["lib"]
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
spec.
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
spec.add_runtime_dependency "logstash-
|
30
|
-
|
31
|
-
spec.
|
32
|
-
|
33
|
-
|
34
|
-
spec.add_development_dependency "
|
35
|
-
spec.add_development_dependency "
|
36
|
-
spec.add_development_dependency "
|
37
|
-
spec.add_development_dependency "
|
38
|
-
spec.add_development_dependency "
|
39
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'version-info'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'logstash-output-seq'
|
9
|
+
spec.version = LogStash::Output::Seq::VERSION
|
10
|
+
spec.licenses = ["MIT"]
|
11
|
+
spec.summary = "This plugin outputs log entries to Seq (https://getseq.net)."
|
12
|
+
spec.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install logstash-output-seq. This gem is not a stand-alone program"
|
13
|
+
spec.authors = ["tintoy"]
|
14
|
+
spec.email = "tintoy@tintoy.io"
|
15
|
+
spec.homepage = "https://github.com/tintoy/logstash-output-seq"
|
16
|
+
spec.require_paths = ["lib"]
|
17
|
+
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
# Files
|
21
|
+
spec.files = Dir['lib/**/*','spec/**/*','vendor/**/*','*.gemspec','*.md','CONTRIBUTORS','Gemfile','LICENSE','NOTICE.TXT']
|
22
|
+
# Tests
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
+
|
25
|
+
# Special flag to let us know this is actually a logstash plugin
|
26
|
+
spec.metadata = { "logstash_plugin" => "true", "logstash_group" => "output" }
|
27
|
+
|
28
|
+
# Dependencies
|
29
|
+
spec.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
|
30
|
+
spec.add_runtime_dependency "logstash-codec-plain"
|
31
|
+
spec.add_runtime_dependency "logstash-mixin-http_client"
|
32
|
+
|
33
|
+
# Development dependencies
|
34
|
+
spec.add_development_dependency "logstash-devutils"
|
35
|
+
spec.add_development_dependency "coveralls", "~> 0.8"
|
36
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
37
|
+
spec.add_development_dependency "pry", "~> 0.10"
|
38
|
+
spec.add_development_dependency "rake", "~> 11.2"
|
39
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
40
|
+
spec.add_development_dependency "sinatra", "~> 1.4"
|
41
|
+
spec.add_development_dependency "webrick", "~> 1.3"
|
42
|
+
end
|
data/spec/outputs/seq_spec.rb
CHANGED
@@ -1,239 +1,240 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'logstash/
|
4
|
-
require 'logstash/
|
5
|
-
|
6
|
-
|
7
|
-
require "
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
let(:
|
15
|
-
let(:
|
16
|
-
|
17
|
-
|
18
|
-
'
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
let(:
|
25
|
-
let(:
|
26
|
-
let(:
|
27
|
-
let(:
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
'
|
34
|
-
'
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
'@
|
42
|
-
'
|
43
|
-
'
|
44
|
-
'
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
'@
|
49
|
-
'
|
50
|
-
'
|
51
|
-
'
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
'
|
89
|
-
'
|
90
|
-
'
|
91
|
-
|
92
|
-
'
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
'
|
126
|
-
'
|
127
|
-
'
|
128
|
-
|
129
|
-
'
|
130
|
-
'
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
'
|
136
|
-
'
|
137
|
-
'
|
138
|
-
|
139
|
-
'
|
140
|
-
'
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
end
|
184
|
-
|
185
|
-
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
189
|
-
# == Sinatra has
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
@
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
self.class.
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'logstash/devutils/rspec/spec_helper'
|
4
|
+
require 'logstash/codecs/plain'
|
5
|
+
require 'logstash/event'
|
6
|
+
|
7
|
+
require "jrjackson"
|
8
|
+
require "sinatra"
|
9
|
+
|
10
|
+
require_relative "../spec_helper"
|
11
|
+
|
12
|
+
describe LogStash::Outputs::Seq do
|
13
|
+
# Output and its configuration
|
14
|
+
let(:port) { PORT }
|
15
|
+
let(:url) { "http://localhost:#{port}/" }
|
16
|
+
let(:output) {
|
17
|
+
LogStash::Outputs::Seq.new({
|
18
|
+
'url' => url,
|
19
|
+
'pool_max' => 1 # Required so we can block until the request completes.
|
20
|
+
})
|
21
|
+
}
|
22
|
+
|
23
|
+
# Captured request
|
24
|
+
let(:request_failed) { TestApp.last_request_failed }
|
25
|
+
let(:last_request) { TestApp.last_request }
|
26
|
+
let(:request_body) { last_request.body.read }
|
27
|
+
let(:request_content_type) { last_request ? last_request.env["CONTENT_TYPE"] : nil }
|
28
|
+
let(:posted_events) { JrJackson::Json.parse(request_body) }
|
29
|
+
|
30
|
+
# Sample events
|
31
|
+
let(:sample_event) {
|
32
|
+
LogStash::Event.new({
|
33
|
+
'@timestamp' => '2016-07-23T10:09:08.12345+10:00',
|
34
|
+
'host' => 'localhost',
|
35
|
+
'message' => 'Hi, Single Event'
|
36
|
+
})
|
37
|
+
}
|
38
|
+
let(:sample_events) {
|
39
|
+
[
|
40
|
+
LogStash::Event.new({
|
41
|
+
'@timestamp' => '2016-07-23T00:09:08.123Z',
|
42
|
+
'@level' => 'Info',
|
43
|
+
'host' => 'localhost',
|
44
|
+
'message' => 'Hello, World!',
|
45
|
+
'name' => 'World'
|
46
|
+
}),
|
47
|
+
LogStash::Event.new({
|
48
|
+
'@timestamp' => '2016-07-23T00:09:00.456Z',
|
49
|
+
'@level' => 'Warning',
|
50
|
+
'host' => 'localhost',
|
51
|
+
'message' => 'Goodbye Moon?',
|
52
|
+
'name' => 'Moon'
|
53
|
+
})
|
54
|
+
]
|
55
|
+
}
|
56
|
+
|
57
|
+
before do
|
58
|
+
TestApp.reset
|
59
|
+
end
|
60
|
+
|
61
|
+
before do
|
62
|
+
output.register
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'receive message' do
|
66
|
+
before do
|
67
|
+
output.receive(sample_event)
|
68
|
+
wait_for_request
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'makes a request' do
|
72
|
+
expect(last_request).to_not be_nil
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'does an HTTP POST' do
|
76
|
+
expect(request_failed).to be(false)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'sends JSON' do
|
80
|
+
expect(request_content_type).to eq('application/json')
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'sends a valid event event data payload' do
|
84
|
+
expect(posted_events).to eq(
|
85
|
+
{
|
86
|
+
'Events' => [
|
87
|
+
{
|
88
|
+
'Timestamp' => '2016-07-23T00:09:08.123Z',
|
89
|
+
'Level' => 'Verbose',
|
90
|
+
'MessageTemplate' => 'Hi, Single Event',
|
91
|
+
'Properties' => {
|
92
|
+
'@Version' => "1",
|
93
|
+
'host' => 'localhost'
|
94
|
+
}
|
95
|
+
}
|
96
|
+
]
|
97
|
+
}
|
98
|
+
)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'receive messages' do
|
103
|
+
before do
|
104
|
+
output.multi_receive(sample_events)
|
105
|
+
wait_for_request
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'makes a request' do
|
109
|
+
expect(last_request).to_not be_nil
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'does an HTTP POST' do
|
113
|
+
expect(request_failed).to be(false)
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'sends JSON' do
|
117
|
+
expect(request_content_type).to eq('application/json')
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'sends a valid event event data payload' do
|
121
|
+
expect(posted_events).to eq(
|
122
|
+
{
|
123
|
+
'Events' => [
|
124
|
+
{
|
125
|
+
'Timestamp' => '2016-07-23T00:09:08.123Z',
|
126
|
+
'Level' => 'Info',
|
127
|
+
'MessageTemplate' => 'Hello, World!',
|
128
|
+
'Properties' => {
|
129
|
+
'@Version' => "1",
|
130
|
+
'host' => 'localhost',
|
131
|
+
'name' => 'World'
|
132
|
+
}
|
133
|
+
},
|
134
|
+
{
|
135
|
+
'Timestamp' => '2016-07-23T00:09:00.456Z',
|
136
|
+
'Level' => 'Warning',
|
137
|
+
'MessageTemplate' => 'Goodbye Moon?',
|
138
|
+
'Properties' => {
|
139
|
+
'@Version' => "1",
|
140
|
+
'host' => 'localhost',
|
141
|
+
'name' => 'Moon'
|
142
|
+
}
|
143
|
+
}
|
144
|
+
]
|
145
|
+
}
|
146
|
+
)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def wait_for_request()
|
151
|
+
# Wait for the current request to complete.
|
152
|
+
output.request_tokens.pop
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Enable access to request tokens from the test.
|
157
|
+
class LogStash::Outputs::Seq
|
158
|
+
attr_reader :request_tokens
|
159
|
+
end
|
160
|
+
|
161
|
+
PORT = rand(65535-1024) + 1025
|
162
|
+
|
163
|
+
RSpec.configure do |config|
|
164
|
+
#http://stackoverflow.com/questions/6557079/start-and-call-ruby-http-server-in-the-same-script
|
165
|
+
def sinatra_run_wait(app, opts)
|
166
|
+
queue = Queue.new
|
167
|
+
|
168
|
+
Thread.new(queue) do |queue|
|
169
|
+
begin
|
170
|
+
app.run!(opts) do |server|
|
171
|
+
queue.push("started")
|
172
|
+
end
|
173
|
+
rescue
|
174
|
+
# ignore
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
queue.pop # blocks until the run! callback runs
|
179
|
+
end
|
180
|
+
|
181
|
+
config.before(:suite) do
|
182
|
+
sinatra_run_wait(TestApp, :port => PORT, :server => 'webrick')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# note that Sinatra startup and shutdown messages are directly logged to stderr so
|
187
|
+
# it is not really possible to disable them without reopening stderr which is not advisable.
|
188
|
+
#
|
189
|
+
# == Sinatra (v1.4.6) has taken the stage on 51572 for development with backup from WEBrick
|
190
|
+
# == Sinatra has ended his set (crowd applauds)
|
191
|
+
|
192
|
+
class TestApp < Sinatra::Base
|
193
|
+
|
194
|
+
# disable WEBrick logging
|
195
|
+
def self.server_settings
|
196
|
+
{ :AccessLog => [], :Logger => WEBrick::BasicLog::new(nil, WEBrick::BasicLog::FATAL) }
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.reset()
|
200
|
+
@last_request_failed = false
|
201
|
+
@last_request = nil
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.last_request_failed=(last_request_failed)
|
205
|
+
@last_request_failed = last_request_failed
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.last_request_failed
|
209
|
+
@last_request_failed
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.last_request=(request)
|
213
|
+
@last_request = request
|
214
|
+
end
|
215
|
+
|
216
|
+
def self.last_request
|
217
|
+
@last_request
|
218
|
+
end
|
219
|
+
|
220
|
+
def self.multiroute(methods, path, &block)
|
221
|
+
methods.each do |method|
|
222
|
+
method.to_sym
|
223
|
+
self.send method, path, &block
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
post "/api/events/raw" do
|
228
|
+
self.class.last_request = request
|
229
|
+
# Success after failure stills means failure until reset
|
230
|
+
|
231
|
+
[200, '{"MinimumLevelAccepted": null}']
|
232
|
+
end
|
233
|
+
|
234
|
+
multiroute(%w(get post put patch delete), "/*") do
|
235
|
+
self.class.last_request = request
|
236
|
+
self.class.last_request_failed = true
|
237
|
+
|
238
|
+
[500, "{\"Error\": \"Unexpected request: #{request.request_method} '#{request.url}'\"}"]
|
239
|
+
end
|
240
|
+
end
|