logstash-output-seq 0.0.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|