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 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: []