fluent-plugin-splunk-ex-logentries 1.0.1.logentries
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/.travis.yml +7 -0
- data/Gemfile +5 -0
- data/README.md +56 -0
- data/Rakefile +16 -0
- data/fluent-plugin-splunk-ex.gemspec +28 -0
- data/lib/fluent/plugin/out_splunk_ex.rb +145 -0
- data/spec/out_splunk_ex_spec.rb +74 -0
- data/spec/spec_helper.rb +25 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: df18337f5895e02bcafd8d9926082575d6ba5234a4b343db4da3bff10efa7678
|
4
|
+
data.tar.gz: 6f7e8e2b4c06a27e04c7fc7bb0d62a6c4fab71b483cfa72663b2e12c5f418440
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 591ca52932934d84a350f5b90f3a358e6250777ea798b79cc15107a81d1146de283419d89243c64a2428c78c85f0e813748a88e25b3e86327d552586658ac4f1
|
7
|
+
data.tar.gz: cac585a169d1b687e96914dbe320e65106814637681ea78d6a2199b8996e95208790f0cbef3d7c41d3cb3591730b4b64b8ad7cd99a202eb64f2def2630943189
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
[](https://travis-ci.org/gtrevg/fluent-plugin-splunk-ex) [](https://codeclimate.com/github/gtrevg/fluent-plugin-splunk-ex) [](https://coveralls.io/r/gtrevg/fluent-plugin-splunk-ex)
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
This plugin will send your fluentd logs to a splunk server. It can send the data in either
|
6
|
+
key/value (k1=v1 k2=v2) or json format for easy splunk parsing.
|
7
|
+
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
gem install fluent-plugin-splunk-ex
|
12
|
+
|
13
|
+
## Configuration
|
14
|
+
|
15
|
+
### Plugin
|
16
|
+
|
17
|
+
<match pattern>
|
18
|
+
type splunk_ex
|
19
|
+
host <splunk_host> # default: localhost
|
20
|
+
port <splunk_port> # default: 9997 - but you'll want to change this
|
21
|
+
output_format json|kv # default: json
|
22
|
+
</match>
|
23
|
+
|
24
|
+
### Splunk
|
25
|
+
|
26
|
+
You may need to open up a special TCP port just for the fluentd logs. To do that, go to
|
27
|
+
`Manager -> Data Inputs -> TCP -> New`. Then decide the following:
|
28
|
+
|
29
|
+
* Port
|
30
|
+
* Source Name
|
31
|
+
* Source Type
|
32
|
+
* Index ( default works well )
|
33
|
+
|
34
|
+
After enabling these settings, you'll be able to see your fluentd logs appear in your Splunk search interface.
|
35
|
+
The JSON format will be automagically parsed and indexed based on the keys passed in.
|
36
|
+
|
37
|
+
Because the plugin batch sends data to Splunk, you'll want to update your `apps/search/local/props.conf`
|
38
|
+
file to specify that Splunk should split on newlines. If you do not update this setting, you find that
|
39
|
+
all logs from a similar time slice will be stacked upon each other. Because the kv & json formats do
|
40
|
+
not contain any newline characters, splitting on the newline will solve this problem. The values to
|
41
|
+
add to this file are:
|
42
|
+
|
43
|
+
[<source_type_here>]
|
44
|
+
SHOULD_LINEMERGE = false
|
45
|
+
|
46
|
+
This will make sure that the new source type you just set up for fluentd will always split on the newline character.
|
47
|
+
|
48
|
+
## Copyright
|
49
|
+
|
50
|
+
Copyright (c) 2014 Trevor Gattis
|
51
|
+
|
52
|
+
## License
|
53
|
+
|
54
|
+
Apache License, Version 2.0
|
55
|
+
|
56
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
require 'rspec/core'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
7
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
8
|
+
end
|
9
|
+
task :default => :spec
|
10
|
+
|
11
|
+
desc 'Open an irb session preloaded with the gem library'
|
12
|
+
task :console do
|
13
|
+
sh 'irb -rubygems -I lib'
|
14
|
+
end
|
15
|
+
task :c => :console
|
16
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.name = "fluent-plugin-splunk-ex-logentries"
|
5
|
+
gem.version = "1.0.1.logentries"
|
6
|
+
|
7
|
+
gem.authors = ["Trevor Gattis"]
|
8
|
+
gem.email = "github@trevorgattis.com"
|
9
|
+
gem.description = "Splunk output plugin for Fluent event collector. It supports reconnecting on socket failure as well as exporting the data as json or in key/value pairs. Modified to produce output format fit for Logentries."
|
10
|
+
gem.homepage = "https://github.com/Indrius/fluent-plugin-splunk-ex"
|
11
|
+
gem.summary = gem.description
|
12
|
+
gem.license = "APLv2"
|
13
|
+
gem.has_rdoc = false
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split("\n")
|
16
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.add_dependency "fluentd", "~> 0.10.17"
|
21
|
+
gem.add_runtime_dependency "json"
|
22
|
+
|
23
|
+
gem.add_development_dependency "rake"
|
24
|
+
gem.add_development_dependency "rspec"
|
25
|
+
gem.add_development_dependency "pry"
|
26
|
+
gem.add_development_dependency "pry-nav"
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,145 @@
|
|
1
|
+
#
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
3
|
+
# you may not use this file except in compliance with the License.
|
4
|
+
# You may obtain a copy of the License at
|
5
|
+
#
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
#
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
11
|
+
# See the License for the specific language governing permissions and
|
12
|
+
# limitations under the License.
|
13
|
+
#
|
14
|
+
require 'open-uri'
|
15
|
+
require 'json'
|
16
|
+
|
17
|
+
class Fluent::SplunkExOutput < Fluent::Output
|
18
|
+
|
19
|
+
SOCKET_TRY_MAX = 3
|
20
|
+
|
21
|
+
Fluent::Plugin.register_output('splunk_ex', self)
|
22
|
+
|
23
|
+
include Fluent::SetTagKeyMixin
|
24
|
+
config_set_default :include_tag_key, false
|
25
|
+
|
26
|
+
include Fluent::SetTimeKeyMixin
|
27
|
+
config_set_default :include_time_key, false
|
28
|
+
|
29
|
+
config_param :host, :string, :default => 'localhost'
|
30
|
+
config_param :port, :string, :default => 9997
|
31
|
+
config_param :output_format, :string, :default => 'json'
|
32
|
+
|
33
|
+
config_param :test_mode, :bool, :default => false
|
34
|
+
|
35
|
+
# To support log_level option implemented by Fluentd v0.10.43
|
36
|
+
unless method_defined?(:log)
|
37
|
+
define_method(:log) { $log }
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def configure(conf)
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def start
|
46
|
+
super
|
47
|
+
|
48
|
+
if @output_format == 'kv'
|
49
|
+
@format_fn = self.class.method(:format_kv)
|
50
|
+
elsif @output_format == 'logentries'
|
51
|
+
@format_fn = self.class.method(:format_logentries)
|
52
|
+
else
|
53
|
+
@format_fn = self.class.method(:format_json)
|
54
|
+
end
|
55
|
+
|
56
|
+
if @test_mode
|
57
|
+
@send_data = proc { |text| log.trace("test mode text: #{text}") }
|
58
|
+
else
|
59
|
+
begin
|
60
|
+
@splunk_connection = TCPSocket.open(@host, @port)
|
61
|
+
rescue Errno::ECONNREFUSED
|
62
|
+
# we'll try again when data is sent
|
63
|
+
end
|
64
|
+
@send_data = self.method(:splunk_send)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def shutdown
|
71
|
+
super
|
72
|
+
if !@test_mode && @splunk_connection.respond_to?(:close)
|
73
|
+
@splunk_connection.close
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def emit(tag, es, chain)
|
79
|
+
chain.next
|
80
|
+
es.each {|time,record|
|
81
|
+
@send_data.call( @format_fn.call(record) )
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
# =================================================================
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
def self.format_kv(record)
|
90
|
+
kv_out_str = ''
|
91
|
+
record.each { |k, v|
|
92
|
+
kv_out_str << sprintf('%s=%s ', URI::encode(k), URI::encode(v.to_s))
|
93
|
+
}
|
94
|
+
kv_out_str
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.format_logentries(record)
|
98
|
+
label = record["kubernetes"]["labels"]["logentries"]
|
99
|
+
message = record["message"]
|
100
|
+
le_out_str = label + " " + message
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.format_json(record)
|
104
|
+
json_str = record.to_json
|
105
|
+
end
|
106
|
+
|
107
|
+
def splunk_send(text, try_count=0)
|
108
|
+
log.debug("splunk_send: #{text}")
|
109
|
+
|
110
|
+
successful_send = false
|
111
|
+
try_count = 0
|
112
|
+
|
113
|
+
while (!successful_send && try_count < SOCKET_TRY_MAX)
|
114
|
+
begin
|
115
|
+
@splunk_connection.puts(text)
|
116
|
+
successful_send = true
|
117
|
+
|
118
|
+
rescue NoMethodError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EPIPE => se
|
119
|
+
log.error("splunk_send - socket send retry (#{try_count}) failed: #{se}")
|
120
|
+
try_count = try_count + 1
|
121
|
+
|
122
|
+
successful_reopen = false
|
123
|
+
while (!successful_reopen && try_count < SOCKET_TRY_MAX)
|
124
|
+
begin
|
125
|
+
# Try reopening
|
126
|
+
@splunk_connection = TCPSocket.open(@host, @port)
|
127
|
+
successful_reopen = true
|
128
|
+
rescue Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EPIPE => se
|
129
|
+
log.error("splunk_send - socket open retry (#{try_count}) failed: #{se}")
|
130
|
+
try_count = try_count + 1
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
if !successful_send
|
137
|
+
log.fatal("splunk_send - retry of sending data failed after #{SOCKET_TRY_MAX} chances.")
|
138
|
+
log.warn(text)
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
end
|
145
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require_relative 'spec_helper'
|
3
|
+
require 'benchmark'
|
4
|
+
Fluent::Test.setup
|
5
|
+
|
6
|
+
def create_driver(config, tag = 'foo.bar')
|
7
|
+
Fluent::Test::OutputTestDriver.new(Fluent::SplunkExOutput, tag).configure(config)
|
8
|
+
end
|
9
|
+
|
10
|
+
# setup
|
11
|
+
single_key_message = {
|
12
|
+
'msg' => 'testing some data'
|
13
|
+
}
|
14
|
+
|
15
|
+
multi_key_message = {
|
16
|
+
'msg' => 'testing some data',
|
17
|
+
'chars' => 'let"s put !@#$%^&*()-= some weird :\'?><,./ characters',
|
18
|
+
'dt' => '2014/04/03T07:02:11.124202',
|
19
|
+
'debug_line' => 24,
|
20
|
+
'debug_file' => '/some/path/to/myFile.py',
|
21
|
+
'statsd_key' => 'fluent_plugin_splunk_ex',
|
22
|
+
'statsd_timing' => 0.234,
|
23
|
+
'statsd_type' => 'timing',
|
24
|
+
'tx' => '280c3e80-bb6c-11e3-a5e2-0800200c9a66',
|
25
|
+
'host' => 'my01.cool.server.com'
|
26
|
+
}
|
27
|
+
|
28
|
+
time = Time.now.to_i
|
29
|
+
|
30
|
+
driver_kv = create_driver(%[
|
31
|
+
log_level fatal
|
32
|
+
test_mode true
|
33
|
+
output_format kv
|
34
|
+
])
|
35
|
+
|
36
|
+
driver_json = create_driver(%[
|
37
|
+
log_level fatal
|
38
|
+
test_mode true
|
39
|
+
output_format json
|
40
|
+
])
|
41
|
+
|
42
|
+
driver_kv_time = create_driver(%[
|
43
|
+
log_level fatal
|
44
|
+
test_mode true
|
45
|
+
output_format kv
|
46
|
+
time_key myKey
|
47
|
+
include_time_key true
|
48
|
+
])
|
49
|
+
|
50
|
+
driver_json_time = create_driver(%[
|
51
|
+
log_level fatal
|
52
|
+
test_mode true
|
53
|
+
output_format json
|
54
|
+
time_key myKey
|
55
|
+
include_time_key true
|
56
|
+
])
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
# bench
|
61
|
+
n = 10000
|
62
|
+
Benchmark.bm(7) do |x|
|
63
|
+
x.report("single_kv ") { driver_kv.run { n.times { driver_kv.emit( single_key_message, time) } } }
|
64
|
+
x.report("single_kv_time ") { driver_kv_time.run { n.times { driver_kv_time.emit( single_key_message, time) } } }
|
65
|
+
x.report("single_json ") { driver_json.run { n.times { driver_json.emit( single_key_message, time) } } }
|
66
|
+
x.report("single_json_time") { driver_json_time.run { n.times { driver_json_time.emit(single_key_message, time) } } }
|
67
|
+
|
68
|
+
x.report("multi_kv ") { driver_kv.run { n.times { driver_kv.emit( multi_key_message, time ) } } }
|
69
|
+
x.report("multi_kv_time ") { driver_kv_time.run { n.times { driver_kv_time.emit( multi_key_message, time ) } } }
|
70
|
+
x.report("multi_json ") { driver_json.run { n.times { driver_json.emit( multi_key_message, time ) } } }
|
71
|
+
x.report("multi_json_time ") { driver_json_time.run { n.times { driver_json_time.emit(multi_key_message, time ) } } }
|
72
|
+
|
73
|
+
end
|
74
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'coveralls'
|
2
|
+
Coveralls.wear!
|
3
|
+
|
4
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
5
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
6
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
7
|
+
# loaded once.
|
8
|
+
#
|
9
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
config.filter_run :focus
|
14
|
+
|
15
|
+
# Run specs in random order to surface order dependencies. If you find an
|
16
|
+
# order dependency and want to debug it, you can fix the order by providing
|
17
|
+
# the seed, which is printed after each run.
|
18
|
+
# --seed 1234
|
19
|
+
config.order = 'random'
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'fluent/test'
|
23
|
+
|
24
|
+
require 'fluent/plugin/out_splunk_ex'
|
25
|
+
|
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-splunk-ex-logentries
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1.logentries
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Trevor Gattis
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: fluentd
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.10.17
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.10.17
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry-nav
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Splunk output plugin for Fluent event collector. It supports reconnecting
|
98
|
+
on socket failure as well as exporting the data as json or in key/value pairs. Modified
|
99
|
+
to produce output format fit for Logentries.
|
100
|
+
email: github@trevorgattis.com
|
101
|
+
executables: []
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- ".travis.yml"
|
106
|
+
- Gemfile
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- fluent-plugin-splunk-ex.gemspec
|
110
|
+
- lib/fluent/plugin/out_splunk_ex.rb
|
111
|
+
- spec/out_splunk_ex_spec.rb
|
112
|
+
- spec/spec_helper.rb
|
113
|
+
homepage: https://github.com/Indrius/fluent-plugin-splunk-ex
|
114
|
+
licenses:
|
115
|
+
- APLv2
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: 1.3.1
|
131
|
+
requirements: []
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 2.7.3
|
134
|
+
signing_key:
|
135
|
+
specification_version: 4
|
136
|
+
summary: Splunk output plugin for Fluent event collector. It supports reconnecting
|
137
|
+
on socket failure as well as exporting the data as json or in key/value pairs. Modified
|
138
|
+
to produce output format fit for Logentries.
|
139
|
+
test_files: []
|