oml4r 2.9.0.2 → 2.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/{LICENSE → LICENSE.txt} +1 -1
- data/README.md +33 -25
- data/examples/oml4r-simple-example.rb +60 -0
- data/{lib/oml4r → examples}/oml4r-wlanconfig.rb +2 -1
- data/examples/oml4r-zabbix.rb +98 -0
- data/examples/test_types.rb +43 -0
- data/lib/oml4r/benchmark.rb +240 -0
- data/lib/oml4r/version.rb +11 -0
- data/lib/oml4r.rb +210 -158
- data/oml4r.gemspec +4 -13
- metadata +11 -7
- data/.yardopts +0 -2
- data/lib/oml4r/oml4r-simple-example.rb +0 -69
data/.gitignore
ADDED
data/{LICENSE → LICENSE.txt}
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright 2009-
|
1
|
+
Copyright 2009-2013 National ICT Australia (NICTA), Australia
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -31,42 +31,50 @@ Usage
|
|
31
31
|
|
32
32
|
### Initialisation, Injection and Tear-down
|
33
33
|
|
34
|
-
OML4R::init(ARGV,
|
34
|
+
OML4R::init(ARGV,
|
35
35
|
:appName => 'oml4rSimpleExample',
|
36
|
-
:
|
36
|
+
:domain => 'foo',
|
37
37
|
:nodeID => 'n1',
|
38
|
-
:omlServer => 'file:-'}
|
39
38
|
)
|
40
|
-
MyMP.inject("hello", 13, 37.)
|
39
|
+
MyMP.inject("hello", 13, 37.1)
|
41
40
|
OML4R::close()
|
41
|
+
|
42
|
+
### Multiple Channels
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
See examples files oml4r-simple-example.rb and oml4r-wlanconfig.rb.
|
44
|
+
It is sometimes desirable to send different measurement points to different collectors. OML4R supports
|
45
|
+
this with the 'channel' abstraction.
|
46
46
|
|
47
|
+
class A_MP < OML4R::MPBase
|
48
|
+
name :a
|
49
|
+
channel :default
|
50
|
+
|
51
|
+
param :a_val, :type => :int32
|
52
|
+
end
|
47
53
|
|
48
|
-
|
49
|
-
|
54
|
+
class B_MP < OML4R::MPBase
|
55
|
+
name :b
|
56
|
+
channel :archive
|
57
|
+
channel :default
|
58
|
+
|
59
|
+
param :b_val, :type => :int32
|
60
|
+
end
|
61
|
+
|
62
|
+
OML4R::init(ARGV,
|
63
|
+
:appName => 'doubleAgent',
|
64
|
+
:domain => 'foo'
|
65
|
+
)
|
66
|
+
OML4R::create_channel(:archive, 'file:/tmp/archive.log')
|
50
67
|
|
51
|
-
|
68
|
+
Setting the command line flag '--oml-collect' will define a ':default' channel. Any additional channels
|
69
|
+
need to be declared with 'OML4R::create_channel' which takes two arguments, the name of the channel
|
70
|
+
and the destination for the measurement stream. The above example defines an 'archive' channel
|
71
|
+
which is being collected in the local '/tmp/archive.log' file.
|
52
72
|
|
53
|
-
|
54
|
-
of this software and associated documentation files (the "Software"), to deal
|
55
|
-
in the Software without restriction, including without limitation the rights
|
56
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
57
|
-
copies of the Software, and to permit persons to whom the Software is
|
58
|
-
furnished to do so, subject to the following conditions:
|
73
|
+
Please note that by declaring a specific channel, every MP needs at least one channel declaration.
|
59
74
|
|
60
|
-
|
61
|
-
all copies or substantial portions of the Software.
|
75
|
+
### Real example
|
62
76
|
|
63
|
-
|
64
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
65
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
66
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
67
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
68
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
69
|
-
THE SOFTWARE.
|
77
|
+
See examples files oml4r-simple-example.rb and oml4r-wlanconfig.rb.
|
70
78
|
|
71
79
|
[oml-text]: http://oml.mytestbed.net/projects/oml/wiki/Description_of_Text_protocol
|
72
80
|
[oml4r-rubygem]: https://rubygems.org/gems/oml4r/
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Copyright (c) 2009 - 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
# ------------------
|
6
|
+
#
|
7
|
+
# = oml4r-simple-example.rb
|
8
|
+
#
|
9
|
+
# == Description
|
10
|
+
#
|
11
|
+
# A very simple straightforward example of OML4R.
|
12
|
+
#
|
13
|
+
require 'rubygems'
|
14
|
+
require 'oml4r'
|
15
|
+
|
16
|
+
# Define your own Measurement Points
|
17
|
+
class SinMP < OML4R::MPBase
|
18
|
+
name :sin
|
19
|
+
#channel :default
|
20
|
+
|
21
|
+
param :label
|
22
|
+
param :angle, :type => :int32
|
23
|
+
param :value, :type => :double
|
24
|
+
end
|
25
|
+
|
26
|
+
class CosMP < OML4R::MPBase
|
27
|
+
name :cos
|
28
|
+
# channel :ch1
|
29
|
+
# channel :default
|
30
|
+
|
31
|
+
param :label
|
32
|
+
param :value, :type => :double
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initialise the OML4R module for your application
|
36
|
+
opts = {:appName => 'oml4rSimpleExample',
|
37
|
+
:domain => 'foo',
|
38
|
+
:collect => 'file:-'} # Server could also be tcp:host:port
|
39
|
+
#
|
40
|
+
#OML4R::create_channel(:ch1, 'file:/tmp/foo.log')
|
41
|
+
|
42
|
+
begin
|
43
|
+
OML4R::init(ARGV, opts)
|
44
|
+
rescue OML4R::MissingArgumentException => mex
|
45
|
+
$stderr.puts mex
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
|
49
|
+
# Now collect and inject some measurements
|
50
|
+
500.times do |i|
|
51
|
+
sleep 0.5
|
52
|
+
angle = 15 * i
|
53
|
+
SinMP.inject("label_#{angle}", angle, Math.sin(angle))
|
54
|
+
CosMP.inject("label_#{angle}", Math.cos(angle))
|
55
|
+
end
|
56
|
+
|
57
|
+
# Don't forget to close when you are finished
|
58
|
+
OML4R::close()
|
59
|
+
|
60
|
+
# vim: sw=2
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2010-
|
2
|
+
# Copyright (c) 2010-2013 National ICT Australia (NICTA), Australia
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -30,6 +30,7 @@
|
|
30
30
|
# its output (= measurements), and finally pass them to OML4R, which will in
|
31
31
|
# turn either store them in a local file or forward them to the OML Server.
|
32
32
|
#
|
33
|
+
require "rubygems"
|
33
34
|
require "oml4r"
|
34
35
|
|
35
36
|
APPNAME = "wlanconfig"
|
@@ -0,0 +1,98 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# example script that reads CPU load measurements from a Zabbix server
|
4
|
+
# and pushes them into an OML database
|
5
|
+
|
6
|
+
# make sure you install these two gems
|
7
|
+
require "zabbixapi"
|
8
|
+
require "oml4r"
|
9
|
+
|
10
|
+
# # Zabbix node names
|
11
|
+
# nodes = ["10.129.16.11", "10.129.16.12", "10.129.16.13"]
|
12
|
+
|
13
|
+
# Define your own Measurement Point
|
14
|
+
class CPU_MP < OML4R::MPBase
|
15
|
+
name :CPU
|
16
|
+
param :ts, :type => :string
|
17
|
+
param :node, :type => :string
|
18
|
+
param :load1, :type => :double
|
19
|
+
param :load5, :type => :double
|
20
|
+
param :load15, :type => :double
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# Initialise the OML4R module for your application
|
25
|
+
oml_opts = {
|
26
|
+
:appName => 'zabbix',
|
27
|
+
:domain => 'zabbix-cpu-measurement',
|
28
|
+
:nodeID => 'cloud',
|
29
|
+
:collect => 'file:-'
|
30
|
+
}
|
31
|
+
zabbix_opts = {
|
32
|
+
:url => 'http://cloud.npc.nicta.com.au/zabbix/api_jsonrpc.php',
|
33
|
+
:user => 'Admin',
|
34
|
+
:password => 'zabbix'
|
35
|
+
}
|
36
|
+
|
37
|
+
interval = 1
|
38
|
+
|
39
|
+
nodes = OML4R::init(ARGV, oml_opts) do |op|
|
40
|
+
op.banner = "Usage: #{$0} [options] host1 host2 ...\n"
|
41
|
+
|
42
|
+
op.on( '-i', '--interval SEC', "Query interval in seconds [#{interval}]" ) do |i|
|
43
|
+
interval = i.to_i
|
44
|
+
end
|
45
|
+
op.on( '-s', '--service-url URL', "Zabbix service url [#{zabbix_opts[:url]}]" ) do |u|
|
46
|
+
zabbix_opts[:url] = p
|
47
|
+
end
|
48
|
+
op.on( '-p', '--password PW', "Zabbix password [#{zabbix_opts[:password]}]" ) do |p|
|
49
|
+
zabbix_opts[:password] = p
|
50
|
+
end
|
51
|
+
op.on( '-u', '--user USER', "Zabbix user name [#{zabbix_opts[:user]}]" ) do |u|
|
52
|
+
zabbix_opts[:user] = u
|
53
|
+
end
|
54
|
+
end
|
55
|
+
if nodes.empty?
|
56
|
+
OML4R.logger.error "Missing host list"
|
57
|
+
OML4R::close()
|
58
|
+
exit(-1)
|
59
|
+
end
|
60
|
+
|
61
|
+
# connect to Zabbix JSON API
|
62
|
+
zbx = ZabbixApi.connect(zabbix_opts)
|
63
|
+
|
64
|
+
# catch CTRL-C
|
65
|
+
exit_requested = false
|
66
|
+
Kernel.trap( "INT" ) { exit_requested = true }
|
67
|
+
|
68
|
+
# poll Zabbix API
|
69
|
+
while !exit_requested
|
70
|
+
nodes.each{|n|
|
71
|
+
# https://www.zabbix.com/documentation/2.0/manual/appendix/api/item/get
|
72
|
+
results = zbx.query(
|
73
|
+
:method => "item.get",
|
74
|
+
:params => {
|
75
|
+
:output => "extend",
|
76
|
+
:host => "#{n}",
|
77
|
+
# only interested in CPU load
|
78
|
+
:search => {
|
79
|
+
:name => "Processor load"
|
80
|
+
}
|
81
|
+
}
|
82
|
+
)
|
83
|
+
unless results.empty?
|
84
|
+
l15 = results[0]["lastvalue"]
|
85
|
+
l1 = results[1]["lastvalue"]
|
86
|
+
l5 = results[2]["lastvalue"]
|
87
|
+
#puts "Injecting values #{l1}, #{l5}, #{l15} for node #{n}"
|
88
|
+
# injecting measurements into OML
|
89
|
+
CPU_MP.inject(Time.now.to_s, n, l1, l5, l15)
|
90
|
+
else
|
91
|
+
OML4R.logger.warn "Empty result usually means misspelled host address"
|
92
|
+
end
|
93
|
+
}
|
94
|
+
sleep interval
|
95
|
+
end
|
96
|
+
|
97
|
+
OML4R::close()
|
98
|
+
puts "Exiting"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Copyright (c) 2009 - 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
# ------------------
|
6
|
+
#
|
7
|
+
# = test_types.rb
|
8
|
+
#
|
9
|
+
# == Description
|
10
|
+
#
|
11
|
+
# Testing blobs and long strings. Should really go into a test suite.
|
12
|
+
#
|
13
|
+
require 'rubygems'
|
14
|
+
require 'oml4r'
|
15
|
+
|
16
|
+
# Define your own Measurement Points
|
17
|
+
class TestMP < OML4R::MPBase
|
18
|
+
name :test
|
19
|
+
#channel :default
|
20
|
+
|
21
|
+
param :text
|
22
|
+
param :blob, :type => :blob
|
23
|
+
end
|
24
|
+
|
25
|
+
# Initialise the OML4R module for your application
|
26
|
+
opts = {:appName => 'test_types',
|
27
|
+
:domain => 'foo', :nodeID => 'n1',
|
28
|
+
:collect => 'file:-'}
|
29
|
+
|
30
|
+
OML4R::init(ARGV, opts)
|
31
|
+
|
32
|
+
# Now collect and inject some measurements
|
33
|
+
blob = ""
|
34
|
+
30.times {|i| blob << i}
|
35
|
+
TestMP.inject(%{tab new line
|
36
|
+
another two
|
37
|
+
|
38
|
+
and that's it}, blob)
|
39
|
+
|
40
|
+
# Don't forget to close when you are finished
|
41
|
+
OML4R::close()
|
42
|
+
|
43
|
+
# vim: sw=2
|
@@ -0,0 +1,240 @@
|
|
1
|
+
# Copyright (c) 2013 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
# ------------------
|
6
|
+
#
|
7
|
+
# = benchmark.rb
|
8
|
+
#
|
9
|
+
# == Description
|
10
|
+
#
|
11
|
+
# Provides convenience functions to monitor long running services and
|
12
|
+
# report performance metrics through OML
|
13
|
+
#
|
14
|
+
require 'oml4r'
|
15
|
+
|
16
|
+
module OML4R
|
17
|
+
#
|
18
|
+
# Monitor the CPU consumption of a block and report it to
|
19
|
+
# OML
|
20
|
+
#
|
21
|
+
class Benchmark
|
22
|
+
|
23
|
+
def self.bm(label, opts = {}, &block)
|
24
|
+
inst = self.new(label, opts)
|
25
|
+
inst.measure(&block) if block
|
26
|
+
inst
|
27
|
+
end
|
28
|
+
|
29
|
+
# Measure execution of 'block'. Benchmarking is assumed
|
30
|
+
# to be finished when block finished. Don't attempt to
|
31
|
+
# call again
|
32
|
+
#
|
33
|
+
def measure(&block)
|
34
|
+
raise "Missing block" unless block
|
35
|
+
start
|
36
|
+
block.arity == 0 ? block.call() : block.call(self)
|
37
|
+
_stop
|
38
|
+
end
|
39
|
+
|
40
|
+
# Execute block and add execution time to overall
|
41
|
+
# measurements. Can be called multiple time. Need
|
42
|
+
# to finally call '#stop' to report overall stats.
|
43
|
+
#
|
44
|
+
def task(&block)
|
45
|
+
raise "Missing block" unless block
|
46
|
+
resume
|
47
|
+
block.arity == 0 ? block.call() : block.call(self)
|
48
|
+
pause
|
49
|
+
end
|
50
|
+
|
51
|
+
def start()
|
52
|
+
@lock.synchronize do
|
53
|
+
raise "Don't call this directly" if @running
|
54
|
+
@running = true
|
55
|
+
end
|
56
|
+
|
57
|
+
if @monitor_interval > 0
|
58
|
+
Thread.new do
|
59
|
+
while @running
|
60
|
+
sleep @monitor_interval
|
61
|
+
_report()
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
@t0, r0 = Process.times, Time.now
|
66
|
+
@t1 = @t0
|
67
|
+
@r1 = @r0 = r0.to_f
|
68
|
+
end
|
69
|
+
|
70
|
+
def pause()
|
71
|
+
t, r = Process.times, Time.now
|
72
|
+
@lock.synchronize do
|
73
|
+
return unless @running
|
74
|
+
return if @paused
|
75
|
+
@paused = true
|
76
|
+
|
77
|
+
@paused_t = t
|
78
|
+
@paused_r = r.to_f
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def resume()
|
83
|
+
@lock.synchronize do
|
84
|
+
unless @running
|
85
|
+
# hasn't been kicked off yet
|
86
|
+
start
|
87
|
+
return
|
88
|
+
end
|
89
|
+
|
90
|
+
return unless @paused
|
91
|
+
t, r = Process.times, Time.now
|
92
|
+
off_u = t.utime - @paused_t.utime
|
93
|
+
off_s = t.stime - @paused_t.stime
|
94
|
+
off_t = r.to_f - @paused_r
|
95
|
+
@t0 = Struct::Tms.new(@t0.utime + off_u, @t0.stime + off_s)
|
96
|
+
@r0 = @r0 + off_t
|
97
|
+
if @t1
|
98
|
+
@t1 = Struct::Tms.new(@t1.utime + off_u, @t1.stime + off_s)
|
99
|
+
@r1 = @r1 + off_t
|
100
|
+
end
|
101
|
+
@paused = false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def stop
|
106
|
+
@lock.synchronize do
|
107
|
+
return unless @running
|
108
|
+
end
|
109
|
+
_stop
|
110
|
+
end
|
111
|
+
|
112
|
+
# Push out an intermediate report. Does
|
113
|
+
# nothing if already finished.
|
114
|
+
#
|
115
|
+
# NOTE: Not thread safe
|
116
|
+
#
|
117
|
+
def report(label = nil)
|
118
|
+
return unless @running
|
119
|
+
_report(label)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Report a step in the processing. Used to calculate a
|
123
|
+
# progress rate
|
124
|
+
#
|
125
|
+
# NOTE: Not thread safe
|
126
|
+
#
|
127
|
+
def step(cnt = 1)
|
128
|
+
@step_cnt += cnt
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
class BenchmarkMP < OML4R::MPBase
|
134
|
+
name :benchmark
|
135
|
+
#channel :default
|
136
|
+
|
137
|
+
param :label
|
138
|
+
param :note
|
139
|
+
param :is_absolute, :type => :boolean
|
140
|
+
param :is_final, :type => :boolean
|
141
|
+
param :step_cnt, :type => :int32
|
142
|
+
param :rate_real, :type => :double
|
143
|
+
param :rate_usys, :type => :double
|
144
|
+
param :time_wall, :type => :double
|
145
|
+
param :time_user, :type => :double
|
146
|
+
param :time_sys, :type => :double
|
147
|
+
end
|
148
|
+
|
149
|
+
def initialize(name, opts)
|
150
|
+
@name = name
|
151
|
+
@running = false
|
152
|
+
@paused = false
|
153
|
+
|
154
|
+
@monitor_interval = opts[:periodic] || -1
|
155
|
+
@step_cnt = 0
|
156
|
+
@step_cnt1 = 0
|
157
|
+
|
158
|
+
@lock = Monitor.new
|
159
|
+
@first_report = true
|
160
|
+
end
|
161
|
+
|
162
|
+
def _stop
|
163
|
+
_report('done', true)
|
164
|
+
@lock.synchronize do
|
165
|
+
@running = false
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def _report(label = '-', is_final = false)
|
170
|
+
t, r = Process.times, Time.now
|
171
|
+
@lock.synchronize do
|
172
|
+
if @paused
|
173
|
+
# report ONCE while paused
|
174
|
+
return if @paused_r == @last_paused_r
|
175
|
+
@last_paused_r = @paused_r
|
176
|
+
t = @paused_t
|
177
|
+
r = @paused_r
|
178
|
+
end
|
179
|
+
r = r.to_f
|
180
|
+
_inject(label, true, is_final, t, r, @t0, @r0, @step_cnt)
|
181
|
+
unless (is_final && @first_report)
|
182
|
+
# don't report incremental on final if this would be the first incr
|
183
|
+
_inject(label, false, is_final, t, r, @t1, @r1, @step_cnt - @step_cnt1)
|
184
|
+
end
|
185
|
+
@t1 = t
|
186
|
+
@r1 = r
|
187
|
+
@step_cnt1 = @step_cnt
|
188
|
+
@first_report = false
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def _inject(label, is_absolute, is_final, t1, r1, t0, r0, step_cnt)
|
193
|
+
d_u = t1.utime - t0.utime
|
194
|
+
d_s = t1.stime - t0.stime
|
195
|
+
d_t = r1 - r0
|
196
|
+
#puts "INJECT0 #{d_u} #{d_s} #{d_t}"
|
197
|
+
return if (d_t <= 0 || (d_s + d_u) <= 0)
|
198
|
+
BenchmarkMP.inject @name, label, is_absolute, is_final, step_cnt, step_cnt / d_t, step_cnt / (d_u + d_s), d_t, d_u, d_s
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
if __FILE__ == $0
|
204
|
+
opts = {
|
205
|
+
:appName => 'bm_test',
|
206
|
+
:domain => 'foo',
|
207
|
+
:nodeID => 'n1',
|
208
|
+
:collect => 'file:-'
|
209
|
+
}
|
210
|
+
OML4R::init(ARGV, opts)
|
211
|
+
|
212
|
+
bm_i = OML4R::Benchmark.bm('inner_test', periodic: 0.1)
|
213
|
+
OML4R::Benchmark.bm('test', periodic: 0.1) do |bm|
|
214
|
+
20.times do |i|
|
215
|
+
10.times do
|
216
|
+
"a" * 1_000_000
|
217
|
+
bm.step
|
218
|
+
end
|
219
|
+
|
220
|
+
bm_i.task do
|
221
|
+
10.times do
|
222
|
+
"a" * 1_000_000
|
223
|
+
bm_i.step
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
sleep 0.02
|
228
|
+
if i == 10
|
229
|
+
bm.pause
|
230
|
+
sleep 2
|
231
|
+
bm.resume
|
232
|
+
end
|
233
|
+
#bm.report()
|
234
|
+
end
|
235
|
+
end
|
236
|
+
bm_i.stop
|
237
|
+
OML4R::close()
|
238
|
+
puts 'done'
|
239
|
+
end
|
240
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Copyright (c) 2009 - 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
# ------------------
|
6
|
+
|
7
|
+
module OML4R
|
8
|
+
VERSION = "2.9.1"
|
9
|
+
VERSION_STRING = "OML4R Client V#{VERSION}"
|
10
|
+
COPYRIGHT = "Copyright 2009-2013, NICTA"
|
11
|
+
end
|
data/lib/oml4r.rb
CHANGED
@@ -1,24 +1,8 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# in the Software without restriction, including without limitation the rights
|
7
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
# copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in
|
12
|
-
# all copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
-
# THE SOFTWARE.
|
21
|
-
#
|
1
|
+
# Copyright (c) 2009 - 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
# ------------------
|
22
6
|
#
|
23
7
|
# = oml4r.rb
|
24
8
|
#
|
@@ -34,21 +18,28 @@ require 'monitor'
|
|
34
18
|
require 'thread'
|
35
19
|
require 'optparse'
|
36
20
|
|
21
|
+
require 'oml4r/version'
|
22
|
+
|
37
23
|
#
|
38
24
|
# This is the OML4R module, which should be required by ruby applications
|
39
25
|
# that want to collect measurements via OML
|
40
26
|
#
|
41
27
|
module OML4R
|
42
28
|
|
43
|
-
VERSION = "2.9.0.2"
|
44
|
-
VERSION_STRING = "OML4R Client V#{VERSION}"
|
45
|
-
COPYRIGHT = "Copyright 2009-2012, NICTA"
|
46
29
|
DEF_SERVER_PORT = 3003
|
30
|
+
DEF_PROTOCOL = 3
|
47
31
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
32
|
+
# Overwrite the default logger
|
33
|
+
#
|
34
|
+
# @param logger Needs to respond to 'debug', 'info', ...
|
35
|
+
#
|
36
|
+
def self.logger=(logger)
|
37
|
+
@@logger = logger
|
38
|
+
end
|
39
|
+
|
40
|
+
class OML4RExeption < Exception; end
|
41
|
+
class MissingArgumentException < OML4RExeption; end
|
42
|
+
class ArgumentMismatchException < OML4RExeption; end
|
52
43
|
#
|
53
44
|
# Measurement Point Class
|
54
45
|
# Ruby applications using this module should sub-class this MPBase class
|
@@ -77,9 +68,9 @@ module OML4R
|
|
77
68
|
# Returns the definition of this MP
|
78
69
|
def self.__def__()
|
79
70
|
unless (defs = @@defs[self])
|
80
|
-
|
81
|
-
|
82
|
-
|
71
|
+
defs = @@defs[self] = {}
|
72
|
+
defs[:p_def] = []
|
73
|
+
defs[:seq_no] = 0
|
83
74
|
end
|
84
75
|
defs
|
85
76
|
end
|
@@ -105,9 +96,12 @@ module OML4R
|
|
105
96
|
o = opts.dup
|
106
97
|
o[:name] = name
|
107
98
|
o[:type] ||= :string
|
108
|
-
|
109
|
-
|
110
|
-
|
99
|
+
case o[:type]
|
100
|
+
when :long
|
101
|
+
OML4R.logger.warn ":long is deprecated use, :int32 instead"
|
102
|
+
o[:type] = :int32
|
103
|
+
when :boolean
|
104
|
+
o[:type] = :int32 # TODO: Hopefully we can remove this soon
|
111
105
|
end
|
112
106
|
__def__()[:p_def] << o
|
113
107
|
nil
|
@@ -124,23 +118,34 @@ module OML4R
|
|
124
118
|
# definition of this Measurement Point
|
125
119
|
defs = __def__()
|
126
120
|
pdef = defs[:p_def]
|
121
|
+
types = defs[:types]
|
127
122
|
if args.size != pdef.size
|
128
|
-
|
123
|
+
raise ArgumentMismatchException.new "OML4R: Size mismatch between the measurement (#{args.size}) and the MP definition (#{pdef.size})!"
|
129
124
|
end
|
130
125
|
|
131
126
|
# Now prepare the measurement...
|
132
127
|
t = Time.now - @@start_time
|
133
128
|
a = []
|
134
129
|
a << (defs[:seq_no] += 1)
|
135
|
-
args.
|
136
|
-
|
130
|
+
args.each_with_index do |arg, i|
|
131
|
+
case types[i]
|
132
|
+
when :string
|
133
|
+
# Escape tabs and newlines
|
134
|
+
arg = arg.to_s.gsub("\n", "\\n").gsub("\t", "\\t")
|
135
|
+
when :boolean
|
136
|
+
# boolean
|
137
|
+
arg = arg ? 1 : 0
|
138
|
+
when :blob
|
139
|
+
arg = [arg].pack("m")
|
140
|
+
end
|
141
|
+
a << arg
|
137
142
|
end
|
138
143
|
# ...and inject it!
|
139
144
|
msg = a.join("\t")
|
140
145
|
@@channels[self].each do |ca|
|
141
|
-
|
142
|
-
|
143
|
-
|
146
|
+
channel = ca[0]
|
147
|
+
index = ca[1]
|
148
|
+
channel.send "#{t}\t#{index}\t#{msg}"
|
144
149
|
end
|
145
150
|
args
|
146
151
|
end
|
@@ -154,24 +159,28 @@ module OML4R
|
|
154
159
|
def self.__freeze__(appName, start_time)
|
155
160
|
return if @@frozen
|
156
161
|
@@frozen = true
|
162
|
+
# create type array for easier processing in inject
|
163
|
+
@@defs.each do |name, descr|
|
164
|
+
descr[:types] = descr[:p_def].map {|h| h[:type]}
|
165
|
+
end
|
166
|
+
|
157
167
|
# replace channel names with channel object
|
158
168
|
self.each_mp do |klass, defs|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
169
|
+
cna = @@channels[klass] || []
|
170
|
+
OML4R.logger.debug "'#{cna.inspect}', '#{klass}'"
|
171
|
+
ca = cna.collect do |cname, domain|
|
172
|
+
# return it in an array as we need to add the channel specific index
|
173
|
+
[Channel[cname.to_sym, domain.to_sym]]
|
174
|
+
end
|
175
|
+
OML4R.logger.debug "Using channels '#{ca.inspect}"
|
176
|
+
@@channels[klass] = ca.empty? ? [[Channel[]]] : ca
|
167
177
|
end
|
168
178
|
@@start_time = start_time
|
169
|
-
|
170
179
|
end
|
171
180
|
|
172
181
|
def self.__unfreeze__()
|
173
182
|
self.each_mp do |klass, defs|
|
174
|
-
|
183
|
+
defs[:seq_no] = 0
|
175
184
|
end
|
176
185
|
@@channels = {}
|
177
186
|
@@start_time = nil
|
@@ -186,16 +195,16 @@ module OML4R
|
|
186
195
|
|
187
196
|
# Do some sanity checks...
|
188
197
|
unless (mp_name = defs[:name])
|
189
|
-
|
198
|
+
raise MissingArgumentException.new "Missing 'name' declaration for '#{self}'"
|
190
199
|
end
|
191
200
|
unless (name_prefix.nil?)
|
192
|
-
|
201
|
+
mp_name = "#{name_prefix}_#{mp_name}"
|
193
202
|
end
|
194
203
|
|
195
204
|
@@channels[self].each do |ca|
|
196
|
-
|
197
|
-
|
198
|
-
|
205
|
+
OML4R.logger.debug "Setting up channel '#{ca.inspect}"
|
206
|
+
index = ca[0].send_schema(mp_name, defs[:p_def])
|
207
|
+
ca << index
|
199
208
|
end
|
200
209
|
end
|
201
210
|
end # class MPBase
|
@@ -215,12 +224,12 @@ module OML4R
|
|
215
224
|
# - & block = a block which defines the additional application-specific arguments
|
216
225
|
#
|
217
226
|
def self.init(argv, opts = {}, &block)
|
218
|
-
|
227
|
+
OML4R#{VERSION_STRING} [#{COPYRIGHT}")
|
219
228
|
|
220
229
|
if d = (ENV['OML_EXP_ID'] || opts[:expID])
|
221
230
|
# XXX: It is still too early to complain about that. We need to be sure
|
222
231
|
# of the nomenclature before making user-visible changes.
|
223
|
-
|
232
|
+
OML4R.logger.warn "opts[:expID] and ENV['OML_EXP_ID'] are getting deprecated; please use opts[:domain] or ENV['OML_DOMAIN'] instead"
|
224
233
|
opts[:domain] ||= d
|
225
234
|
end
|
226
235
|
domain ||= ENV['OML_DOMAIN'] || opts[:domain]
|
@@ -237,16 +246,17 @@ module OML4R
|
|
237
246
|
# raise 'OML4R: :app is not a valid option. Do you mean :appName?'
|
238
247
|
#end
|
239
248
|
appName = opts[:appName] || opts[:app]
|
249
|
+
protocol = opts[:protocol] = DEF_PROTOCOL
|
240
250
|
|
241
251
|
if ENV['OML_URL'] || opts[:omlURL] || opts[:url]
|
242
|
-
raise '
|
252
|
+
raise MissingArgumentException.new 'neither OML_URL, :omlURL nor :url are valid. Do you mean OML_COLLECT or :omlCollect?'
|
243
253
|
end
|
244
254
|
if ENV['OML_SERVER'] || opts[:omlServer]
|
245
|
-
|
255
|
+
OML4R.logger.warn "opts[:omlServer] and ENV['OML_SERVER'] are getting deprecated; please use opts[:collect] or ENV['OML_COLLECT'] instead"
|
246
256
|
end
|
247
257
|
omlCollectUri = ENV['OML_COLLECT'] || ENV['OML_SERVER'] || opts[:collect] || opts[:omlServer]
|
248
258
|
noop = opts[:noop] || false
|
249
|
-
|
259
|
+
|
250
260
|
|
251
261
|
# Create a new Parser for the command line
|
252
262
|
op = OptionParser.new
|
@@ -256,61 +266,69 @@ module OML4R
|
|
256
266
|
op.on("--oml-id id", "Name to identify this app instance [#{nodeID || 'undefined'}]") { |name| nodeID = name }
|
257
267
|
op.on("--oml-domain domain", "Name of experimental domain [#{domain || 'undefined'}] *EXPERIMENTAL*") { |name| domain = name }
|
258
268
|
op.on("--oml-collect uri", "URI of server to send measurements to") { |u| omlCollectUri = u }
|
259
|
-
op.on("--oml-
|
269
|
+
op.on("--oml-protocol p", "Protocol number [#{OML4R::DEF_PROTOCOL}]") { |l| protocol = l.to_i }
|
270
|
+
op.on("--oml-log-level l", "Log level used (info: 1 .. debug: 0)") { |l| OML4R.logger.level = l.to_i }
|
260
271
|
op.on("--oml-noop", "Do not collect measurements") { noop = true }
|
261
|
-
op.on("--oml-config file", "File holding OML configuration parameters") { |f| omlConfigFile = f }
|
262
272
|
op.on("--oml-exp-id domain", "Obsolescent equivalent to --oml-domain domain") { |name|
|
263
273
|
domain = name
|
264
|
-
|
274
|
+
OML4R.logger.warn "Option --oml-exp-id is getting deprecated; please use '--oml-domain #{domain}' instead"
|
265
275
|
}
|
266
276
|
op.on("--oml-file localPath", "Obsolescent equivalent to --oml-collect file:localPath") { |name|
|
267
277
|
omlCollectUri = "file:#{name}"
|
268
|
-
|
278
|
+
OML4R.logger.warn "Option --oml-file is getting deprecated; please use '--oml-collect #{omlCollectUri}' instead"
|
269
279
|
}
|
270
280
|
op.on("--oml-server uri", "Obsolescent equivalent to --oml-collect uri") {|u|
|
271
281
|
omlCollectUri = u
|
272
|
-
|
282
|
+
OML4R.logger.warn "Option --oml-server is getting deprecated; please use '--oml-collect #{omlCollectUri}' instead"
|
273
283
|
}
|
274
284
|
op.on_tail("--oml-help", "Show this message") { $stderr.puts op; exit }
|
275
285
|
# XXX: This should be set by the application writer, not the command line
|
276
286
|
#op.on("--oml-appid APPID", "Application ID for OML [#{appName || 'undefined'}] *EXPERIMENTAL*") { |name| appID = name }
|
277
287
|
|
278
|
-
# Set a default collection URI if nothing has been specified
|
279
|
-
omlCollectUri ||= "file:#{appName}_#{nodeID}_#{domain}_#{Time.now.strftime("%Y-%m-%dt%H.%M.%S%z")}"
|
280
|
-
|
281
288
|
# Now parse the command line
|
282
|
-
|
289
|
+
OML4R.logger.debug "ARGV:>>> #{argv.inspect}"
|
283
290
|
rest = op.parse(argv)
|
284
291
|
return if noop
|
285
292
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
293
|
+
unless nodeID
|
294
|
+
begin
|
295
|
+
# Create a default nodeID by concatinating the local hostname with the process ID
|
296
|
+
hostname = nil
|
297
|
+
begin
|
298
|
+
hostname = Socket.gethostbyname(Socket.gethostname)[0]
|
299
|
+
rescue Exception
|
300
|
+
begin
|
301
|
+
hostname = `hostname`
|
302
|
+
rescue Exception; end
|
296
303
|
end
|
297
|
-
|
304
|
+
if hostname
|
305
|
+
nodeID = "#{hostname}-#{Process.pid}"
|
306
|
+
end
|
307
|
+
end
|
308
|
+
unless nodeID
|
309
|
+
raise MissingArgumentException.new 'OML4R: Missing values for parameter :nodeID (--oml-id)'
|
310
|
+
end
|
298
311
|
end
|
299
|
-
|
300
|
-
unless domain &&
|
301
|
-
raise 'OML4R: Missing values for parameters :domain (--oml-domain), :nodeID (--oml-id), or :appName (in code)!'
|
312
|
+
|
313
|
+
unless domain && appName
|
314
|
+
raise MissingArgumentException.new 'OML4R: Missing values for parameters :domain (--oml-domain), :nodeID (--oml-id), or :appName (in code)!'
|
302
315
|
end
|
303
316
|
|
304
|
-
|
317
|
+
# Set a default collection URI if nothing has been specified
|
318
|
+
omlCollectUri ||= "file:#{appName}_#{nodeID}_#{domain}_#{Time.now.strftime("%Y-%m-%dt%H.%M.%S%z")}"
|
319
|
+
|
320
|
+
create_channel(:default, omlCollectUri) if omlCollectUri
|
305
321
|
|
306
322
|
# Handle the defined Measurement Points
|
307
323
|
startTime = Time.now
|
308
|
-
Channel.init_all(domain, nodeID, appName, startTime)
|
309
|
-
|
310
|
-
Object.const_defined?(:MObject) ? MObject.debug(:oml4r, msg) : $stderr.puts("INFO #{msg}")
|
311
|
-
|
324
|
+
Channel.init_all(domain, nodeID, appName, startTime, protocol)
|
325
|
+
OML4R.logger.info "Collection URI is #{omlCollectUri}"
|
312
326
|
rest || []
|
313
327
|
end
|
328
|
+
|
329
|
+
def self.create_channel(name, url)
|
330
|
+
Channel.create(name, url)
|
331
|
+
end
|
314
332
|
|
315
333
|
#
|
316
334
|
# Close the OML collection. This will block until all outstanding data have been sent out.
|
@@ -330,14 +348,16 @@ module OML4R
|
|
330
348
|
class Channel
|
331
349
|
@@channels = {}
|
332
350
|
@@default_domain = nil
|
351
|
+
|
352
|
+
|
333
353
|
|
334
354
|
def self.create(name, url, domain = :default)
|
335
355
|
key = "#{name}:#{domain}"
|
336
356
|
if channel = @@channels[key]
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
357
|
+
if url != channel.url
|
358
|
+
raise OML4RException.new "OML4R: Channel '#{name}' already defined with different url"
|
359
|
+
end
|
360
|
+
return channel
|
341
361
|
end
|
342
362
|
return self._create(key, domain, url)
|
343
363
|
end
|
@@ -349,15 +369,15 @@ module OML4R
|
|
349
369
|
|
350
370
|
def self._connect(url)
|
351
371
|
if url.start_with? 'file:'
|
352
|
-
|
353
|
-
|
372
|
+
proto, fname = url.split(':')
|
373
|
+
out = (fname == '-' ? $stdout : File.open(fname, "w+"))
|
354
374
|
elsif url.start_with? 'tcp:'
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
375
|
+
#tcp:norbit.npc.nicta.com.au:3003
|
376
|
+
proto, host, port = url.split(':')
|
377
|
+
port ||= DEF_SERVER_PORT
|
378
|
+
out = TCPSocket.new(host, port)
|
359
379
|
else
|
360
|
-
|
380
|
+
raise OML4RException.new "OML4R: Unknown transport in server url '#{url}'"
|
361
381
|
end
|
362
382
|
out
|
363
383
|
end
|
@@ -365,28 +385,28 @@ module OML4R
|
|
365
385
|
def self.[](name = :default, domain = :default)
|
366
386
|
key = "#{name}:#{domain}"
|
367
387
|
unless (@@channels.key?(key))
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
388
|
+
# If domain != :default and we have one for :default, create a new one
|
389
|
+
if (domain != :default)
|
390
|
+
if (dc = @@channels["#{name}:default"])
|
391
|
+
return self._create(key, domain, dc.url)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
raise OML4RException.new "OML4R: Unknown channel '#{name}'"
|
375
395
|
end
|
376
396
|
@@channels[key]
|
377
397
|
end
|
378
398
|
|
379
|
-
def self.init_all(domain, nodeID, appName, startTime)
|
399
|
+
def self.init_all(domain, nodeID, appName, startTime, protocol)
|
380
400
|
@@default_domain = domain
|
381
401
|
|
382
402
|
MPBase.__freeze__(appName, startTime)
|
383
403
|
|
384
404
|
# send channel header
|
385
|
-
@@channels.values.each { |c| c.init(nodeID, appName, startTime) }
|
405
|
+
@@channels.values.each { |c| c.init(nodeID, appName, startTime, protocol) }
|
386
406
|
|
387
407
|
# send schema definitions
|
388
408
|
MPBase.each_mp do |klass, defs|
|
389
|
-
|
409
|
+
klass.__print_meta__(appName)
|
390
410
|
end
|
391
411
|
|
392
412
|
MPBase.__useOML__()
|
@@ -403,12 +423,13 @@ module OML4R
|
|
403
423
|
def send_schema(mp_name, pdefs) # defs[:p_def]
|
404
424
|
# Build the schema and send it
|
405
425
|
@index += 1
|
406
|
-
line = ['schema:', @index, mp_name]
|
426
|
+
#line = ['schema:', @index, mp_name]
|
427
|
+
line = [@index, mp_name]
|
407
428
|
pdefs.each do |d|
|
408
|
-
|
429
|
+
line << "#{d[:name]}:#{d[:type]}"
|
409
430
|
end
|
410
431
|
msg = line.join(' ')
|
411
|
-
@
|
432
|
+
@schemas << msg
|
412
433
|
@index
|
413
434
|
end
|
414
435
|
|
@@ -416,8 +437,8 @@ module OML4R
|
|
416
437
|
@queue.push msg
|
417
438
|
end
|
418
439
|
|
419
|
-
def init(nodeID, appName, startTime)
|
420
|
-
|
440
|
+
def init(nodeID, appName, startTime, protocol)
|
441
|
+
@nodeID, @appName, @startTime, @protocol = nodeID, appName, startTime, protocol
|
421
442
|
end
|
422
443
|
|
423
444
|
def close()
|
@@ -431,67 +452,82 @@ module OML4R
|
|
431
452
|
@url = url
|
432
453
|
@out = out_channel
|
433
454
|
@index = 0
|
434
|
-
@
|
455
|
+
@schemas = []
|
435
456
|
@header_sent = false
|
436
457
|
@queue = Queue.new
|
437
458
|
start_runner
|
438
459
|
end
|
439
460
|
|
440
461
|
|
441
|
-
def
|
442
|
-
|
462
|
+
def _send_protocol_header(stream)
|
463
|
+
header = []
|
464
|
+
header << "protocol: #{@protocol}"
|
465
|
+
header << "content: text"
|
443
466
|
d = (@domain == :default) ? @@default_domain : @domain
|
444
|
-
raise "Missing domain name" unless d
|
445
|
-
@
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
467
|
+
raise MissingArgumentException.new "Missing domain name" unless d
|
468
|
+
case @protocol || OML4R::DEF_PROTOCOL
|
469
|
+
when 3
|
470
|
+
header << "experiment-id: #{d}"
|
471
|
+
header << "start_time: #{@startTime.tv_sec}"
|
472
|
+
header << "sender-id: #{@nodeID}"
|
473
|
+
header << "app-name: #{@appName}"
|
474
|
+
@schemas.each do |s|
|
475
|
+
header << "schema: #{s}"
|
476
|
+
end
|
477
|
+
header << ""
|
478
|
+
when 4
|
479
|
+
i = 0
|
480
|
+
header << ""
|
481
|
+
header << "0\t0\t#{i += 1}\t.\texperiment-id\t#{d}"
|
482
|
+
header << "0\t0\t#{i += 1}\t.\tstart_time\t#{@startTime.tv_sec}"
|
483
|
+
header << "0\t0\t#{i += 1}\t.\tsender-id\t#{@nodeID}"
|
484
|
+
header << "0\t0\t#{i += 1}\t.\tapp-name\t#{@appName}"
|
485
|
+
@schemas.each do |s|
|
486
|
+
header << "0\t0\t#{i += 1}\t.\tschema\t#{s}"
|
487
|
+
end
|
488
|
+
|
489
|
+
else
|
490
|
+
raise OML4RException.new "Unsupported protocol #{@protocol}"
|
491
|
+
end
|
492
|
+
stream.puts header
|
450
493
|
end
|
451
494
|
|
452
495
|
def start_runner
|
453
496
|
header_sent = false
|
454
497
|
@runner = Thread.new do
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
498
|
+
active = true
|
499
|
+
begin
|
500
|
+
while (active)
|
501
|
+
msg = @queue.pop
|
502
|
+
active = !msg.nil?
|
503
|
+
if !@queue.empty?
|
504
|
+
ma = [msg]
|
505
|
+
while !@queue.empty?
|
506
|
+
msg = @queue.pop
|
507
|
+
if (active = !msg.nil?)
|
508
|
+
ma << msg
|
509
|
+
end
|
510
|
+
end
|
511
|
+
msg = ma.join("\n")
|
512
|
+
end
|
513
|
+
#$stderr.puts ">>>>>>#{@domain}: <#{msg}>"
|
471
514
|
unless msg.nil?
|
472
515
|
_send msg
|
473
516
|
end
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
info "Channel #{url} closed"
|
517
|
+
end
|
518
|
+
@out.close unless @out == $stdout
|
519
|
+
@out = nil
|
520
|
+
rescue Exception => ex
|
521
|
+
OML4R.logger.warn "Exception while sending message to channel '#{@url}' (#{ex})"
|
522
|
+
end
|
523
|
+
OML4R.logger.info "Channel #{url} closed"
|
482
524
|
end
|
483
525
|
end
|
484
526
|
|
485
|
-
def info(msg)
|
486
|
-
Object.const_defined?(:MObject) ? MObject.warn(:oml4r, msg) : $stderr.puts("INFO #{msg}")
|
487
|
-
end
|
488
|
-
|
489
527
|
def _send(msg)
|
490
528
|
begin
|
491
529
|
unless @header_sent
|
492
|
-
|
493
|
-
$stderr.puts "DEBUG '#{h}'" if OML4R.loglevel > 3
|
494
|
-
@out.puts h
|
530
|
+
_send_protocol_header(@out)
|
495
531
|
@header_sent = true
|
496
532
|
end
|
497
533
|
@out.puts msg
|
@@ -499,16 +535,16 @@ module OML4R
|
|
499
535
|
|
500
536
|
rescue Errno::EPIPE
|
501
537
|
# Trying to reconnect
|
502
|
-
info "Trying to reconnect to '#{@url}'"
|
538
|
+
OML4R.logger.info "Trying to reconnect to '#{@url}'"
|
503
539
|
loop do
|
504
540
|
sleep 5
|
505
541
|
begin
|
506
542
|
@out = self.class._connect(@url)
|
507
543
|
@header_sent = false
|
508
|
-
info "Reconnected to '#{@url}'"
|
544
|
+
OML4R.logger.info "Reconnected to '#{@url}'"
|
509
545
|
return _send(msg)
|
510
546
|
rescue Errno::ECONNREFUSED => ex
|
511
|
-
|
547
|
+
OML4R.logger.warn "Exception while reconnect '#{@url}' (#{ex.class})"
|
512
548
|
end
|
513
549
|
#Errno::ECONNREFUSED
|
514
550
|
end
|
@@ -516,7 +552,23 @@ module OML4R
|
|
516
552
|
end
|
517
553
|
|
518
554
|
end # Channel
|
519
|
-
|
555
|
+
|
556
|
+
require 'logger'
|
557
|
+
|
558
|
+
class Logger < ::Logger
|
559
|
+
def format_message(severity, time, progname, message)
|
560
|
+
"%5s oml4r: %s\n" % [severity, message]
|
561
|
+
end
|
562
|
+
end
|
563
|
+
|
564
|
+
@@logger = Logger.new(STDERR)
|
565
|
+
@@logger.level = ::Logger::INFO
|
566
|
+
|
567
|
+
def self.logger
|
568
|
+
@@logger
|
569
|
+
end
|
570
|
+
|
571
|
+
|
520
572
|
end # module OML4R
|
521
573
|
|
522
574
|
# vim: sw=2
|
data/oml4r.gemspec
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
$:.push File.expand_path("../lib", __FILE__)
|
4
|
+
require "oml4r/version"
|
3
5
|
|
4
6
|
Gem::Specification.new do |gem|
|
5
7
|
gem.authors = ["NICTA"]
|
@@ -10,18 +12,7 @@ Gem::Specification.new do |gem|
|
|
10
12
|
|
11
13
|
# ls-files won't work in VPATH builds;
|
12
14
|
# plus, we want lib/oml4r.rb rather than lib/oml4r.rb.in
|
13
|
-
|
14
|
-
gem.files = [
|
15
|
-
".yardopts",
|
16
|
-
"Gemfile",
|
17
|
-
"LICENSE",
|
18
|
-
"README.md",
|
19
|
-
"Rakefile",
|
20
|
-
"lib/oml4r.rb",
|
21
|
-
"lib/oml4r/oml4r-simple-example.rb",
|
22
|
-
"lib/oml4r/oml4r-wlanconfig.rb",
|
23
|
-
"oml4r.gemspec",
|
24
|
-
]
|
15
|
+
gem.files = `git ls-files`.split($\)
|
25
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
26
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
27
18
|
gem.name = "oml4r"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oml4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.9.
|
4
|
+
version: 2.9.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-04-09 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! '["Simple OML client library for Ruby"]'
|
15
15
|
email:
|
@@ -18,14 +18,18 @@ executables: []
|
|
18
18
|
extensions: []
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
|
-
- .
|
21
|
+
- .gitignore
|
22
22
|
- Gemfile
|
23
|
-
- LICENSE
|
23
|
+
- LICENSE.txt
|
24
24
|
- README.md
|
25
25
|
- Rakefile
|
26
|
+
- examples/oml4r-simple-example.rb
|
27
|
+
- examples/oml4r-wlanconfig.rb
|
28
|
+
- examples/oml4r-zabbix.rb
|
29
|
+
- examples/test_types.rb
|
26
30
|
- lib/oml4r.rb
|
27
|
-
- lib/oml4r/
|
28
|
-
- lib/oml4r/
|
31
|
+
- lib/oml4r/benchmark.rb
|
32
|
+
- lib/oml4r/version.rb
|
29
33
|
- oml4r.gemspec
|
30
34
|
homepage: http://oml.mytestbed.net
|
31
35
|
licenses:
|
@@ -48,7 +52,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
48
52
|
version: '0'
|
49
53
|
requirements: []
|
50
54
|
rubyforge_project:
|
51
|
-
rubygems_version: 1.8.
|
55
|
+
rubygems_version: 1.8.24
|
52
56
|
signing_key:
|
53
57
|
specification_version: 3
|
54
58
|
summary: ! '["This is a simple client library for OML which does not use liboml2 and
|
data/.yardopts
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright (c) 2012 National ICT Australia (NICTA), Australia
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files (the "Software"), to deal
|
6
|
-
# in the Software without restriction, including without limitation the rights
|
7
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
# copies of the Software, and to permit persons to whom the Software is
|
9
|
-
# furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in
|
12
|
-
# all copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
-
# THE SOFTWARE.
|
21
|
-
#
|
22
|
-
#
|
23
|
-
# = oml4r-simple-example.rb
|
24
|
-
#
|
25
|
-
# == Description
|
26
|
-
#
|
27
|
-
# A very simple straightforward example of OML4R.
|
28
|
-
#
|
29
|
-
require 'oml4r'
|
30
|
-
|
31
|
-
# Define your own Measurement Points
|
32
|
-
class SinMP < OML4R::MPBase
|
33
|
-
name :sin
|
34
|
-
#channel :default
|
35
|
-
|
36
|
-
param :label
|
37
|
-
param :angle, :type => :int32
|
38
|
-
param :value, :type => :double
|
39
|
-
end
|
40
|
-
|
41
|
-
class CosMP < OML4R::MPBase
|
42
|
-
name :cos
|
43
|
-
# channel :ch1
|
44
|
-
# channel :default
|
45
|
-
|
46
|
-
param :label
|
47
|
-
param :value, :type => :double
|
48
|
-
end
|
49
|
-
|
50
|
-
# Initialise the OML4R module for your application
|
51
|
-
opts = {:appName => 'oml4rSimpleExample',
|
52
|
-
:expID => 'foo', :nodeID => 'n1',
|
53
|
-
:omlServer => 'file:-'} # Server could also be tcp:host:port
|
54
|
-
# OML4R::create_channel(:default, 'file:-')
|
55
|
-
|
56
|
-
OML4R::init(ARGV, opts)
|
57
|
-
|
58
|
-
# Now collect and inject some measurements
|
59
|
-
5.times do |i|
|
60
|
-
sleep 0.5
|
61
|
-
angle = 15 * i
|
62
|
-
SinMP.inject("label_#{angle}", angle, Math.sin(angle))
|
63
|
-
CosMP.inject("label_#{angle}", Math.cos(angle))
|
64
|
-
end
|
65
|
-
|
66
|
-
# Don't forget to close when you are finished
|
67
|
-
OML4R::close()
|
68
|
-
|
69
|
-
# vim: sw=2
|