fluent-plugin-splunk-hec 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +6 -2
- data/Gemfile.lock +27 -19
- data/README.md +21 -7
- data/Rakefile +7 -5
- data/VERSION +1 -1
- data/fluent-plugin-splunk-hec.gemspec +24 -20
- data/lib/fluent/plugin/out_splunk_hec.rb +31 -7
- data/lib/fluent/plugin/out_splunk_hec/match_formatter.rb +10 -7
- data/lib/fluent/plugin/out_splunk_hec/version.rb +3 -1
- data/test/fluent/plugin/out_splunk_hec_test.rb +139 -60
- data/test/test_helper.rb +15 -12
- metadata +36 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4460c822fc2a85e65234099aca29574dcdc17e4403c3fbc1da7c48d4a5fd9608
|
4
|
+
data.tar.gz: 9950c15e61273b9dcd597c8fc3ff83dad5be0f7f741bb67a5b296ccd98c1a366
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39fcf467dea44451264c3a56e0ab1442b196ab7c424112969e997567174ba9b4e0ce1def62535bb72a5a5af88d45ac16f53273cc590c2c9636d57e927e7b6b2e
|
7
|
+
data.tar.gz: d50f4a1df76c1d2661d387cfdedb0e47d4621526b7e94b73a0e06c3965b38c9b53ca87a83f48df60f64da553ec62c1bd9bbae1301b9677f0c7dbd316bbf1fa2f
|
data/Gemfile
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
|
3
|
+
group :test do
|
4
|
+
gem 'simplecov', require: false
|
5
|
+
end
|
6
|
+
|
7
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
8
|
|
5
9
|
# Specify your gem's dependencies in fluent-plugin-splunk_hec_output.gemspec
|
6
10
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,22 +1,23 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fluent-plugin-splunk-hec (1.
|
5
|
-
fluentd (~> 1.
|
4
|
+
fluent-plugin-splunk-hec (1.1.0)
|
5
|
+
fluentd (~> 1.4)
|
6
6
|
multi_json (~> 1.13)
|
7
7
|
net-http-persistent (~> 3.0)
|
8
8
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
addressable (2.
|
12
|
+
addressable (2.6.0)
|
13
13
|
public_suffix (>= 2.0.2, < 4.0)
|
14
|
-
connection_pool (2.2.
|
14
|
+
connection_pool (2.2.2)
|
15
15
|
cool.io (1.5.3)
|
16
16
|
crack (0.4.3)
|
17
17
|
safe_yaml (~> 1.0.0)
|
18
18
|
dig_rb (1.0.1)
|
19
|
-
|
19
|
+
docile (1.3.1)
|
20
|
+
fluentd (1.4.0)
|
20
21
|
cool.io (>= 1.4.5, < 2.0.0)
|
21
22
|
dig_rb (~> 1.0.0)
|
22
23
|
http_parser.rb (>= 0.5.1, < 0.7.0)
|
@@ -27,44 +28,51 @@ GEM
|
|
27
28
|
tzinfo (~> 1.0)
|
28
29
|
tzinfo-data (~> 1.0)
|
29
30
|
yajl-ruby (~> 1.0)
|
30
|
-
hashdiff (0.3.
|
31
|
+
hashdiff (0.3.8)
|
31
32
|
http_parser.rb (0.6.0)
|
33
|
+
json (2.1.0)
|
32
34
|
minitest (5.11.3)
|
33
|
-
msgpack (1.2.
|
35
|
+
msgpack (1.2.7)
|
34
36
|
multi_json (1.13.1)
|
35
37
|
net-http-persistent (3.0.0)
|
36
38
|
connection_pool (~> 2.2)
|
37
|
-
power_assert (1.1.
|
38
|
-
public_suffix (3.0.
|
39
|
-
rake (
|
39
|
+
power_assert (1.1.3)
|
40
|
+
public_suffix (3.0.3)
|
41
|
+
rake (12.3.2)
|
40
42
|
safe_yaml (1.0.4)
|
41
|
-
serverengine (2.0
|
43
|
+
serverengine (2.1.0)
|
42
44
|
sigdump (~> 0.2.2)
|
43
45
|
sigdump (0.2.4)
|
46
|
+
simplecov (0.16.1)
|
47
|
+
docile (~> 1.1)
|
48
|
+
json (>= 1.8, < 3)
|
49
|
+
simplecov-html (~> 0.10.0)
|
50
|
+
simplecov-html (0.10.2)
|
44
51
|
strptime (0.2.3)
|
45
|
-
test-unit (3.
|
52
|
+
test-unit (3.3.0)
|
46
53
|
power_assert
|
47
54
|
thread_safe (0.3.6)
|
48
55
|
tzinfo (1.2.5)
|
49
56
|
thread_safe (~> 0.1)
|
50
|
-
tzinfo-data (1.2018.
|
57
|
+
tzinfo-data (1.2018.9)
|
51
58
|
tzinfo (>= 1.0.0)
|
52
|
-
webmock (3.
|
59
|
+
webmock (3.5.1)
|
53
60
|
addressable (>= 2.3.6)
|
54
61
|
crack (>= 0.3.2)
|
55
62
|
hashdiff
|
56
|
-
yajl-ruby (1.
|
63
|
+
yajl-ruby (1.4.1)
|
57
64
|
|
58
65
|
PLATFORMS
|
59
66
|
ruby
|
60
67
|
|
61
68
|
DEPENDENCIES
|
62
|
-
bundler (~>
|
69
|
+
bundler (~> 2.0)
|
63
70
|
fluent-plugin-splunk-hec!
|
64
71
|
minitest (~> 5.0)
|
65
|
-
rake (~>
|
72
|
+
rake (~> 12.0)
|
73
|
+
simplecov
|
66
74
|
test-unit (~> 3.0)
|
67
|
-
webmock (~> 3.
|
75
|
+
webmock (~> 3.5.0)
|
68
76
|
|
69
77
|
BUNDLED WITH
|
70
|
-
|
78
|
+
2.0.1
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[
|
1
|
+
[![CircleCI](https://circleci.com/gh/git-lfs/git-lfs.svg?style=shield&circle-token=856152c2b02bfd236f54d21e1f581f3e4ebf47ad)](https://circleci.com/gh/splunk/fluent-plugin-splunk-hec)
|
2
2
|
# fluent-plugin-splunk-hec
|
3
3
|
|
4
4
|
[Fluentd](https://fluentd.org/) output plugin to send events and metrics to [Splunk](https://www.splunk.com) over the HEC (HTTP Event Collector) API.
|
@@ -6,11 +6,9 @@
|
|
6
6
|
## Installation
|
7
7
|
|
8
8
|
### RubyGems
|
9
|
-
|
10
|
-
```
|
9
|
+
```
|
11
10
|
$ gem install fluent-plugin-splunk-hec
|
12
11
|
```
|
13
|
-
|
14
12
|
### Bundler
|
15
13
|
|
16
14
|
Add following line to your Gemfile:
|
@@ -334,6 +332,22 @@ If you want to use a different default formatter, you can add a `<format **>` (o
|
|
334
332
|
|
335
333
|
Defines which formatter to use.
|
336
334
|
|
335
|
+
### Net::HTTP::Persistent parameters (optional)
|
336
|
+
|
337
|
+
The following parameters can be used for tuning HTTP connections
|
338
|
+
|
339
|
+
#### idle_timeout (integer)
|
340
|
+
|
341
|
+
The default is 5 seconds. If a connection has not been used for this number of seconds it will automatically be reset upon the next use to avoid attempting to send to a closed connection; nil means no timeout.
|
342
|
+
|
343
|
+
#### read_timeout (integer)
|
344
|
+
|
345
|
+
The default is nil. The amount of time allowed between reading two chunks from the socket.
|
346
|
+
|
347
|
+
#### open_timeout (integer)
|
348
|
+
|
349
|
+
The default is nil. The amount of time to wait for a connection to be opened.
|
350
|
+
|
337
351
|
### SSL parameters
|
338
352
|
|
339
353
|
There are quite some parameters you can use to configure SSL (for HTTPS protocol).
|
@@ -372,10 +386,10 @@ It batches all events in a chunk in one request. So you need to configure the `<
|
|
372
386
|
Here are some hints:
|
373
387
|
|
374
388
|
* Read through the [fluentd buffer document](https://docs.fluentd.org/v1.0/articles/buffer-section) to understand the buffer configurations.
|
375
|
-
* Use `chunk_limit_size` and/or `chunk_limit_records` to define how big a chunk can be. And
|
389
|
+
* Use `chunk_limit_size` and/or `chunk_limit_records` to define how big a chunk can be. And remember that all events in a chunk will be sent in one request.
|
376
390
|
* Splunk has a limit on how big the payload of a HEC request can be. And it's defined with `max_content_length` in [the `[http_input]` section of `limits.conf`](https://docs.splunk.com/Documentation/Splunk/latest/Admin/Limitsconf#.5Bhttp_input.5D). In Splunk of version 6.5.0+, the default value is 800MiB, while in versions before 6.5.0, it's just 1MB. Make sure your chunk size won't exceed this limit, or you should change the limit on your Splunk deployment.
|
377
|
-
* Sending requests to HEC takes time, so if you flush your fluentd buffer too fast (for example, with a very small `flush_interval`), it's possible that the plugin cannot catch up with the buffer flushing. There are two ways you can handle this
|
391
|
+
* Sending requests to HEC takes time, so if you flush your fluentd buffer too fast (for example, with a very small `flush_interval`), it's possible that the plugin cannot catch up with the buffer flushing. There are two ways you can handle this situation, one is to increase the `flush_interval` or use multiple flush threads by setting `flush_thread_count` to a number bigger than 1.
|
378
392
|
|
379
393
|
## License
|
380
394
|
|
381
|
-
Please see [LICENSE](LICENSE).
|
395
|
+
Please see [LICENSE](LICENSE).
|
data/Rakefile
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
3
3
|
|
4
4
|
Rake::TestTask.new(:test) do |t|
|
5
|
-
t.libs <<
|
6
|
-
t.libs <<
|
7
|
-
t.test_files = FileList[
|
5
|
+
t.libs << 'test'
|
6
|
+
t.libs << 'lib'
|
7
|
+
t.test_files = FileList['test/**/*_test.rb']
|
8
|
+
t.verbose = false
|
9
|
+
t.warning = false
|
8
10
|
end
|
9
11
|
|
10
12
|
task :default => :test
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
@@ -1,16 +1,18 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
|
-
spec.name =
|
3
|
-
spec.version = File.read(
|
4
|
-
spec.authors = [
|
5
|
-
spec.email = [
|
2
|
+
spec.name = 'fluent-plugin-splunk-hec'
|
3
|
+
spec.version = File.read('VERSION')
|
4
|
+
spec.authors = ['Splunk Inc.']
|
5
|
+
spec.email = ['DataEdge@splunk.com']
|
6
6
|
|
7
|
-
spec.summary =
|
8
|
-
spec.description =
|
9
|
-
|
10
|
-
spec.
|
7
|
+
spec.summary = 'Fluentd plugin for Splunk HEC.'
|
8
|
+
spec.description = 'A fluentd output plugin created by Splunk
|
9
|
+
that writes events to splunk indexers over HTTP Event Collector API.'
|
10
|
+
spec.homepage = 'https://github.com/splunk/fluent-plugin-splunk-hec'
|
11
|
+
spec.license = 'Apache-2.0'
|
11
12
|
|
12
|
-
# Prevent pushing this gem to RubyGems.org.
|
13
|
-
#
|
13
|
+
# Prevent pushing this gem to RubyGems.org.
|
14
|
+
# To allow pushes either set the 'allowed_push_host' to allow
|
15
|
+
# pushing to a single host or delete this section to allow pushing to any host.
|
14
16
|
# if spec.respond_to?(:metadata)
|
15
17
|
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
16
18
|
# else
|
@@ -18,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
18
20
|
# "public gem pushes."
|
19
21
|
# end
|
20
22
|
|
21
|
-
spec.require_paths = [
|
23
|
+
spec.require_paths = ['lib']
|
22
24
|
spec.test_files = Dir.glob('test/**/**.rb')
|
23
25
|
spec.files = %w[
|
24
26
|
CODE_OF_CONDUCT.md README.md LICENSE
|
@@ -27,15 +29,17 @@ Gem::Specification.new do |spec|
|
|
27
29
|
Rakefile VERSION
|
28
30
|
] + Dir.glob('lib/**/**').reject(&File.method(:directory?))
|
29
31
|
|
30
|
-
spec.required_ruby_version = '>= 2.
|
32
|
+
spec.required_ruby_version = '>= 2.3.0'
|
31
33
|
|
32
|
-
spec.add_runtime_dependency
|
33
|
-
spec.add_runtime_dependency
|
34
|
-
spec.add_runtime_dependency
|
34
|
+
spec.add_runtime_dependency 'fluentd', '~> 1.4'
|
35
|
+
spec.add_runtime_dependency 'multi_json', '~> 1.13'
|
36
|
+
spec.add_runtime_dependency 'net-http-persistent', '~> 3.0'
|
35
37
|
|
36
|
-
spec.add_development_dependency
|
37
|
-
spec.add_development_dependency
|
38
|
-
|
39
|
-
spec.add_development_dependency
|
40
|
-
spec.add_development_dependency
|
38
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
39
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
40
|
+
# required by fluent/test.rb
|
41
|
+
spec.add_development_dependency 'test-unit', '~> 3.0'
|
42
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
43
|
+
spec.add_development_dependency 'webmock', '~> 3.5.0'
|
44
|
+
spec.add_development_dependency 'simplecov', '~> 0.16.1'
|
41
45
|
end
|
@@ -16,7 +16,7 @@ module Fluent::Plugin
|
|
16
16
|
autoload :VERSION, "fluent/plugin/out_splunk_hec/version"
|
17
17
|
autoload :MatchFormatter, "fluent/plugin/out_splunk_hec/match_formatter"
|
18
18
|
|
19
|
-
KEY_FIELDS = %w[index host source sourcetype metric_name metric_value].freeze
|
19
|
+
KEY_FIELDS = %w[index time host source sourcetype metric_name metric_value].freeze
|
20
20
|
TAG_PLACEHOLDER = '${tag}'.freeze
|
21
21
|
|
22
22
|
MISSING_FIELD = Hash.new { |h, k|
|
@@ -36,6 +36,15 @@ module Fluent::Plugin
|
|
36
36
|
desc 'The HEC token.'
|
37
37
|
config_param :hec_token, :string
|
38
38
|
|
39
|
+
desc 'If a connection has not been used for this number of seconds it will automatically be reset upon the next use to avoid attempting to send to a closed connection. nil means no timeout.'
|
40
|
+
config_param :idle_timeout, :integer, default: 5
|
41
|
+
|
42
|
+
desc 'The amount of time allowed between reading two chunks from the socket.'
|
43
|
+
config_param :read_timeout, :integer, default: nil
|
44
|
+
|
45
|
+
desc 'The amount of time to wait for a connection to be opened.'
|
46
|
+
config_param :open_timeout, :integer, default: nil
|
47
|
+
|
39
48
|
desc 'The path to a file containing a PEM-format CA certificate for this client.'
|
40
49
|
config_param :client_cert, :string, default: nil
|
41
50
|
|
@@ -60,6 +69,9 @@ module Fluent::Plugin
|
|
60
69
|
desc 'The Splunk index to index events. When not set, will be decided by HEC. This is exclusive with `index_key`'
|
61
70
|
config_param :index, :string, default: nil
|
62
71
|
|
72
|
+
desc 'Field name to contain Splunk event time. By default will use fluentd\'d time'
|
73
|
+
config_param :time_key, :string, default: nil
|
74
|
+
|
63
75
|
desc 'Field name to contain Splunk index name. This is exclusive with `index`.'
|
64
76
|
config_param :index_key, :string, default: nil
|
65
77
|
|
@@ -113,7 +125,7 @@ module Fluent::Plugin
|
|
113
125
|
config_param :coerce_to_utf8, :bool, :default => true
|
114
126
|
|
115
127
|
desc <<~DESC
|
116
|
-
If `coerce_to_utf8` is set to true, any
|
128
|
+
If `coerce_to_utf8` is set to true, any not-UTF-8 char's would be
|
117
129
|
replaced by the string specified here.
|
118
130
|
DESC
|
119
131
|
config_param :non_utf8_replacement_string, :string, :default => ' '
|
@@ -237,9 +249,18 @@ module Fluent::Plugin
|
|
237
249
|
# From the API reference
|
238
250
|
# http://docs.splunk.com/Documentation/Splunk/latest/RESTREF/RESTinput#services.2Fcollector
|
239
251
|
# `time` should be a string or unsigned integer.
|
240
|
-
# That's why we use
|
252
|
+
# That's why we use the to_string function here.
|
241
253
|
time: time.to_f.to_s
|
242
254
|
}.tap { |payload|
|
255
|
+
|
256
|
+
if @time
|
257
|
+
time_value = @time.(tag, record)
|
258
|
+
# if no value is found don't override and use fluentd's time
|
259
|
+
if !time_value.nil?
|
260
|
+
payload[:time] = time_value
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
243
264
|
payload[:index] = @index.(tag, record) if @index
|
244
265
|
payload[:source] = @source.(tag, record) if @source
|
245
266
|
payload[:sourcetype] = @sourcetype.(tag, record) if @sourcetype
|
@@ -248,8 +269,8 @@ module Fluent::Plugin
|
|
248
269
|
%i[host index source sourcetype].each { |f| payload.delete f if payload[f].nil? }
|
249
270
|
|
250
271
|
if @extra_fields
|
251
|
-
|
252
|
-
|
272
|
+
payload[:fields] = @extra_fields.map { |name, field| [name, record[field]] }.to_h
|
273
|
+
payload[:fields].delete_if { |_k,v| v.nil? }
|
253
274
|
# if a field is already in indexed fields, then remove it from the original event
|
254
275
|
@extra_fields.values.each { |field| record.delete field }
|
255
276
|
end
|
@@ -286,7 +307,7 @@ module Fluent::Plugin
|
|
286
307
|
fields.update record
|
287
308
|
end
|
288
309
|
|
289
|
-
|
310
|
+
fields.delete_if { |_k,v| v.nil? }
|
290
311
|
|
291
312
|
payload[:fields] = convert_to_utf8 fields
|
292
313
|
|
@@ -315,6 +336,9 @@ module Fluent::Plugin
|
|
315
336
|
c.ca_file = @ca_file
|
316
337
|
c.ca_path = @ca_path
|
317
338
|
c.ciphers = @ssl_ciphers
|
339
|
+
c.idle_timeout = @idle_timeout
|
340
|
+
c.read_timeout = @read_timeout
|
341
|
+
c.open_timeout = @open_timeout
|
318
342
|
|
319
343
|
c.override_headers['Content-Type'] = 'application/json'
|
320
344
|
c.override_headers['User-Agent'] = "fluent-plugin-splunk_hec_out/#{VERSION}"
|
@@ -375,7 +399,7 @@ module Fluent::Plugin
|
|
375
399
|
'replace them with spaces, please set "coerce_to_utf8" ' \
|
376
400
|
'to true.' }
|
377
401
|
raise
|
378
|
-
|
402
|
+
end
|
379
403
|
end
|
380
404
|
end
|
381
405
|
end
|
@@ -2,13 +2,16 @@ require 'fluent/match'
|
|
2
2
|
|
3
3
|
class Fluent::Plugin::SplunkHecOutput::MatchFormatter
|
4
4
|
def initialize(pattern, formatter)
|
5
|
-
#
|
6
|
-
patterns = pattern.split(/\s+/).map { |str|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
# based on fluentd/lib/fluent/event_router.rb
|
6
|
+
patterns = pattern.split(/\s+/).map { |str|
|
7
|
+
Fluent::MatchPattern.create(str)
|
8
|
+
}
|
9
|
+
@pattern =
|
10
|
+
if patterns.length == 1
|
11
|
+
patterns[0]
|
12
|
+
else
|
13
|
+
Fluent::OrMatchPattern.new(patterns)
|
14
|
+
end
|
12
15
|
@formatter = formatter
|
13
16
|
end
|
14
17
|
|
@@ -8,10 +8,59 @@ describe Fluent::Plugin::SplunkHecOutput do
|
|
8
8
|
|
9
9
|
it { expect(::Fluent::Plugin::SplunkHecOutput::VERSION).wont_be_nil }
|
10
10
|
|
11
|
+
describe "config param tests" do
|
12
|
+
it "should require https protocol" do
|
13
|
+
expect(create_output_driver('hec_host protocol').instance.protocol).must_equal :https
|
14
|
+
end
|
15
|
+
it "should require hec_host" do
|
16
|
+
expect(create_output_driver('hec_host hec_host').instance.hec_host).must_equal "hec_host"
|
17
|
+
end
|
18
|
+
it "should require hec_port" do
|
19
|
+
expect(create_output_driver('hec_host hec_port').instance.hec_port).must_equal 8088
|
20
|
+
end
|
21
|
+
it "should require hec_token" do
|
22
|
+
expect(create_output_driver('hec_host hec_token').instance.hec_token).must_equal "some-token"
|
23
|
+
end
|
24
|
+
it "should define client_cert as nil initially" do
|
25
|
+
assert_nil(create_output_driver('hec_host hec_token').instance.client_cert)
|
26
|
+
end
|
27
|
+
it "should define client_key as nil (string) initially" do
|
28
|
+
assert_nil(create_output_driver('hec_host hec_token').instance.client_key)
|
29
|
+
expect(create_output_driver('hec_host hec_token').instance.client_key).is_a? String
|
30
|
+
end
|
31
|
+
it "should define ca_file as nil (string) initially" do
|
32
|
+
assert_nil(create_output_driver('hec_host hec_token').instance.ca_file)
|
33
|
+
expect(create_output_driver('hec_host hec_token').instance.ca_file).is_a? String
|
34
|
+
end
|
35
|
+
it "should define ca_path as nil (string) initially" do
|
36
|
+
assert_nil(create_output_driver('hec_host hec_token').instance.ca_path)
|
37
|
+
expect(create_output_driver('hec_host hec_token').instance.ca_path).is_a? String
|
38
|
+
end
|
39
|
+
it "should define ssl_ciphers as nil (array) initially" do
|
40
|
+
assert_nil(create_output_driver('hec_host hec_token').instance.ssl_ciphers)
|
41
|
+
expect(create_output_driver('hec_host hec_token').instance.ssl_ciphers).is_a? Array
|
42
|
+
end
|
43
|
+
it "should not allow an insecure ssl connection" do
|
44
|
+
expect(create_output_driver('hec_host hec_token').instance.insecure_ssl).must_equal false
|
45
|
+
end
|
46
|
+
it "should allow both event (default) and metric to be sent to splunk" do
|
47
|
+
expect(create_output_driver('hec_host hec_token').instance.data_type).must_equal :event
|
48
|
+
expect(create_output_driver('hec_host hec_token').instance.data_type = :metric).must_equal :metric
|
49
|
+
end
|
50
|
+
it "should define Splunk index to index (string) as nil initially" do
|
51
|
+
assert_nil(create_output_driver('hec_host hec_token').instance.index)
|
52
|
+
expect(create_output_driver('hec_host hec_token').instance.index).is_a? String
|
53
|
+
end
|
54
|
+
it "should define field names to include Splunk index_key as nil (string) initially" do
|
55
|
+
assert_nil(create_output_driver('hec_host hec_token').instance.index_key)
|
56
|
+
expect(create_output_driver('hec_host hec_token').instance.index_key).is_a? String
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
11
60
|
describe "hec_host validation" do
|
12
61
|
describe "invalid host" do
|
13
62
|
it "should require hec_host" do
|
14
|
-
|
63
|
+
expect{ create_output_driver }.must_raise Fluent::ConfigError
|
15
64
|
end
|
16
65
|
|
17
66
|
it { expect{ create_output_driver('hec_host %bad-host%') }.must_raise Fluent::ConfigError }
|
@@ -19,7 +68,7 @@ describe Fluent::Plugin::SplunkHecOutput do
|
|
19
68
|
|
20
69
|
describe "good host" do
|
21
70
|
it {
|
22
|
-
|
71
|
+
expect(create_output_driver('hec_host splunk.com').instance.hec_host).must_equal "splunk.com"
|
23
72
|
}
|
24
73
|
end
|
25
74
|
end
|
@@ -34,16 +83,25 @@ describe Fluent::Plugin::SplunkHecOutput do
|
|
34
83
|
it "should use string for event time, and the value of the string should be a float" do
|
35
84
|
verify_sent_events { |batch|
|
36
85
|
batch.each do |item|
|
37
|
-
|
38
|
-
|
86
|
+
expect(item['time']).must_be_instance_of String
|
87
|
+
expect(item['time']).must_match /^\d+\.\d+$/
|
39
88
|
end
|
40
89
|
}
|
41
90
|
end
|
42
91
|
|
92
|
+
# it "should contain splunk event time field via fluentd, as nil" do
|
93
|
+
# expect(create_output_driver('hec_host splunk.com').instance.time_key).must_equal nil
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
it "should contain splunk event time field via fluentd, as nil" do
|
97
|
+
test_driver = create_output_driver('hec_host splunk.com')
|
98
|
+
assert_nil(test_driver.instance.time_key)
|
99
|
+
end
|
100
|
+
|
43
101
|
it "should use host machine's hostname for event host by default" do
|
44
102
|
verify_sent_events { |batch|
|
45
103
|
batch.each do |item|
|
46
|
-
|
104
|
+
expect(item['host']).must_equal Socket.gethostname
|
47
105
|
end
|
48
106
|
}
|
49
107
|
end
|
@@ -51,9 +109,9 @@ describe Fluent::Plugin::SplunkHecOutput do
|
|
51
109
|
%w[index source sourcetype].each do |field|
|
52
110
|
it "should not set #{field} by default" do
|
53
111
|
verify_sent_events { |batch|
|
54
|
-
|
55
|
-
|
56
|
-
|
112
|
+
batch.each do |item|
|
113
|
+
expect(item).wont_include field
|
114
|
+
end
|
57
115
|
}
|
58
116
|
end
|
59
117
|
end
|
@@ -66,9 +124,9 @@ describe Fluent::Plugin::SplunkHecOutput do
|
|
66
124
|
sourcetype ${tag}
|
67
125
|
CONF
|
68
126
|
batch.each do |item|
|
69
|
-
|
70
|
-
|
71
|
-
|
127
|
+
%w[index host source sourcetype].each { |field|
|
128
|
+
expect(%w[tag.event1 tag.event2]).must_include item[field]
|
129
|
+
}
|
72
130
|
end
|
73
131
|
}
|
74
132
|
end
|
@@ -81,10 +139,10 @@ describe Fluent::Plugin::SplunkHecOutput do
|
|
81
139
|
sourcetype_key agent.name
|
82
140
|
CONF
|
83
141
|
batch.each { |item|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
142
|
+
expect(item['index']).must_equal 'info'
|
143
|
+
expect(item['host']).must_equal 'my_machine'
|
144
|
+
expect(item['source']).must_equal 'cool.log'
|
145
|
+
expect(item['sourcetype']).must_equal 'test'
|
88
146
|
|
89
147
|
JSON.load(item['event']).tap do |event|
|
90
148
|
%w[level from file].each { |field| expect(event).wont_include field }
|
@@ -94,7 +152,7 @@ describe Fluent::Plugin::SplunkHecOutput do
|
|
94
152
|
}
|
95
153
|
end
|
96
154
|
|
97
|
-
it "should remove nil
|
155
|
+
it "should remove nil fields." do
|
98
156
|
verify_sent_events(<<~CONF) { |batch|
|
99
157
|
index_key nonexist
|
100
158
|
host_key nonexist
|
@@ -111,7 +169,7 @@ describe Fluent::Plugin::SplunkHecOutput do
|
|
111
169
|
end
|
112
170
|
|
113
171
|
describe 'formatter' do
|
114
|
-
it "should support replace the default json
|
172
|
+
it "should support replace the default json formatter" do
|
115
173
|
verify_sent_events(<<~CONF) { |batch|
|
116
174
|
<format>
|
117
175
|
@type single_value
|
@@ -163,86 +221,107 @@ describe Fluent::Plugin::SplunkHecOutput do
|
|
163
221
|
describe 'metric'do
|
164
222
|
it 'should check related configs' do
|
165
223
|
expect(
|
166
|
-
|
224
|
+
create_output_driver('hec_host somehost', 'data_type metric')
|
167
225
|
).wont_be_nil
|
168
226
|
|
169
227
|
expect{
|
170
|
-
|
228
|
+
create_output_driver('hec_host somehost', 'data_type metric', 'metrics_from_event false')
|
171
229
|
}.must_raise Fluent::ConfigError
|
172
230
|
|
173
231
|
expect{
|
174
|
-
|
232
|
+
create_output_driver('hec_host somehost', 'data_type metric', 'metric_name_key x')
|
175
233
|
}.must_raise Fluent::ConfigError
|
176
234
|
|
177
235
|
expect(
|
178
|
-
|
236
|
+
create_output_driver('hec_host somehost', 'data_type metric', 'metric_name_key x', 'metric_value_key y')
|
179
237
|
).wont_be_nil
|
180
238
|
end
|
181
239
|
|
182
240
|
it 'should have "metric" as event, and have proper fields' do
|
183
241
|
verify_sent_events(<<~CONF) { |batch|
|
184
|
-
|
185
|
-
|
186
|
-
|
242
|
+
data_type metric
|
243
|
+
metric_name_key from
|
244
|
+
metric_value_key value
|
187
245
|
CONF
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
246
|
+
batch.each do |item|
|
247
|
+
expect(item['event']).must_equal 'metric'
|
248
|
+
expect(item['fields']['metric_name']).must_equal 'my_machine'
|
249
|
+
expect(item['fields']['_value']).must_equal 100
|
250
|
+
expect(item['fields']['log']).must_equal 'everything is good'
|
251
|
+
expect(item['fields']['level']).must_equal 'info'
|
252
|
+
expect(item['fields']['file']).must_equal 'cool.log'
|
253
|
+
end
|
196
254
|
}
|
197
255
|
end
|
198
256
|
|
199
257
|
it 'should handle empty fields' do
|
200
258
|
verify_sent_events(<<~CONF) { |batch|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
259
|
+
data_type metric
|
260
|
+
metric_name_key from
|
261
|
+
metric_value_key value
|
262
|
+
<fields>
|
263
|
+
</fields>
|
206
264
|
CONF
|
207
|
-
|
265
|
+
batch.each do |item|
|
208
266
|
# only "metric_name" and "_value"
|
209
|
-
|
210
|
-
|
267
|
+
expect(item['fields'].keys.size).must_equal 2
|
268
|
+
end
|
211
269
|
}
|
212
270
|
end
|
213
271
|
|
214
272
|
it 'should handle custom fields' do
|
215
273
|
verify_sent_events(<<~CONF) { |batch|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
274
|
+
data_type metric
|
275
|
+
metric_name_key from
|
276
|
+
metric_value_key value
|
277
|
+
<fields>
|
278
|
+
level
|
279
|
+
filePath file
|
280
|
+
username
|
281
|
+
</fields>
|
224
282
|
CONF
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
283
|
+
batch.each do |item|
|
284
|
+
expect(item['fields'].keys.size).must_equal 4
|
285
|
+
expect(item['fields']['level']).must_equal 'info'
|
286
|
+
expect(item['fields']['filePath']).must_equal 'cool.log'
|
287
|
+
# null fields should be removed
|
288
|
+
expect(item['fields']).wont_be :has_key?, 'username'
|
289
|
+
end
|
232
290
|
}
|
233
291
|
end
|
234
292
|
|
235
293
|
it 'should treat each key-value in event as a metric' do
|
236
294
|
metrics = [
|
237
|
-
|
238
|
-
|
295
|
+
['tag', event_time, {'cup': 0.5, 'memory': 100}],
|
296
|
+
['tag', event_time, {'cup': 0.6, 'memory': 200}]
|
239
297
|
]
|
240
298
|
with_stub_hec(events: metrics, conf: 'data_type metric') { |batch|
|
241
|
-
|
299
|
+
expect(batch.size).must_equal 4
|
242
300
|
}
|
243
301
|
end
|
244
302
|
end
|
245
303
|
|
304
|
+
describe 'timeout params' do
|
305
|
+
it 'should reset unused connection after 5 seconds' do
|
306
|
+
expect(create_output_driver('hec_host splunk.com', 'idle_timeout 5').instance.idle_timeout).must_equal 5
|
307
|
+
end
|
308
|
+
|
309
|
+
it 'should allow custom setting between reading chunks from the socket' do
|
310
|
+
expect(create_output_driver('hec_host splunk.com', 'read_timeout 5').instance.read_timeout).must_equal 5
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'should allow custom setting a connection to be opened' do
|
314
|
+
expect(create_output_driver('hec_host splunk.com', 'open_timeout 5').instance.open_timeout).must_equal 5
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'should check default values are created correctly for timeout params' do
|
318
|
+
test_driver = create_output_driver('hec_host splunk.com')
|
319
|
+
expect(test_driver.instance.idle_timeout).must_equal 5
|
320
|
+
assert_nil(test_driver.instance.read_timeout)
|
321
|
+
assert_nil(test_driver.instance.open_timeout)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
246
325
|
def with_stub_hec(events:, conf: '', &blk)
|
247
326
|
host = "hec.splunk.com"
|
248
327
|
@driver = create_output_driver("hec_host #{host}", conf)
|
@@ -266,8 +345,8 @@ describe Fluent::Plugin::SplunkHecOutput do
|
|
266
345
|
"file" => "cool.log",
|
267
346
|
"value" => 100,
|
268
347
|
"agent" => {
|
269
|
-
|
270
|
-
|
348
|
+
"name" => "test",
|
349
|
+
"version" => "1.1.0"
|
271
350
|
}
|
272
351
|
}
|
273
352
|
events = [
|
data/test/test_helper.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require "fluent/plugin/out_splunk_hec"
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
require
|
8
|
-
require "minitest/autorun"
|
9
|
-
require "webmock/minitest"
|
4
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
5
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
6
|
+
require 'fluent/plugin/out_splunk_hec'
|
10
7
|
|
8
|
+
require 'fluent/test'
|
9
|
+
require 'fluent/test/driver/output'
|
10
|
+
require 'fluent/test/helpers'
|
11
|
+
require 'minitest/autorun'
|
12
|
+
require 'webmock/minitest'
|
11
13
|
|
12
14
|
# make assertions from webmock available in minitest/spec
|
13
15
|
module Minitest::Expectations
|
@@ -15,7 +17,7 @@ module Minitest::Expectations
|
|
15
17
|
infect_an_assertion :assert_not_requested, :wont_be_requested, :reverse
|
16
18
|
end
|
17
19
|
|
18
|
-
TEST_HEC_TOKEN =
|
20
|
+
TEST_HEC_TOKEN = 'some-token'.freeze
|
19
21
|
|
20
22
|
module PluginTestHelper
|
21
23
|
def fluentd_conf_for(*lines)
|
@@ -32,8 +34,9 @@ module PluginTestHelper
|
|
32
34
|
end
|
33
35
|
|
34
36
|
def stub_hec_request(endpoint)
|
35
|
-
stub_request(:post, "#{endpoint}/services/collector")
|
36
|
-
with(headers: {
|
37
|
-
|
37
|
+
stub_request(:post, "#{endpoint}/services/collector")
|
38
|
+
.with(headers: { 'Authorization' => "Splunk #{TEST_HEC_TOKEN}",
|
39
|
+
'User-Agent' => "fluent-plugin-splunk_hec_out/#{Fluent::Plugin::SplunkHecOutput::VERSION}" })
|
40
|
+
.to_return(body: '{"text":"Success","code":0}')
|
38
41
|
end
|
39
42
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-splunk-hec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Splunk Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-03-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.4'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.4'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: multi_json
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,28 +58,28 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '2.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '2.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '12.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '12.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: test-unit
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,18 +114,33 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
117
|
+
version: 3.5.0
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
125
|
-
|
126
|
-
|
124
|
+
version: 3.5.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.16.1
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.16.1
|
139
|
+
description: |-
|
140
|
+
A fluentd output plugin created by Splunk
|
141
|
+
that writes events to splunk indexers over HTTP Event Collector API.
|
127
142
|
email:
|
128
|
-
-
|
143
|
+
- DataEdge@splunk.com
|
129
144
|
executables: []
|
130
145
|
extensions: []
|
131
146
|
extra_rdoc_files: []
|
@@ -163,26 +178,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
163
178
|
requirements:
|
164
179
|
- - ">="
|
165
180
|
- !ruby/object:Gem::Version
|
166
|
-
version: 2.
|
181
|
+
version: 2.3.0
|
167
182
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
183
|
requirements:
|
169
184
|
- - ">="
|
170
185
|
- !ruby/object:Gem::Version
|
171
186
|
version: '0'
|
172
187
|
requirements: []
|
173
|
-
|
174
|
-
rubygems_version: 2.7.6
|
188
|
+
rubygems_version: 3.0.3
|
175
189
|
signing_key:
|
176
190
|
specification_version: 4
|
177
191
|
summary: Fluentd plugin for Splunk HEC.
|
178
192
|
test_files:
|
179
|
-
- test/fluent/plugin/out_splunk_hec_test.rb
|
180
|
-
- test/lib/webmock/http_lib_adapters/patron_adapter.rb
|
181
|
-
- test/lib/webmock/http_lib_adapters/manticore_adapter.rb
|
182
193
|
- test/lib/webmock/http_lib_adapters/em_http_request_adapter.rb
|
183
194
|
- test/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb
|
184
|
-
- test/lib/webmock/http_lib_adapters/curb_adapter.rb
|
185
195
|
- test/lib/webmock/http_lib_adapters/httpclient_adapter.rb
|
186
|
-
- test/lib/webmock/http_lib_adapters/http_rb_adapter.rb
|
187
196
|
- test/lib/webmock/http_lib_adapters/excon_adapter.rb
|
197
|
+
- test/lib/webmock/http_lib_adapters/patron_adapter.rb
|
198
|
+
- test/lib/webmock/http_lib_adapters/manticore_adapter.rb
|
199
|
+
- test/lib/webmock/http_lib_adapters/curb_adapter.rb
|
200
|
+
- test/lib/webmock/http_lib_adapters/http_rb_adapter.rb
|
188
201
|
- test/test_helper.rb
|
202
|
+
- test/fluent/plugin/out_splunk_hec_test.rb
|