oml4r 2.9.0.2 → 2.9.1
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/.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
|