monitoring_protocols 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ea3d4b5a1ff69111426666e3e6c9365db1794ef2
4
+ data.tar.gz: f1792e58cbf6b9e78cc40d0c1fda80607d3d8914
5
+ SHA512:
6
+ metadata.gz: 87bc1ec3055c2d0424db2992e6195d8c14bcf06c555785d2fdee3dd74f4944afc4013b0a33235290708bbda1bfd8f35a0b1f337f8b3ef0e23c0562edad355a6d
7
+ data.tar.gz: 8155810e85f50e3d7f88b6bddbfbe998b2842a20c69fd258e7758723f56073cc8de1f0630893ff027063ef3f9480b8289734871289ece389f1f62587993eb29f
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ Gemfile.lock
5
+ coverage/
6
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
6
+
7
+ group(:test) do
8
+ gem 'eetee', '~> 0.0.9'
9
+ # gem 'eetee', path: '/Users/Schmurfy/Dev/personal/gems/eetee'
10
+ gem 'mocha', '~> 0.12.0'
11
+ gem 'factory_girl'
12
+ gem 'rb-blink1'
13
+
14
+ gem 'simplecov'
15
+ gem 'guard', '~> 1.8.1'
16
+ gem 'rb-fsevent'
17
+ gem 'growl'
18
+ end
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+
2
+ require 'eetee'
3
+ require 'blink1'
4
+
5
+ guard 'eetee', blink1: true do
6
+ watch(%r{^lib/monitoring_protocols/(.+)\.rb$}) { |m| "specs/unit/#{m[1]}_spec.rb" }
7
+ watch(%r{specs/.+\.rb$})
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Julien Ammous
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require "bundler/gem_tasks"
4
+
5
+ task :default => :test
6
+
7
+ task :test do
8
+
9
+ # do not generate coverage report under travis
10
+ unless ENV['TRAVIS']
11
+
12
+ require 'simplecov'
13
+ SimpleCov.command_name "E.T."
14
+ SimpleCov.start do
15
+ add_filter ".*_spec"
16
+ add_filter "/specs/helpers/"
17
+ add_filter "/example/"
18
+ end
19
+ end
20
+
21
+ require 'eetee'
22
+
23
+ runner = EEtee::Runner.new
24
+ runner.run_pattern('specs/**/*_spec.rb')
25
+ runner.report_results()
26
+
27
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path('../monitoring_protocols/core', __FILE__)
2
+
3
+ require File.expand_path('../monitoring_protocols/version', __FILE__)
4
+ require File.expand_path('../monitoring_protocols/struct', __FILE__)
5
+ require File.expand_path('../monitoring_protocols/parser', __FILE__)
6
+ require File.expand_path('../monitoring_protocols/builder', __FILE__)
7
+
8
+ require File.expand_path('../monitoring_protocols/collectd/msg', __FILE__)
9
+ require File.expand_path('../monitoring_protocols/collectd/builder', __FILE__)
10
+ require File.expand_path('../monitoring_protocols/collectd/parser', __FILE__)
11
+
12
+ require File.expand_path('../monitoring_protocols/json/parser', __FILE__)
13
+ require File.expand_path('../monitoring_protocols/json/builder', __FILE__)
14
+
15
+ require File.expand_path('../monitoring_protocols/msgpack/parser', __FILE__)
16
+
17
+
18
+ module MonitoringProtocols
19
+ def self.factory_file
20
+ File.expand_path('../../specs/factories.rb', __FILE__)
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ module MonitoringProtocols
2
+
3
+ class Builder
4
+
5
+ def initialize(points)
6
+ @points = points
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,96 @@
1
+ module MonitoringProtocols
2
+ module Collectd
3
+
4
+ class Builder
5
+ # part type
6
+ HOST = 0x0000
7
+ TIME = 0x0001
8
+ PLUGIN = 0x0002
9
+ PLUGIN_INSTANCE = 0x0003
10
+ TYPE = 0x0004
11
+ TYPE_INSTANCE = 0x0005
12
+ VALUES = 0x0006
13
+ INTERVAL = 0x0007
14
+ MESSAGE = 0x0100
15
+ SEVERITY = 0x0101
16
+
17
+ # data type
18
+ COUNTER = 0
19
+ GAUGE = 1
20
+ DERIVE = 2
21
+ ABSOLUTE = 3
22
+
23
+
24
+ attr_accessor :host, :time, :interval
25
+ attr_accessor :plugin, :plugin_instance
26
+ attr_accessor :type, :type_instance
27
+
28
+ # Encode a string (type 0, null terminated string)
29
+ def self.string(type, str)
30
+ str += "\000"
31
+ str_size = str.respond_to?(:bytesize) ? str.bytesize : str.size
32
+ [type, 4 + str_size].pack("nn") + str
33
+ end
34
+
35
+ # Encode an integer
36
+ def self.number(type, num)
37
+ [type, 12].pack("nn") + [num >> 32, num & 0xffffffff].pack("NN")
38
+ end
39
+
40
+ def self.values(types = [], values = [])
41
+ # values part header
42
+ ret = [VALUES, 4 + 2 + (values.size * 9), values.size].pack('nnn')
43
+
44
+ # types
45
+ ret << types.pack('C*')
46
+
47
+ # and the values
48
+ values.each.with_index do |v, i|
49
+ case types[i]
50
+ when COUNTER, ABSOLUTE, DERIVE
51
+ ret << [v >> 32, v & 0xffffffff].pack("NN")
52
+
53
+ when GAUGE
54
+ ret << [v].pack('E')
55
+
56
+ else
57
+ raise "unknown type: #{types[i]}"
58
+ end
59
+ end
60
+
61
+ ret
62
+ end
63
+
64
+ def initialize
65
+ @values = []
66
+ @values_type = []
67
+ end
68
+
69
+ def add_value(type, value)
70
+ raise(ArgumentError, "unknown type: #{type}") unless self.class.const_defined?(type.to_s.upcase)
71
+ data_type = self.class.const_get(type.to_s.upcase)
72
+
73
+ @values_type << data_type
74
+ @values << value
75
+ end
76
+
77
+ def build_packet
78
+ @pkt = self.class.string(HOST, @host)
79
+ @pkt << self.class.number(TIME, @time)
80
+ @pkt << self.class.number(INTERVAL, @interval)
81
+ @pkt << self.class.string(PLUGIN, @plugin)
82
+ @pkt << self.class.string(PLUGIN_INSTANCE, @plugin_instance)
83
+ @pkt << self.class.string(TYPE, @type)
84
+ @pkt << self.class.string(TYPE_INSTANCE, @type_instance)
85
+
86
+ @pkt << self.class.values(@values_type, @values)
87
+
88
+ @pkt
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
95
+ register_builder(:collectd, Collectd::Builder)
96
+ end
@@ -0,0 +1,106 @@
1
+ module MonitoringProtocols
2
+ module Collectd
3
+
4
+ # from collectd source code
5
+ # plugin.h
6
+ #
7
+ ### notification:
8
+ # int severity;
9
+ # cdtime_t time;
10
+ # char message[NOTIF_MAX_MSG_LEN];
11
+ # char host[DATA_MAX_NAME_LEN];
12
+ # char plugin[DATA_MAX_NAME_LEN];
13
+ # char plugin_instance[DATA_MAX_NAME_LEN];
14
+ # char type[DATA_MAX_NAME_LEN];
15
+ # char type_instance[DATA_MAX_NAME_LEN];
16
+ #
17
+ ### data
18
+ # value_t *values;
19
+ # int values_len;
20
+ # cdtime_t time;
21
+ # cdtime_t interval;
22
+ # char host[DATA_MAX_NAME_LEN];
23
+ # char plugin[DATA_MAX_NAME_LEN];
24
+ # char plugin_instance[DATA_MAX_NAME_LEN];
25
+ # char type[DATA_MAX_NAME_LEN];
26
+ # char type_instance[DATA_MAX_NAME_LEN];
27
+ #
28
+ class NetworkMessage < NetworkMessage
29
+ properties(
30
+ :time,
31
+ :host,
32
+ :plugin,
33
+ :plugin_instance,
34
+ :type,
35
+ :type_instance,
36
+
37
+ # data
38
+ :interval,
39
+ :values,
40
+
41
+ # notification
42
+ :message,
43
+ :severity
44
+ )
45
+
46
+ def notification?
47
+ !self.message.nil?
48
+ end
49
+
50
+ def data?
51
+ self.message.nil?
52
+ end
53
+
54
+ def value(index = 0)
55
+ values[index]
56
+ end
57
+
58
+ def plugin_display
59
+ if plugin_instance && !plugin_instance.empty?
60
+ "#{plugin}/#{plugin_instance}"
61
+ else
62
+ plugin
63
+ end
64
+ end
65
+
66
+ def type_display
67
+ if type_instance && !type_instance.empty?
68
+ "#{type}/#{type_instance}"
69
+ else
70
+ type
71
+ end
72
+ end
73
+ ##
74
+ # return a unique id for the measured data.
75
+ #
76
+ def measure_id
77
+ "#{host}-#{plugin_display}-#{type_display}"
78
+ end
79
+
80
+ def convert_content
81
+ common = {
82
+ time: time,
83
+ host: host,
84
+ app_name: plugin,
85
+ res_name: type,
86
+ metric_name: type_instance,
87
+ }
88
+
89
+ if data?
90
+ ret = DataPoint.new(common.merge!(
91
+ value: value
92
+ ))
93
+ else
94
+ ret = Notification.new(common.merge!(
95
+ severity: severity,
96
+ message: message
97
+ ))
98
+ end
99
+
100
+ [ret]
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+ end
@@ -0,0 +1,175 @@
1
+ module MonitoringProtocols
2
+ module Collectd
3
+
4
+ class Parser < Parser
5
+
6
+ # part type
7
+ HOST = 0x0000
8
+ TIME = 0x0001
9
+ TIME_HR = 0X0008
10
+ PLUGIN = 0x0002
11
+ PLUGIN_INSTANCE = 0x0003
12
+ TYPE = 0x0004
13
+ TYPE_INSTANCE = 0x0005
14
+ VALUES = 0x0006
15
+ INTERVAL = 0x0007
16
+ INTERVAL_HR = 0X0009
17
+ MESSAGE = 0x0100
18
+ SEVERITY = 0x0101
19
+
20
+ PART_TYPE_AS_STRING = {
21
+ HOST => 'host',
22
+ TIME => 'time',
23
+ TIME_HR => 'time_hr',
24
+ PLUGIN => 'plugin',
25
+ PLUGIN_INSTANCE => 'plugin_instance',
26
+ TYPE => 'type',
27
+ TYPE_INSTANCE => 'type_instance',
28
+ VALUES => 'values',
29
+ INTERVAL => 'interval',
30
+ INTERVAL_HR => 'interval_hr',
31
+ MESSAGE => 'message',
32
+ SEVERITY => 'severity'
33
+ }.freeze
34
+
35
+ STR_FIELDS = [HOST, PLUGIN, PLUGIN_INSTANCE, TYPE, TYPE_INSTANCE, MESSAGE]
36
+ INT_FIELDS = [TIME, TIME_HR, INTERVAL, INTERVAL_HR, SEVERITY]
37
+
38
+ COUNTER = 0x00
39
+ GAUGE = 0x01
40
+ DERIVE = 0x02
41
+ ABSOLUTE = 0x03
42
+
43
+ def self.parse_part_header(buffer)
44
+ type, length, rest = buffer.unpack('nna*')
45
+ [type, length - 4, rest]
46
+ end
47
+
48
+ INT64_MAX = (1 << 63)
49
+ INT64_SIGN_BIT = (1 << 64)
50
+
51
+ # uint to int
52
+ # "val = val - #{1 << nbits} if (val >= #{1 << (nbits - 1)})"
53
+ def self.parse_int64(buffer, signed = false)
54
+ # [v>>32, v & 0xffffffff].pack("NN")}.join
55
+
56
+ hi, lo, buffer = buffer.unpack("NNa*")
57
+ n = (hi << 32 | lo)
58
+
59
+ if signed && (n >= INT64_MAX)
60
+ n = n - INT64_SIGN_BIT
61
+ end
62
+
63
+ [n, buffer]
64
+ end
65
+
66
+ def self.parse_part(buffer)
67
+ type, length, buffer = parse_part_header(buffer)
68
+ case
69
+ when INT_FIELDS.include?(type) then val, buffer = parse_int64(buffer)
70
+ when STR_FIELDS.include?(type) then val, buffer = buffer.unpack("Z#{length}a*")
71
+ when type == VALUES then val, buffer = parse_part_values(length, buffer)
72
+ else
73
+ val, buffer = buffer.unpack("a#{length}a*")
74
+ raise ParseError, "unknown part: #{type}, data: #{val.inspect}"
75
+ end
76
+
77
+ # just convert to seconds
78
+ if (type == TIME_HR)
79
+ type = TIME
80
+ val = (val >> 30)
81
+ end
82
+
83
+ if (type == INTERVAL_HR)
84
+ type = INTERVAL
85
+ val = (val >> 30)
86
+ p [:interval, val]
87
+ end
88
+
89
+ [
90
+ PART_TYPE_AS_STRING[type],
91
+ val,
92
+ buffer
93
+ ]
94
+ end
95
+
96
+ def self.parse_part_values(length, buffer)
97
+ # first we need to read the types of all the values
98
+ values_count, buffer = buffer.unpack("na*")
99
+ *types, buffer = buffer.unpack("C#{values_count}a*")
100
+ values = types.map! do |type|
101
+ case type
102
+ when COUNTER, ABSOLUTE then val, buffer = parse_int64(buffer)
103
+ when GAUGE then val, buffer = buffer.unpack("Ea*")
104
+ when DERIVE then val, buffer = parse_int64(buffer, true)
105
+ end
106
+
107
+ val
108
+ end
109
+
110
+ [values, buffer]
111
+ end
112
+
113
+ COPY_FIELDS = [
114
+ :time,
115
+ :host,
116
+ :plugin,
117
+ :plugin_instance,
118
+ :type,
119
+ :type_instance,
120
+ :interval
121
+ ].freeze
122
+
123
+ def self.parse_packet(buffer, initial_values = {})
124
+ packet = NetworkMessage.new(initial_values, COPY_FIELDS)
125
+
126
+ begin
127
+ type, value, buffer = parse_part(buffer)
128
+ packet.send("#{type}=", value)
129
+ end until packet.message || packet.values
130
+
131
+ [packet, buffer]
132
+ end
133
+
134
+ def self.parse(buffer)
135
+ packets = []
136
+ last_packet = {}
137
+
138
+ # 4 = part header size
139
+ while buffer.bytesize >= 4
140
+ packet, buffer = parse_packet(buffer, last_packet)
141
+ packets << packet
142
+
143
+ last_packet = packet if packet.data?
144
+ end
145
+
146
+ packets
147
+ end
148
+
149
+ # def initialize
150
+ # @buffer = ""
151
+ # @last_packet = {}
152
+ # end
153
+
154
+ # def feed(data)
155
+ # ret = []
156
+
157
+ # @buffer << data
158
+ # if @buffer.bytesize >= 4
159
+ # pkt, @buffer = self.class.parse_packet(@buffer, @last_packet)
160
+ # if pkt.data?
161
+ # ret << pkt
162
+ # @last_packet = pack
163
+ # end
164
+ # end
165
+
166
+ # ret
167
+ # end
168
+
169
+ end
170
+
171
+
172
+ end
173
+
174
+ register_parser(:collectd, Collectd::Parser)
175
+ end