ffwd-collectd 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.
- checksums.yaml +7 -0
- data/lib/ffwd/plugin/collectd/connection.rb +83 -0
- data/lib/ffwd/plugin/collectd/parser.rb +159 -0
- data/lib/ffwd/plugin/collectd/types_db.rb +57 -0
- data/lib/ffwd/plugin/collectd/version.rb +22 -0
- data/lib/ffwd/plugin/collectd.rb +50 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 56020d48d93dc000931a007ace619ad887135b62
|
4
|
+
data.tar.gz: 62204ed7e4b07dd2caec921729cce2b9cfdafdf2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 227f6d4c8a2e86d72f694b2460296108cd171d037f82974a0c5ec721006b2201eeecd84e7bdc443e43e4f06efcf59350b2725813104ce6f5d2af670904a271f8
|
7
|
+
data.tar.gz: 5f881f021cc072c3a200e1e9240d1bef04fea22a874c465d97e149d3eff1fbd62fa0b60e2aab00a0bc1565ba2bb628d575b030ace96418a5bac2f4653332b124
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
require 'ffwd/logging'
|
17
|
+
require 'ffwd/connection'
|
18
|
+
|
19
|
+
require_relative 'parser'
|
20
|
+
|
21
|
+
module FFWD::Plugin::Collectd
|
22
|
+
class Connection < FFWD::Connection
|
23
|
+
include FFWD::Logging
|
24
|
+
|
25
|
+
def self.plugin_type
|
26
|
+
"collectd_in"
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize bind, core, types_db
|
30
|
+
@bind = bind
|
31
|
+
@core = core
|
32
|
+
@types_db = types_db
|
33
|
+
end
|
34
|
+
|
35
|
+
def receive_data(data)
|
36
|
+
Parser.parse(data) do |metric|
|
37
|
+
plugin_key = metric[:plugin]
|
38
|
+
type_key = metric[:type]
|
39
|
+
|
40
|
+
if instance = metric[:plugin_instance] and not instance.empty?
|
41
|
+
plugin_key = "#{plugin_key}-#{instance}"
|
42
|
+
end
|
43
|
+
|
44
|
+
if instance = metric[:type_instance] and not instance.empty?
|
45
|
+
type_key = "#{type_key}-#{instance}"
|
46
|
+
end
|
47
|
+
|
48
|
+
key = "#{plugin_key}/#{type_key}"
|
49
|
+
|
50
|
+
values = metric[:values]
|
51
|
+
|
52
|
+
time = metric[:time]
|
53
|
+
host = metric[:host]
|
54
|
+
|
55
|
+
# Just add a running integer to the end of the key, the 'correct'
|
56
|
+
# solution would have been to read, parse and match from a types.db.
|
57
|
+
#
|
58
|
+
# http://collectd.org/documentation/manpages/types.db.5.shtml
|
59
|
+
if values.size > 1
|
60
|
+
values.each_with_index do |v, i|
|
61
|
+
if @types_db and name = @types_db.get_name(type_key, i)
|
62
|
+
index_key = name
|
63
|
+
else
|
64
|
+
index_key = i.to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
@core.input.metric(
|
68
|
+
:key => "#{key}_#{index_key}", :time => time, :value => v[1],
|
69
|
+
:host => host)
|
70
|
+
@bind.increment :received_metrics
|
71
|
+
end
|
72
|
+
else
|
73
|
+
v = values[0]
|
74
|
+
@core.input.metric(
|
75
|
+
:key => key, :time => time, :value => v[1], :host => host)
|
76
|
+
@bind.increment :received_metrics
|
77
|
+
end
|
78
|
+
end
|
79
|
+
rescue => e
|
80
|
+
log.error "Failed to receive data", e
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
require 'ffwd/logging'
|
17
|
+
|
18
|
+
module FFWD::Plugin::Collectd
|
19
|
+
# An parser implementation of
|
20
|
+
# https://collectd.org/wiki/index.php/Binary_protocol
|
21
|
+
module Parser
|
22
|
+
include FFWD::Logging
|
23
|
+
|
24
|
+
HOST = 0x0000
|
25
|
+
TIME = 0x0001
|
26
|
+
TIME_HR = 0x0008
|
27
|
+
PLUGIN = 0x0002
|
28
|
+
PLUGIN_INSTANCE = 0x0003
|
29
|
+
TYPE = 0x0004
|
30
|
+
TYPE_INSTANCE = 0x0005
|
31
|
+
VALUES = 0x0006
|
32
|
+
INTERVAL = 0x0007
|
33
|
+
INTERVAL_HR = 0x0009
|
34
|
+
MESSAGE = 0x0100
|
35
|
+
SEVERITY = 0x0101
|
36
|
+
|
37
|
+
COUNTER = 0
|
38
|
+
GAUGE = 1
|
39
|
+
DERIVE = 2
|
40
|
+
ABSOLUTE = 3
|
41
|
+
|
42
|
+
SB64 = 0x8000000000000000
|
43
|
+
B64 = 0x10000000000000000
|
44
|
+
|
45
|
+
FACTOR_HR = 2**30
|
46
|
+
|
47
|
+
def self.unsigned_integer data
|
48
|
+
high, low = data.unpack("NN")
|
49
|
+
((high << 32) | low)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.signed_integer data
|
53
|
+
us = unsigned_integer(data)
|
54
|
+
|
55
|
+
if (us & SB64) == SB64
|
56
|
+
us - B64
|
57
|
+
else
|
58
|
+
us
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.values frame, i, size
|
63
|
+
n = frame[i + 4, 2].unpack("n")[0]
|
64
|
+
|
65
|
+
result = []
|
66
|
+
|
67
|
+
types = frame[i + 6, n].unpack("C" * n)
|
68
|
+
|
69
|
+
types.each_with_index do |type, j|
|
70
|
+
o = 6 + n + (j * 8)
|
71
|
+
data = frame[i + o, 8]
|
72
|
+
|
73
|
+
case type
|
74
|
+
when COUNTER
|
75
|
+
result << [:counter, self.unsigned_integer(data)]
|
76
|
+
when GAUGE
|
77
|
+
result << [:gauge, data.unpack("E")[0]]
|
78
|
+
when DERIVE
|
79
|
+
result << [:derive, self.signed_integer(data)]
|
80
|
+
when ABSOLUTE
|
81
|
+
result << [:absolute, self.unsigned_integer(data)]
|
82
|
+
else
|
83
|
+
raise "unkonwn value type: #{type}"
|
84
|
+
end
|
85
|
+
|
86
|
+
j += 1
|
87
|
+
end
|
88
|
+
|
89
|
+
result
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.string frame, i, size
|
93
|
+
frame[4 + i, (size - 5)]
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.numeric frame, i, size
|
97
|
+
unsigned_integer frame[4 + i, 8]
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.time_high_res frame, i, size
|
101
|
+
Time.at(numeric(frame, i, size).to_f / FACTOR_HR)
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.interval_high_res frame, i, size
|
105
|
+
numeric(frame, i, size).to_f / FACTOR_HR
|
106
|
+
end
|
107
|
+
|
108
|
+
# Maintain a current frame, and yield a copy of it to the subscribing
|
109
|
+
# block.
|
110
|
+
#
|
111
|
+
# Reading a 'values' part is the indicator that a block is 'ready'.
|
112
|
+
def self.parse frame
|
113
|
+
raise "invalid frame" if frame.size < 4
|
114
|
+
|
115
|
+
current = {}
|
116
|
+
|
117
|
+
i = 0
|
118
|
+
|
119
|
+
loop do
|
120
|
+
break if i >= frame.size
|
121
|
+
|
122
|
+
type, size = frame[i,4].unpack("nn")
|
123
|
+
|
124
|
+
case type
|
125
|
+
when HOST
|
126
|
+
current[:host] = self.string(frame, i, size)
|
127
|
+
when TIME
|
128
|
+
current[:time] = Time.at(self.numeric(frame, i, size))
|
129
|
+
when TIME_HR
|
130
|
+
current[:time] = self.time_high_res(frame, i, size)
|
131
|
+
when PLUGIN
|
132
|
+
current[:plugin] = self.string(frame, i, size)
|
133
|
+
when PLUGIN_INSTANCE
|
134
|
+
current[:plugin_instance] = self.string(frame, i, size)
|
135
|
+
when TYPE
|
136
|
+
current[:type] = self.string(frame, i, size)
|
137
|
+
when TYPE_INSTANCE
|
138
|
+
current[:type_instance] = self.string(frame, i, size)
|
139
|
+
when VALUES
|
140
|
+
values = self.values(frame, i, size)
|
141
|
+
current[:values] = values
|
142
|
+
yield current
|
143
|
+
when INTERVAL
|
144
|
+
current[:interval] = self.numeric(frame, i, size).to_f
|
145
|
+
when INTERVAL_HR
|
146
|
+
current[:interval] = self.interval_high_res(frame, i, size)
|
147
|
+
when MESSAGE
|
148
|
+
current[:message] = self.string(frame, i, size)
|
149
|
+
when SEVERITY
|
150
|
+
current[:severity] = self.numeric(frame, i, size)
|
151
|
+
else
|
152
|
+
log.warning("cannot understand type: #{type}")
|
153
|
+
end
|
154
|
+
|
155
|
+
i += size
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
module FFWD::Plugin::Collectd
|
17
|
+
# A minimal implementation of a reader for collectd's types.db
|
18
|
+
#
|
19
|
+
# http://collectd.org/documentation/manpages/types.db.5.shtml
|
20
|
+
class TypesDB
|
21
|
+
def initialize database
|
22
|
+
@database = database
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_name key, i
|
26
|
+
unless entry = @database[key]
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
unless type_spec = entry[i]
|
31
|
+
return nil
|
32
|
+
end
|
33
|
+
|
34
|
+
type_spec[0]
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.open path
|
38
|
+
return nil unless File.file? path
|
39
|
+
|
40
|
+
database = {}
|
41
|
+
|
42
|
+
File.open(path) do |f|
|
43
|
+
f.readlines.each do |line|
|
44
|
+
next if line.start_with? "#"
|
45
|
+
parts = line.split(/[\t ]+/, 2)
|
46
|
+
next unless parts.size == 2
|
47
|
+
key, value_specs = parts
|
48
|
+
value_specs = value_specs.split(",").map(&:strip)
|
49
|
+
value_specs = value_specs.map{|s| s.split(':')}
|
50
|
+
database[key] = value_specs
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
new database
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
module FFWD
|
17
|
+
module Plugin
|
18
|
+
module Collectd
|
19
|
+
VERSION = "0.1.0"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# $LICENSE
|
2
|
+
# Copyright 2013-2014 Spotify AB. All rights reserved.
|
3
|
+
#
|
4
|
+
# The contents of this file are licensed under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations under
|
14
|
+
# the License.
|
15
|
+
|
16
|
+
require 'ffwd/plugin'
|
17
|
+
require 'ffwd/protocol'
|
18
|
+
require 'ffwd/logging'
|
19
|
+
|
20
|
+
require_relative 'collectd/connection'
|
21
|
+
require_relative 'collectd/types_db'
|
22
|
+
|
23
|
+
module FFWD::Plugin::Collectd
|
24
|
+
include FFWD::Plugin
|
25
|
+
include FFWD::Logging
|
26
|
+
|
27
|
+
register_plugin "collectd"
|
28
|
+
|
29
|
+
DEFAULT_HOST = "localhost"
|
30
|
+
DEFAULT_PORT = 25826
|
31
|
+
DEFAULT_TYPES_DB = "/usr/share/collectd/types.db"
|
32
|
+
|
33
|
+
def self.setup_input opts, core
|
34
|
+
opts[:host] ||= DEFAULT_HOST
|
35
|
+
opts[:port] ||= DEFAULT_PORT
|
36
|
+
opts[:types_db] ||= DEFAULT_TYPES_DB
|
37
|
+
protocol = FFWD.parse_protocol(opts[:protocol] || "udp")
|
38
|
+
types_db = TypesDB.open opts[:types_db]
|
39
|
+
protocol.bind opts, core, log, Connection, types_db
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.setup_tunnel opts, core, tunnel
|
43
|
+
opts[:port] ||= DEFAULT_PORT
|
44
|
+
opts[:types_db] ||= DEFAULT_TYPES_DB
|
45
|
+
protocol = FFWD.parse_protocol(opts[:protocol] || "udp")
|
46
|
+
protocol.tunnel log, opts, Connection
|
47
|
+
types_db = TypesDB.open opts[:types_db]
|
48
|
+
protocol.bind opts, core, tunnel, log, Connection, types_db
|
49
|
+
end
|
50
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ffwd-collectd
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John-John Tedro
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffwd
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- udoprog@spotify.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- lib/ffwd/plugin/collectd/parser.rb
|
35
|
+
- lib/ffwd/plugin/collectd/types_db.rb
|
36
|
+
- lib/ffwd/plugin/collectd/connection.rb
|
37
|
+
- lib/ffwd/plugin/collectd/version.rb
|
38
|
+
- lib/ffwd/plugin/collectd.rb
|
39
|
+
homepage: https://github.com/spotify/ffwd
|
40
|
+
licenses:
|
41
|
+
- Apache 2.0
|
42
|
+
metadata: {}
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 2.0.3
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: collectd support for FFWD.
|
63
|
+
test_files: []
|