logstash-output-unomaly 0.1.3
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 +7 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +11 -0
- data/README.md +40 -0
- data/lib/logstash/outputs/unomaly.rb +333 -0
- data/logstash-output-unomaly.gemspec +28 -0
- data/spec/outputs/unomaly_spec.rb +46 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4a098c44ba976c41ad152a148d265a6a7ece4216307104156ae1ff9f578589cd
|
4
|
+
data.tar.gz: b1dc31ddc497b25ae5895aa5407117047f695cc03d1ccc99e4f69f605e3cc9e0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1b9e317eab598594b691766d46199d12dfe3291baa7e49863762cae50e7a9679693f1d35ed80ce69c4d033908171b9026a19e910c78c818b979ca0d5a7b23cf0
|
7
|
+
data.tar.gz: cecec9cc21f9dc4c23663010be493597baeb082c73eecec5e3fcd122bdfac1f679b303e275e0a6659d6c669b3fe5a25a829c7be9517a45e4046b04e32e2b9fbb
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
logstash_path = ENV["LOGSTASH_PATH"] || "../../logstash"
|
6
|
+
use_logstash_source = ENV["LOGSTASH_SOURCE"] && ENV["LOGSTASH_SOURCE"].to_s == "1"
|
7
|
+
|
8
|
+
if Dir.exist?(logstash_path) && use_logstash_source
|
9
|
+
gem 'logstash-core', :path => "#{logstash_path}/logstash-core"
|
10
|
+
gem 'logstash-core-plugin-api', :path => "#{logstash_path}/logstash-core-plugin-api"
|
11
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Logstash output plugin for Unomaly
|
2
|
+
|
3
|
+
[](https://travis-ci.org/unomaly/logstash-output-unomaly)
|
4
|
+
|
5
|
+
This plugin sends Logstash events to the [Unomaly](https://www.unomaly.com) ingestion API (min version Unomaly 2.27). The minimal configuration looks like this:
|
6
|
+
|
7
|
+
|
8
|
+
```
|
9
|
+
output {
|
10
|
+
unomaly {
|
11
|
+
host => "https://your-unomaly-instance:443"
|
12
|
+
}
|
13
|
+
}
|
14
|
+
```
|
15
|
+
|
16
|
+
# Important options
|
17
|
+
|
18
|
+
|
19
|
+
| Option | Description | Default |
|
20
|
+
|----------------------------|----------------------------------------------------------------------------------|------------|
|
21
|
+
| host | Unomaly instance address. Must define full path such as "https://my-instance:443"| No default |
|
22
|
+
| message_key | The key in the Logstash event that Unomaly should use for anomaly detection. | "message" |
|
23
|
+
| source_key | The event key defining the Unomaly system. | "host" |
|
24
|
+
| ssl_certificate_validation | Enable or disable SSL certificate validation | "strict" |
|
25
|
+
|
26
|
+
See the [source code](lib/logstash/outputs/unomaly.rb) for the full list of options
|
27
|
+
|
28
|
+
|
29
|
+
## Known issues
|
30
|
+
- Installation of the plugin fails on Logstash 6.2.1.
|
31
|
+
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome. This project is intended to
|
36
|
+
be a safe, welcoming space for collaboration.
|
37
|
+
|
38
|
+
## Development
|
39
|
+
|
40
|
+
We use docker to build the plugin. You can build it by running `docker-compose run jruby gem build logstash-output-unomaly.gemspec `
|
@@ -0,0 +1,333 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/outputs/base"
|
3
|
+
require "logstash/namespace"
|
4
|
+
require "logstash/json"
|
5
|
+
require 'uri'
|
6
|
+
require 'json'
|
7
|
+
require 'manticore'
|
8
|
+
|
9
|
+
# An example output that does nothing.
|
10
|
+
class LogStash::Outputs::Unomaly < LogStash::Outputs::Base
|
11
|
+
class InvalidHTTPConfigError < StandardError; end
|
12
|
+
|
13
|
+
concurrency :shared
|
14
|
+
config_name "unomaly"
|
15
|
+
|
16
|
+
# Event batch size to send to Unomaly. Increasing the batch size can increase throughput by reducing HTTP overhead
|
17
|
+
config :batch_size, :validate => :number, :default => 50
|
18
|
+
|
19
|
+
# Unomaly host to send the logs to
|
20
|
+
config :host, :validate => :string, :required => true
|
21
|
+
|
22
|
+
# Key that will be used by Unomaly as the log message
|
23
|
+
config :message_key, :validate => :string, :default => "message"
|
24
|
+
|
25
|
+
# Key that will be used by Unomaly as the system key
|
26
|
+
config :source_key, :validate => :string, :default => "host"
|
27
|
+
|
28
|
+
# Unomaly api path to push events
|
29
|
+
config :api_path, :validate => :string, :default => "/v1/batch"
|
30
|
+
|
31
|
+
# Keep logstash timestamp
|
32
|
+
config :keep_timestamp, :validate => :boolean, :default => true
|
33
|
+
|
34
|
+
# Display debug logs
|
35
|
+
config :debug, :validate => :boolean, :default => false
|
36
|
+
|
37
|
+
# Timeout (in seconds) for the entire request
|
38
|
+
config :request_timeout, :validate => :number, :default => 60
|
39
|
+
|
40
|
+
# Timeout (in seconds) to wait for data on the socket. Default is `10s`
|
41
|
+
config :socket_timeout, :validate => :number, :default => 10
|
42
|
+
|
43
|
+
# Timeout (in seconds) to wait for a connection to be established. Default is `10s`
|
44
|
+
config :connect_timeout, :validate => :number, :default => 10
|
45
|
+
|
46
|
+
# Should redirects be followed? Defaults to `true`
|
47
|
+
config :follow_redirects, :validate => :boolean, :default => true
|
48
|
+
|
49
|
+
# Max number of concurrent connections. Defaults to `50`
|
50
|
+
config :pool_max, :validate => :number, :default => 50
|
51
|
+
|
52
|
+
# Max number of concurrent connections to a single host. Defaults to `25`
|
53
|
+
config :pool_max_per_route, :validate => :number, :default => 25
|
54
|
+
|
55
|
+
# Turn this on to enable HTTP keepalive support. We highly recommend setting `automatic_retries` to at least
|
56
|
+
# one with this to fix interactions with broken keepalive implementations.
|
57
|
+
config :keepalive, :validate => :boolean, :default => true
|
58
|
+
|
59
|
+
# How many times should the client retry a failing URL. We highly recommend NOT setting this value
|
60
|
+
# to zero if keepalive is enabled. Some servers incorrectly end keepalives early requiring a retry!
|
61
|
+
# Note: if `retry_non_idempotent` is set only GET, HEAD, PUT, DELETE, OPTIONS, and TRACE requests will be retried.
|
62
|
+
config :automatic_retries, :validate => :number, :default => 1
|
63
|
+
|
64
|
+
# If `automatic_retries` is enabled this will cause non-idempotent HTTP verbs (such as POST) to be retried.
|
65
|
+
config :retry_non_idempotent, :validate => :boolean, :default => false
|
66
|
+
|
67
|
+
# How long to wait before checking if the connection is stale before executing a request on a connection using keepalive.
|
68
|
+
# # You may want to set this lower, possibly to 0 if you get connection errors regularly
|
69
|
+
# Quoting the Apache commons docs (this client is based Apache Commmons):
|
70
|
+
# 'Defines period of inactivity in milliseconds after which persistent connections must be re-validated prior to being leased to the consumer. Non-positive value passed to this method disables connection validation. This check helps detect connections that have become stale (half-closed) while kept inactive in the pool.'
|
71
|
+
# See https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.html#setValidateAfterInactivity(int)[these docs for more info]
|
72
|
+
config :validate_after_inactivity, :validate => :number, :default => 200
|
73
|
+
|
74
|
+
# refer to https://github.com/cheald/manticore/blob/6764e2d3fb67a1ef244cb4610d5b74ba1dd6694c/lib/manticore/client.rb#L161
|
75
|
+
# instead of using symbol, use string "disable" or "false", "browser", "strict"
|
76
|
+
config :ssl_certificate_validation, :validate => :string, :default => "strict"
|
77
|
+
|
78
|
+
# If you need to use a custom X.509 CA (.pem certs) specify the path to that here
|
79
|
+
config :cacert, :validate => :path
|
80
|
+
|
81
|
+
# If you'd like to use a client certificate (note, most people don't want this) set the path to the x509 cert here
|
82
|
+
config :client_cert, :validate => :path
|
83
|
+
# If you're using a client certificate specify the path to the encryption key here
|
84
|
+
config :client_key, :validate => :path
|
85
|
+
|
86
|
+
# If you need to use a custom keystore (`.jks`) specify that here. This does not work with .pem keys!
|
87
|
+
config :keystore, :validate => :path
|
88
|
+
|
89
|
+
# Specify the keystore password here.
|
90
|
+
# Note, most .jks files created with keytool require a password!
|
91
|
+
config :keystore_password, :validate => :password
|
92
|
+
|
93
|
+
# Specify the keystore type here. One of `JKS` or `PKCS12`. Default is `JKS`
|
94
|
+
config :keystore_type, :validate => :string, :default => "JKS"
|
95
|
+
|
96
|
+
# If you need to use a custom truststore (`.jks`) specify that here. This does not work with .pem certs!
|
97
|
+
config :truststore, :validate => :path
|
98
|
+
|
99
|
+
# Specify the truststore password here.
|
100
|
+
# Note, most .jks files created with keytool require a password!
|
101
|
+
config :truststore_password, :validate => :password
|
102
|
+
|
103
|
+
# Specify the truststore type here. One of `JKS` or `PKCS12`. Default is `JKS`
|
104
|
+
config :truststore_type, :validate => :string, :default => "JKS"
|
105
|
+
|
106
|
+
# Enable cookie support. With this enabled the client will persist cookies
|
107
|
+
# across requests as a normal web browser would. Enabled by default
|
108
|
+
config :cookies, :validate => :boolean, :default => true
|
109
|
+
|
110
|
+
# If you'd like to use an HTTP proxy . This supports multiple configuration syntaxes:
|
111
|
+
#
|
112
|
+
# 1. Proxy host in form: `http://proxy.org:1234`
|
113
|
+
# 2. Proxy host in form: `{host => "proxy.org", port => 80, scheme => 'http', user => 'username@host', password => 'password'}`
|
114
|
+
# 3. Proxy host in form: `{url => 'http://proxy.org:1234', user => 'username@host', password => 'password'}`
|
115
|
+
config :proxy
|
116
|
+
|
117
|
+
# Username to use for HTTP auth.
|
118
|
+
config :user, :validate => :string
|
119
|
+
|
120
|
+
# Password to use for HTTP auth
|
121
|
+
config :password, :validate => :password
|
122
|
+
|
123
|
+
public
|
124
|
+
def register
|
125
|
+
@total = 0
|
126
|
+
@total_failed = 0
|
127
|
+
logger.info("Initialized Unomaly output plugin with configuration",
|
128
|
+
:host => @host,
|
129
|
+
:accept_self_signed_cert => @accept_self_signed_cert)
|
130
|
+
|
131
|
+
end # def register
|
132
|
+
|
133
|
+
def client_config
|
134
|
+
c = {
|
135
|
+
connect_timeout: @connect_timeout,
|
136
|
+
socket_timeout: @socket_timeout,
|
137
|
+
request_timeout: @request_timeout,
|
138
|
+
follow_redirects: @follow_redirects,
|
139
|
+
automatic_retries: @automatic_retries,
|
140
|
+
retry_non_idempotent: @retry_non_idempotent,
|
141
|
+
check_connection_timeout: @validate_after_inactivity,
|
142
|
+
pool_max: @pool_max,
|
143
|
+
pool_max_per_route: @pool_max_per_route,
|
144
|
+
cookies: @cookies,
|
145
|
+
keepalive: @keepalive
|
146
|
+
}
|
147
|
+
|
148
|
+
if @proxy
|
149
|
+
# Symbolize keys if necessary
|
150
|
+
c[:proxy] = @proxy.is_a?(Hash) ?
|
151
|
+
@proxy.reduce({}) {|memo,(k,v)| memo[k.to_sym] = v; memo} :
|
152
|
+
@proxy
|
153
|
+
end
|
154
|
+
|
155
|
+
if @user
|
156
|
+
if !@password || !@password.value
|
157
|
+
raise ::LogStash::ConfigurationError, "User '#{@user}' specified without password!"
|
158
|
+
end
|
159
|
+
|
160
|
+
# Symbolize keys if necessary
|
161
|
+
c[:auth] = {
|
162
|
+
:user => @user,
|
163
|
+
:password => @password.value,
|
164
|
+
:eager => true
|
165
|
+
}
|
166
|
+
end
|
167
|
+
|
168
|
+
c[:ssl] = {}
|
169
|
+
if @ssl_certificate_validation == "disable" || @ssl_certificate_validation == "false"
|
170
|
+
c[:ssl][:verify] = :disable
|
171
|
+
elsif @ssl_certificate_validation == "browser"
|
172
|
+
c[:ssl][:verify] = :browser
|
173
|
+
end
|
174
|
+
|
175
|
+
if @cacert
|
176
|
+
c[:ssl][:ca_file] = @cacert
|
177
|
+
end
|
178
|
+
|
179
|
+
if @truststore
|
180
|
+
c[:ssl].merge!(
|
181
|
+
:truststore => @truststore,
|
182
|
+
:truststore_type => @truststore_type,
|
183
|
+
:truststore_password => @truststore_password.value
|
184
|
+
)
|
185
|
+
|
186
|
+
if c[:ssl][:truststore_password].nil?
|
187
|
+
raise LogStash::ConfigurationError, "Truststore declared without a password! This is not valid, please set the 'truststore_password' option"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
if @keystore
|
192
|
+
c[:ssl].merge!(
|
193
|
+
:keystore => @keystore,
|
194
|
+
:keystore_type => @keystore_type,
|
195
|
+
:keystore_password => @keystore_password.value
|
196
|
+
)
|
197
|
+
|
198
|
+
if c[:ssl][:keystore_password].nil?
|
199
|
+
raise LogStash::ConfigurationError, "Keystore declared without a password! This is not valid, please set the 'keystore_password' option"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
if @client_cert && @client_key
|
204
|
+
c[:ssl][:client_cert] = @client_cert
|
205
|
+
c[:ssl][:client_key] = @client_key
|
206
|
+
elsif !!@client_cert ^ !!@client_key
|
207
|
+
raise InvalidHTTPConfigError, "You must specify both client_cert and client_key for an HTTP client, or neither!"
|
208
|
+
end
|
209
|
+
|
210
|
+
c
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
def make_client
|
215
|
+
puts client_config
|
216
|
+
Manticore::Client.new(client_config)
|
217
|
+
end
|
218
|
+
|
219
|
+
public
|
220
|
+
def client
|
221
|
+
@client ||= make_client
|
222
|
+
end
|
223
|
+
|
224
|
+
public
|
225
|
+
def close
|
226
|
+
@client.close
|
227
|
+
end
|
228
|
+
|
229
|
+
def flatten(data, prefix)
|
230
|
+
ret = {}
|
231
|
+
if data.is_a? Hash
|
232
|
+
data.each { |key, value|
|
233
|
+
if prefix.to_s.empty?
|
234
|
+
ret.merge! flatten(value, "#{key.to_s}")
|
235
|
+
else
|
236
|
+
ret.merge! flatten(value, "#{prefix}__#{key.to_s}")
|
237
|
+
end
|
238
|
+
}
|
239
|
+
elsif data.is_a? Array
|
240
|
+
data.each_with_index {|val,index | ret.merge! flatten(val, "#{prefix}__#{index}")}
|
241
|
+
else
|
242
|
+
return {prefix => data.to_s}
|
243
|
+
end
|
244
|
+
|
245
|
+
ret
|
246
|
+
end
|
247
|
+
|
248
|
+
def send_batch(events)
|
249
|
+
url = @host + @api_path
|
250
|
+
body = events.to_json
|
251
|
+
|
252
|
+
request = client.post(url, {
|
253
|
+
:body => body,
|
254
|
+
:headers => {"Content-Type"=>"application/json"}
|
255
|
+
})
|
256
|
+
|
257
|
+
request.on_success do |response|
|
258
|
+
if response.code == 200
|
259
|
+
@logger.debug("Successfully sent ",
|
260
|
+
:response_code => response.code,
|
261
|
+
:total => @total,
|
262
|
+
:time => Time::now.utc)
|
263
|
+
else
|
264
|
+
@total_failed += 1
|
265
|
+
log_failure(
|
266
|
+
"Encountered non-200 HTTP code #{response.code}",
|
267
|
+
:response_code => response.code,
|
268
|
+
:url => url,
|
269
|
+
:response_body => response.body,
|
270
|
+
:total_failed => @total_failed)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
request.on_failure do |exception|
|
275
|
+
@total_failed += 1
|
276
|
+
log_failure("Could not access URL",
|
277
|
+
:url => url,
|
278
|
+
:method => @http_method,
|
279
|
+
:body => body,
|
280
|
+
:message => exception.message,
|
281
|
+
:class => exception.class.name,
|
282
|
+
:backtrace => exception.backtrace,
|
283
|
+
:total_failed => @total_failed
|
284
|
+
)
|
285
|
+
end
|
286
|
+
|
287
|
+
@logger.debug("Sending Unomaly Event",
|
288
|
+
:total => @total,
|
289
|
+
:time => Time::now.utc)
|
290
|
+
request.call
|
291
|
+
|
292
|
+
rescue Exception => e
|
293
|
+
@logger.error("[Exception=] #{e.message} #{e.backtrace}")
|
294
|
+
end
|
295
|
+
|
296
|
+
|
297
|
+
public
|
298
|
+
def multi_receive(events)
|
299
|
+
if debug
|
300
|
+
puts events.to_json
|
301
|
+
end
|
302
|
+
|
303
|
+
events.each_slice(@batch_size) do |chunk|
|
304
|
+
documents = []
|
305
|
+
chunk.each do |event|
|
306
|
+
unomaly_event = {
|
307
|
+
message: event.get(@message_key),
|
308
|
+
source: event.get(@source_key),
|
309
|
+
}
|
310
|
+
|
311
|
+
metadata = event.to_hash
|
312
|
+
|
313
|
+
if @keep_timestamp
|
314
|
+
unomaly_event["timestamp"] = event.get("@timestamp")
|
315
|
+
metadata.delete("@timestamp")
|
316
|
+
end
|
317
|
+
|
318
|
+
metadata.delete(@source_key)
|
319
|
+
metadata.delete(@message_key)
|
320
|
+
|
321
|
+
unomaly_event["metadata"]=flatten(metadata,"")
|
322
|
+
|
323
|
+
|
324
|
+
documents.push(unomaly_event)
|
325
|
+
end
|
326
|
+
send_batch(documents)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def log_failure(message, opts)
|
331
|
+
@logger.error("[HTTP Output Failure] #{message}", opts)
|
332
|
+
end
|
333
|
+
end # class LogStash::Outputs::Unomaly
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'logstash-output-unomaly'
|
3
|
+
s.version = '0.1.3'
|
4
|
+
s.licenses = ['Apache License (2.0)']
|
5
|
+
s.summary = "Logstash output plugin for Unomaly"
|
6
|
+
s.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 gemname. This gem is not a stand-alone program"
|
7
|
+
s.authors = ["Unomaly"]
|
8
|
+
s.email = "support@unomaly.com"
|
9
|
+
s.homepage = "https://unomaly.com"
|
10
|
+
s.require_paths = ["lib"]
|
11
|
+
|
12
|
+
# Files
|
13
|
+
s.files = Dir['lib/**/*','spec/**/*','vendor/**/*','*.gemspec','*.md','Gemfile']
|
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
|
+
s.metadata = { "logstash_plugin" => "true", "logstash_group" => "output" }
|
19
|
+
|
20
|
+
# Gem dependencies
|
21
|
+
#
|
22
|
+
|
23
|
+
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
|
24
|
+
s.add_runtime_dependency "logstash-codec-plain"
|
25
|
+
s.add_runtime_dependency 'manticore', '>= 0.5.2', '< 1.0.0'
|
26
|
+
|
27
|
+
s.add_development_dependency 'logstash-devutils'
|
28
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/devutils/rspec/spec_helper"
|
3
|
+
require "logstash/outputs/unomaly"
|
4
|
+
require "logstash/event"
|
5
|
+
|
6
|
+
describe LogStash::Outputs::Unomaly do
|
7
|
+
let(:sample_event) { LogStash::Event.new("message" => "hello this is log") }
|
8
|
+
let(:client) { @unomaly.client }
|
9
|
+
|
10
|
+
before do
|
11
|
+
@unomaly = LogStash::Outputs::Unomaly.new("host" => "localhost", "batch_size" => 3)
|
12
|
+
@unomaly.register
|
13
|
+
allow(@unomaly).to receive(:client).and_return(client)
|
14
|
+
allow(client).to receive(:post).and_call_original
|
15
|
+
end
|
16
|
+
|
17
|
+
before do
|
18
|
+
allow(@unomaly).to receive(:client).and_return(client)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
it "Forwards an event" do
|
23
|
+
expect(client).to receive(:post).once.and_call_original
|
24
|
+
@unomaly.multi_receive([sample_event])
|
25
|
+
end
|
26
|
+
|
27
|
+
it "Batches multiple events and extracts metadata" do
|
28
|
+
event1 = LogStash::Event.new("message" => "hello this is log 1", "host" => "host1")
|
29
|
+
event2 = LogStash::Event.new("message" => "hello this is log 2", "host" => "host2")
|
30
|
+
event3 = LogStash::Event.new("message" => "hello this is log 3", "host" => "host3")
|
31
|
+
expect(client).to receive(:post).once.with("localhost/v1/batch",hash_including(:body => LogStash::Json.dump(
|
32
|
+
[{"message" => "hello this is log 1", "source" => "host1", "timestamp" => event1.timestamp.to_s, "metadata" => {"@version" => "1"}},
|
33
|
+
{"message" => "hello this is log 2", "source" => "host2", "timestamp" => event2.timestamp.to_s, "metadata" => {"@version" => "1"}},
|
34
|
+
{"message" => "hello this is log 3", "source" => "host3", "timestamp" => event3.timestamp.to_s, "metadata" => {"@version" => "1"}}
|
35
|
+
]
|
36
|
+
))).and_call_original
|
37
|
+
@unomaly.multi_receive([event1, event2, event3])
|
38
|
+
end
|
39
|
+
|
40
|
+
it "Batches data of size batch_size" do
|
41
|
+
expect(client).to receive(:post).exactly(2).times.and_call_original
|
42
|
+
@unomaly.multi_receive([sample_event, sample_event, sample_event, sample_event])
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: logstash-output-unomaly
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Unomaly
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-06-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: logstash-core-plugin-api
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.60'
|
20
|
+
- - "<="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.99'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.60'
|
30
|
+
- - "<="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.99'
|
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: manticore
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.5.2
|
54
|
+
- - "<"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 1.0.0
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.5.2
|
64
|
+
- - "<"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 1.0.0
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: logstash-devutils
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
description: This gem is a Logstash plugin required to be installed on top of the
|
82
|
+
Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This
|
83
|
+
gem is not a stand-alone program
|
84
|
+
email: support@unomaly.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- CHANGELOG.md
|
90
|
+
- Gemfile
|
91
|
+
- README.md
|
92
|
+
- lib/logstash/outputs/unomaly.rb
|
93
|
+
- logstash-output-unomaly.gemspec
|
94
|
+
- spec/outputs/unomaly_spec.rb
|
95
|
+
homepage: https://unomaly.com
|
96
|
+
licenses:
|
97
|
+
- Apache License (2.0)
|
98
|
+
metadata:
|
99
|
+
logstash_plugin: 'true'
|
100
|
+
logstash_group: output
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 2.7.7
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: Logstash output plugin for Unomaly
|
121
|
+
test_files:
|
122
|
+
- spec/outputs/unomaly_spec.rb
|