fluent-plugin-collectd-unroll 0.1.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.
- data/ChangeLog +3 -0
- data/Gemfile +3 -0
- data/README.md +52 -0
- data/Rakefile +12 -0
- data/VERSION +1 -0
- data/fluent-plugin-collectd-unroll.gemspec +22 -0
- data/lib/fluent/plugin/out_collectd_unroll.rb +57 -0
- data/sample-zeus-config/td-agent.conf +69 -0
- data/test/out_collectd_unroll.rb +100 -0
- metadata +86 -0
data/ChangeLog
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Output filter plugin to rewrite Collectd JSON output to unroll into a flat json
|
2
|
+
|
3
|
+
Rewrites the message coming from Collectd to store as a flat json. Can be used in Elasticsearch to display metrics.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Use RubyGems:
|
8
|
+
|
9
|
+
gem install fluent-plugin-collectd-unroll
|
10
|
+
|
11
|
+
## Configuration
|
12
|
+
|
13
|
+
<match pattern>
|
14
|
+
type collectd_unroll
|
15
|
+
</match>
|
16
|
+
|
17
|
+
If following record is passed:
|
18
|
+
|
19
|
+
```js
|
20
|
+
[{"time" => 1000, "host" => 'host_v', "interval" => 5, "plugin" => 'plugin_v', "plugin_instance" => 'plugin_instance_v', "type" => 'type_v', "type_instance" => 'type_instance_v', "values" => ['v1', 'v2'], "dsnames" => ['n1', 'n2'], "dstypes" => ['t1', 't2']}]
|
21
|
+
```
|
22
|
+
|
23
|
+
then you got new record like below:
|
24
|
+
|
25
|
+
```js
|
26
|
+
[{"n1"=>"v1", "n2"=>"v2"}]
|
27
|
+
```
|
28
|
+
|
29
|
+
and the record tag will be changed to
|
30
|
+
|
31
|
+
```js
|
32
|
+
host_v.plugin_v.plugin_instance_v.type_v.type_instance_v
|
33
|
+
```
|
34
|
+
|
35
|
+
Empty values in "plugin", "plugin_instance", "type" or "type_instance" will not be copied into the new tag name
|
36
|
+
|
37
|
+
|
38
|
+
## WARNING
|
39
|
+
|
40
|
+
* This plugin was written to deal with a specific use-case, might not be the best fit for everyone. If you need more configurability/features, create a PR
|
41
|
+
|
42
|
+
|
43
|
+
## Copyright
|
44
|
+
|
45
|
+
<table>
|
46
|
+
<tr>
|
47
|
+
<td>Author</td><td>Manoj Sharma <vigyanik@gmail.com></td>
|
48
|
+
</tr>
|
49
|
+
<tr>
|
50
|
+
<td>License</td><td>MIT License</td>
|
51
|
+
</tr>
|
52
|
+
</table>
|
data/Rakefile
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "fluent-plugin-collectd-unroll"
|
6
|
+
gem.description = "Output filter plugin to rewrite Collectd JSON output to flat json"
|
7
|
+
gem.homepage = "https://github.com/giannello/fluent-plugin-collectd-unroll"
|
8
|
+
gem.summary = gem.description
|
9
|
+
gem.version = File.read("VERSION").strip
|
10
|
+
gem.authors = ["Manoj Sharma"]
|
11
|
+
gem.email = "vigyanik@gmail.com"
|
12
|
+
gem.has_rdoc = false
|
13
|
+
#gem.platform = Gem::Platform::RUBY
|
14
|
+
gem.license = 'MIT'
|
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_development_dependency "rake", ">= 0.9.2"
|
22
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Fluent
|
2
|
+
class CollectdUnrollOutput < Output
|
3
|
+
Fluent::Plugin.register_output('collectd_unroll', self)
|
4
|
+
|
5
|
+
config_param :remove_tag_prefix, :string, :default => nil
|
6
|
+
config_param :add_tag_prefix, :string, :default => nil
|
7
|
+
|
8
|
+
|
9
|
+
def emit(tag, es, chain)
|
10
|
+
tag = update_tag(tag)
|
11
|
+
es.each { |time, record|
|
12
|
+
Engine.emit(tag, time, normalize_record(record))
|
13
|
+
}
|
14
|
+
|
15
|
+
chain.next
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def update_tag(tag)
|
20
|
+
if remove_tag_prefix
|
21
|
+
if remove_tag_prefix == tag
|
22
|
+
tag = ''
|
23
|
+
elsif tag.to_s.start_with?(remove_tag_prefix+'.')
|
24
|
+
tag = tag[remove_tag_prefix.length+1 .. -1]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
if add_tag_prefix
|
28
|
+
tag = tag && tag.length > 0 ? "#{add_tag_prefix}.#{tag}" : add_tag_prefix
|
29
|
+
end
|
30
|
+
return tag
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def normalize_record(record)
|
36
|
+
if record.nil?
|
37
|
+
return record
|
38
|
+
end
|
39
|
+
if !(record.has_key?('values')) || !(record.has_key?('dsnames')) || !(record.has_key?('dstypes')) || !(record.has_key?('host')) || !(record.has_key?('plugin')) || !(record.has_key?('plugin_instance')) || !(record.has_key?('type')) || !(record.has_key?('type_instance'))
|
40
|
+
return record
|
41
|
+
end
|
42
|
+
|
43
|
+
record['values'].each_with_index { |value, index|
|
44
|
+
@tags = [record['host'].gsub(".","/"), record['plugin'], record['plugin_instance'], record['type'], record['type_instance'], record['dsnames'][index]]
|
45
|
+
tag = @tags.join(".").squeeze(".").gsub(/\.$/, '')
|
46
|
+
record[tag] = value
|
47
|
+
record[record['dsnames'][index]] = value
|
48
|
+
record['dstype_' + record['dsnames'][index]] = record['dstypes'][index]
|
49
|
+
record['dstype'] = record['dstypes'][index]
|
50
|
+
}
|
51
|
+
record.delete('dstypes')
|
52
|
+
record.delete('dsnames')
|
53
|
+
record.delete('values')
|
54
|
+
record
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
## match tag=debug.** and dump to console
|
2
|
+
<match debug.**>
|
3
|
+
type stdout
|
4
|
+
</match>
|
5
|
+
|
6
|
+
####
|
7
|
+
## Source descriptions:
|
8
|
+
##
|
9
|
+
|
10
|
+
## built-in TCP input
|
11
|
+
## @see http://docs.fluentd.org/articles/in_forward
|
12
|
+
<source>
|
13
|
+
type forward
|
14
|
+
</source>
|
15
|
+
|
16
|
+
|
17
|
+
# HTTP input
|
18
|
+
# POST http://localhost:8888/<tag>?json=<json>
|
19
|
+
# POST http://localhost:8888/td.myapp.login?json={"user"%3A"me"}
|
20
|
+
# @see http://docs.fluentd.org/articles/in_http
|
21
|
+
# receives collectd input
|
22
|
+
<source>
|
23
|
+
type http
|
24
|
+
port 8888
|
25
|
+
</source>
|
26
|
+
|
27
|
+
## live debugging agent
|
28
|
+
<source>
|
29
|
+
type debug_agent
|
30
|
+
bind 127.0.0.1
|
31
|
+
port 24230
|
32
|
+
</source>
|
33
|
+
<match collectd>
|
34
|
+
type collectd_unroll
|
35
|
+
add_tag_prefix metrics_unrolled
|
36
|
+
</match>
|
37
|
+
|
38
|
+
<match metrics_unrolled.**>
|
39
|
+
type record_reformer
|
40
|
+
tag logs.collectd.zeushack085-2f586ba2
|
41
|
+
<record>
|
42
|
+
@timestamp ${time}
|
43
|
+
</record>
|
44
|
+
</match>
|
45
|
+
|
46
|
+
<source>
|
47
|
+
type syslog
|
48
|
+
port 42185
|
49
|
+
tag syslog
|
50
|
+
</source>
|
51
|
+
|
52
|
+
<match syslog.**>
|
53
|
+
type record_reformer
|
54
|
+
tag logs.${tag}.zeushack085-2f586ba2
|
55
|
+
<record>
|
56
|
+
@timestamp ${time}
|
57
|
+
</record>
|
58
|
+
</match>
|
59
|
+
|
60
|
+
<match logs.**>
|
61
|
+
type secure_forward
|
62
|
+
shared_key cisco_zeus_log_metric_pipline
|
63
|
+
self_hostname fluentd-client1.ciscozeus.io
|
64
|
+
secure false
|
65
|
+
keepalive 10
|
66
|
+
<server>
|
67
|
+
host data01.ciscozeus.io
|
68
|
+
</server>
|
69
|
+
</match>
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'fluent/test'
|
2
|
+
require 'fluent/plugin/out_collectd_unroll'
|
3
|
+
|
4
|
+
|
5
|
+
class CollectdUnrollOutputTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
Fluent::Test.setup
|
8
|
+
end
|
9
|
+
|
10
|
+
CONFIG = %[
|
11
|
+
type collectd_unroll
|
12
|
+
tag foo.filtered
|
13
|
+
]
|
14
|
+
|
15
|
+
def create_driver(conf = CONFIG)
|
16
|
+
Fluent::Test::OutputTestDriver.new(Fluent::CollectdUnrollOutput, tag='test_tag').configure(conf)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_rewrite_tag
|
20
|
+
d = create_driver %[
|
21
|
+
type collectd_unroll
|
22
|
+
]
|
23
|
+
|
24
|
+
d.run do
|
25
|
+
d.emit([{
|
26
|
+
"time" => 1000, "host" => 'host', "interval" => 5,
|
27
|
+
"plugin" => 'plugin', "plugin_instance" => 'plugin_instance',
|
28
|
+
"type" => 'type', "type_instance" => 'type_instance',
|
29
|
+
"values" => ['v1', 'v2'], "dsnames" => ['n1', 'n2'], "dstypes" => ['t1', 't2']
|
30
|
+
}])
|
31
|
+
d.emit([{
|
32
|
+
"time" => 1000, "host" => 'host', "interval" => 5,
|
33
|
+
"plugin" => 'plugin', "plugin_instance" => '',
|
34
|
+
"type" => 'type', "type_instance" => 'type_instance',
|
35
|
+
"values" => ['v1', 'v2'], "dsnames" => ['n1', 'n2'], "dstypes" => ['t1', 't2']
|
36
|
+
}])
|
37
|
+
d.emit([{
|
38
|
+
"time" => 1000, "host" => 'host', "interval" => 5,
|
39
|
+
"plugin" => 'plugin', "plugin_instance" => 'plugin_instance',
|
40
|
+
"type" => '', "type_instance" => 'type_instance',
|
41
|
+
"values" => ['v1', 'v2'], "dsnames" => ['n1', 'n2'], "dstypes" => ['t1', 't2']
|
42
|
+
}])
|
43
|
+
d.emit([{
|
44
|
+
"time" => 1000, "host" => 'host', "interval" => 5,
|
45
|
+
"plugin" => 'plugin', "plugin_instance" => 'plugin_instance',
|
46
|
+
"type" => 'type', "type_instance" => '',
|
47
|
+
"values" => ['v1', 'v2'], "dsnames" => ['n1', 'n2'], "dstypes" => ['t1', 't2']
|
48
|
+
}])
|
49
|
+
end
|
50
|
+
|
51
|
+
assert_equal 4, d.emits.length
|
52
|
+
assert_equal "test_tag.host.plugin.plugin_instance.type.type_instance", d.emits[0][0]
|
53
|
+
assert_equal "test_tag.host.plugin.type.type_instance", d.emits[1][0]
|
54
|
+
assert_equal "test_tag.host.plugin.plugin_instance.type_instance", d.emits[2][0]
|
55
|
+
assert_equal "test_tag.host.plugin.plugin_instance.type", d.emits[3][0]
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_use_timestamp
|
59
|
+
d = create_driver %[
|
60
|
+
type collectd_unroll
|
61
|
+
]
|
62
|
+
|
63
|
+
d.run do
|
64
|
+
d.emit([{
|
65
|
+
"time" => 1000, "host" => 'host', "interval" => 5,
|
66
|
+
"plugin" => 'plugin', "plugin_instance" => 'plugin_instance',
|
67
|
+
"type" => 'type', "type_instance" => 'type_instance',
|
68
|
+
"values" => ['v1', 'v2'], "dsnames" => ['n1', 'n2'], "dstypes" => ['t1', 't2']
|
69
|
+
}])
|
70
|
+
d.emit([{
|
71
|
+
"time" => 9999, "host" => 'host', "interval" => 5,
|
72
|
+
"plugin" => 'plugin', "plugin_instance" => '',
|
73
|
+
"type" => 'type', "type_instance" => 'type_instance',
|
74
|
+
"values" => ['v1', 'v2'], "dsnames" => ['n1', 'n2'], "dstypes" => ['t1', 't2']
|
75
|
+
}])
|
76
|
+
end
|
77
|
+
|
78
|
+
assert_equal 2, d.emits.length
|
79
|
+
assert_equal 1000, d.emits[0][1]
|
80
|
+
assert_equal 9999, d.emits[1][1]
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_normalize_record
|
84
|
+
d = create_driver %[
|
85
|
+
type collectd_unroll
|
86
|
+
]
|
87
|
+
|
88
|
+
d.run do
|
89
|
+
d.emit([{
|
90
|
+
"time" => 1000, "host" => 'v', "interval" => 5,
|
91
|
+
"plugin" => 'v', "plugin_instance" => 'v',
|
92
|
+
"type" => 'v', "type_instance" => 'v',
|
93
|
+
"values" => ['v1', 'v2'], "dsnames" => ['n1', 'n2'], "dstypes" => ['t1', 't2']
|
94
|
+
}])
|
95
|
+
end
|
96
|
+
|
97
|
+
assert_equal ({'n1'=>'v1','n2'=>'v2'} - d.records[0]).empty?, true
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-collectd-unroll
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Manoj Sharma
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-10-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fluentd
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.10.17
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.10.17
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.9.2
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.9.2
|
46
|
+
description: Output filter plugin to rewrite Collectd JSON output to flat json
|
47
|
+
email: vigyanik@gmail.com
|
48
|
+
executables: []
|
49
|
+
extensions: []
|
50
|
+
extra_rdoc_files: []
|
51
|
+
files:
|
52
|
+
- ChangeLog
|
53
|
+
- Gemfile
|
54
|
+
- README.md
|
55
|
+
- Rakefile
|
56
|
+
- VERSION
|
57
|
+
- fluent-plugin-collectd-unroll.gemspec
|
58
|
+
- lib/fluent/plugin/out_collectd_unroll.rb
|
59
|
+
- sample-zeus-config/td-agent.conf
|
60
|
+
- test/out_collectd_unroll.rb
|
61
|
+
homepage: https://github.com/giannello/fluent-plugin-collectd-unroll
|
62
|
+
licenses:
|
63
|
+
- MIT
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.8.23
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: Output filter plugin to rewrite Collectd JSON output to flat json
|
86
|
+
test_files: []
|