pipeline_toolkit 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,7 +1,7 @@
1
1
  = Pipeline Toolkit
2
2
  by VisFleet
3
3
 
4
- Command line tools for processing messages by constructing a pipeline of workers. AMQP and Unix pipes are used to construct the pipeline. Messages are simple Hashs (serialized as YAML) so they can hold any values and change throughout the processing.
4
+ Command line tools for processing messages by constructing a pipeline of workers. AMQP and Unix pipes are used to construct the pipeline. Messages are simple Hashes (serialized as YAML) so they can hold any values and change throughout the processing.
5
5
 
6
6
  Provides:
7
7
  - Processing acknowledgments, ensuring the a message is only disposed of once it has been successful processed
@@ -14,8 +14,7 @@ Provides:
14
14
 
15
15
  == Install
16
16
 
17
- > gem sources -a http://gems.github.com
18
- > sudo gem install visfleet-pipeline_toolkit
17
+ > sudo gem install pipeline_toolkit
19
18
 
20
19
  === Dependancies
21
20
 
@@ -37,7 +36,7 @@ It is assumed that you have:
37
36
  end
38
37
  MyWorker.new.start
39
38
 
40
- 2. Hook it up to the main pipe (i.e. the AMQP server)
39
+ 2. Hook it up to a AMQP message source
41
40
 
42
41
  > msg_subscribe.rb -q source | my_worker.rb | msg_push.rb -x dest
43
42
 
@@ -48,7 +47,24 @@ You can learn more about the command line tools and what options are available b
48
47
  > msg_sink --help
49
48
  > msg_probe --help
50
49
 
50
+ == Examples
51
51
 
52
-
52
+ Generate a bunch of sample messages and push them to an AMQP exchange 'test-exchange'. Hook up a pipe to consume and push results to /dev/null. Goto http://localhost:9090 to see message throughput.
53
+
54
+ > msg_generator.rb | msg_push.rb -x test-exchange
55
+ > msg_subscribe.rb --http-port 9090 -x test-exchange -q test_queue > /dev/null
56
+
57
+ Same as above, but this time with acknowledgements switched on. This guarantees that a message isn't removed from the message server until handled. msg_sink.rb acknowledges all messages.
58
+
59
+ > msg_generator.rb | msg_push.rb -x test-exchange
60
+ > msg_subscribe.rb -a -x test-exchange -q test_queue | msg_sink.rb
61
+
62
+ == Todo
63
+
64
+ - Logging. For the moment we're using SysLogLogger (which requires Syslog). This needs to be switched to the default ruby logging, and we need to find out a way to plug in alternatives if required.
65
+
66
+ - DNS-SD is broken. See http://github.com/tenderlove/dnssd/issues#issue/3
67
+
68
+ - Decide if we want to support other exchange, queue and binding configurations. For example, exchanges are always fanout and durable at the moment.
53
69
 
54
70
 
data/Rakefile CHANGED
@@ -10,9 +10,11 @@ begin
10
10
  gem.homepage = "http://github.com/visfleet/pipeline_toolkit"
11
11
  gem.authors = ["Aisha Fenton"]
12
12
  gem.executables = ["msg_probe.rb", "msg_subscribe.rb", "msg_push.rb", "msg_sink.rb", "msg_generator.rb"]
13
- gem.add_runtime_dependency('amqp', ">=0.6.4")
13
+ gem.add_runtime_dependency('amqp', ">=0.6.5")
14
14
  gem.add_runtime_dependency('trollop', ">=1.14")
15
- gem.add_runtime_dependency('eventmachine', ">=0.12.8")
15
+ gem.add_runtime_dependency('eventmachine', ">=0.12.10")
16
+ gem.add_runtime_dependency('eventmachine_httpserver', ">=0.2.0")
17
+ gem.add_runtime_dependency('SyslogLogger', ">=1.4.0")
16
18
  end
17
19
  Jeweler::GemcutterTasks.new
18
20
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.0.2
data/bin/msg_generator.rb CHANGED
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'rubygems'
3
- require 'trollop'
4
- require 'pipeline_toolkit'
5
-
6
- opts = Trollop::options do
7
- banner <<-EOS
8
- Generates messages for testing the pipeline
9
- Usage:
10
- msg_generator.rb -m "My message"
11
- EOS
12
- opt :msg, "The message to send", :short => "m", :default => "Test message"
13
- opt :delay, "Sleep time between sends in seconds", :short => "d", :type => :float
14
- end
15
-
16
- class MsgGenerator
17
-
18
- def initialize(opts)
19
- @delay = opts.delay
20
- @msg = opts.msg
21
- end
22
-
23
- def start
24
- loop do
25
- self.send_msg(@msg)
26
- sleep(@delay) unless @delay.nil?
27
- end
28
- end
29
-
30
- def send_msg(msg)
31
- puts MessageCoder.encode(@msg)
32
- $stdout.flush
33
- end
34
- end
35
-
36
- MsgGenerator.new(opts).start
data/bin/msg_probe.rb CHANGED
@@ -6,8 +6,10 @@ require 'pipeline_toolkit'
6
6
 
7
7
  opts = Trollop::options do
8
8
  opt :interval, "Time in seconds between updates", :short => "i", :default => 2
9
- opt :http_port, "The HTTP server port for accessing the stats", :default => 9070
9
+ opt :http_port, "The port the HTTP server runs on. Default is a random port between 10000-11000", :type => :integer
10
10
  opt :name, "The name of the probe. Used in monitoring", :type => :string, :short => 'n'
11
+ opt :dnssd, "Switches on DNSSD (i.e. Bonjour) for the monitoring interface", :short => 'd'
11
12
  end
12
13
 
13
- MessageProbe.new(opts).start
14
+ MessageProbe.new(opts).start
15
+
data/bin/msg_subscribe.rb CHANGED
@@ -4,11 +4,17 @@ require 'trollop'
4
4
  require 'pipeline_toolkit'
5
5
 
6
6
  opts = Trollop::options do
7
- opt :exchange, "The exchange to subscribe to", :short => "x", :type => :string
8
- opt :queue, "The source queue", :short => "q", :type => :string
7
+ # Monitoring
8
+ opt :name, "The name used to describe the entire process chain", :short => "n", :type => :string
9
+ opt :http_port, "The port the HTTP monitoring server runs on. Default is a random port between 10000-11000", :type => :integer
10
+ opt :dnssd, "Switches on DNSSD (i.e. Bonjour) for the monitoring interface", :short => 'd'
11
+
12
+ # Messages
13
+ opt :queue, "The source queue", :short => "q", :type => :string, :required => true
9
14
  opt :ack, "Switch that requires that messages are successfully processed before continuing with the next message", :short => "a"
10
15
  opt :topic, "The queue topic to subscribe to", :short => "t", :type => :string
11
16
  opt :max_unackd, "The maximum number of unaknowledged messages to buffer before waiting for them to be acknowledged. Defaults to 100", :default => 100
17
+ opt :exchange_bind, "Binds the the queue to the specified exchange. The created exchange is (for now) fanout, durable, and not passive", :short => "x", :type => :string
12
18
 
13
19
  # Msg server
14
20
  opt :host, "The AMQP message server host", :default => "localhost"
@@ -6,3 +6,4 @@ require "pipeline_toolkit/message_pusher"
6
6
  require "pipeline_toolkit/message_subscriber"
7
7
  require "pipeline_toolkit/message_sink"
8
8
  require "pipeline_toolkit/open_hash"
9
+ require "pipeline_toolkit/socket_util"
@@ -10,9 +10,7 @@ module DefaultLogger
10
10
  end
11
11
 
12
12
  def syslog_name
13
- "pipeline-" + Process.ppid.to_s
13
+ "pipeline"
14
14
  end
15
15
 
16
- end
17
-
18
-
16
+ end
@@ -16,9 +16,9 @@ module MessageCommand
16
16
 
17
17
  begin
18
18
  EM.run do
19
- self.init_loop
20
19
  conn = EM.watch($stdin, ProcessLine, self)
21
20
  conn.notify_readable = true
21
+ self.init_loop
22
22
  end
23
23
  rescue StandardError => e
24
24
  log.info e
@@ -53,7 +53,8 @@ module MessageCommand
53
53
 
54
54
  def ack_msg(msg)
55
55
  return unless @use_ack
56
- @sys_pipe.syswrite(msg.ack_id + "\n")
56
+ msg = {:msg_type => :ack, :ack_id => msg.ack_id}
57
+ @sys_pipe.syswrite(MessageCoder.encode(msg) << "\n")
57
58
  end
58
59
 
59
60
  def pass_on_msg(msg)
@@ -66,6 +67,11 @@ module MessageCommand
66
67
  # Implemented in class that includes me
67
68
  end
68
69
 
70
+ # Can be overriden in included class. Called when the sys_pipe has been established.
71
+ def syspipe_open
72
+ # Implemented in class that includes me
73
+ end
74
+
69
75
  # Override in included class. Processes a message. This method
70
76
  # must return either a msg object -- which may or may not have been modified -- or the symbol :ack.
71
77
  # Returning :ack mean that the message has been dealt with and can be acknowledged back to the queue
@@ -80,6 +86,7 @@ module MessageCommand
80
86
  @use_ack = msg.use_ack
81
87
  @max_unackd = msg.max_unackd
82
88
  msg
89
+ self.syspipe_open
83
90
  end
84
91
 
85
92
  module ProcessLine
@@ -6,10 +6,11 @@ class MessageProbe
6
6
 
7
7
  def initialize(opts)
8
8
  @interval = opts.interval
9
- @http_port= opts.http_port
9
+ @http_port= opts.http_port || Socket.select_random_port(10_000, 11_000)
10
10
  @start_time = Time.now
11
11
  @name = opts.name
12
12
  self.reset
13
+ self.init_dnssd if opts.dnssd
13
14
  end
14
15
 
15
16
  def init_loop
@@ -17,10 +18,14 @@ class MessageProbe
17
18
  EM.add_periodic_timer(@interval) { self.tick }
18
19
  end
19
20
 
21
+ def init_dnssd
22
+ require 'dnssd'
23
+ DNSSD.register!("#{@name} probe", "_http._tcp", nil, @http_port)
24
+ end
25
+
20
26
  def tick
21
27
  @time_delta = Time.now - @prev_time
22
28
  @mps = @count / @time_delta
23
-
24
29
  self.reset
25
30
  end
26
31
 
@@ -33,6 +38,8 @@ class MessageProbe
33
38
  Time.now - @start_time
34
39
  end
35
40
 
41
+ # OPTIMIZE. can improve performance by overriding base process_line method
42
+ # saving us the unnecessary marshal step.
36
43
  def process_message(msg)
37
44
  @count += 1
38
45
  msg
@@ -94,7 +101,7 @@ class ProbeHttpRequest < EM::Connection
94
101
  <td>messages per second:</td><td><span class="mps">#{@probe.mps}</span></td><td></td>
95
102
  </tr>
96
103
  <tr>
97
- <td>uptime:</td><td><span class="uptime">#{@probe.uptime.to_i / 60}</span></td><td>mins</td
104
+ <td>uptime:</td><td><span class="uptime">#{@probe.uptime.to_i / 60}</span></td><td>mins</td>
98
105
  </tr>
99
106
  </table>
100
107
  </div>
@@ -1,6 +1,6 @@
1
1
  require "mq"
2
2
 
3
- class MessagePusher
3
+ class MessagePusher
4
4
  include MessageCommand
5
5
 
6
6
  def initialize(opts)
@@ -27,6 +27,12 @@ class MessagePusher
27
27
  end
28
28
  end
29
29
 
30
+ def syspipe_open
31
+ # Send back details of where messages are going
32
+ msg = {:msg_type => :pipe_desc, :exchanges => @exchange_names.join(",")}
33
+ self.sys_pipe.syswrite(MessageCoder.encode(msg) << "\n")
34
+ end
35
+
30
36
  def load_route(key_file)
31
37
  require key_file
32
38
  self.extend eval(classify(key_file.gsub(".rb", "")))
@@ -45,8 +51,9 @@ class MessagePusher
45
51
  def process_message(msg)
46
52
  @exchanges.each do |exchange|
47
53
  key = route_key(msg)
48
- exchange.publish(msg.to_yaml, :routing_key => key)
49
- # OPTIMIZE. Using MessageCoder.encode(msg) instead of to_yaml is 2x faster. But won't be easy to debug. Worth it?
54
+ exchange.publish(msg.to_yaml)
55
+ # OPTIMIZE. Using MessageCoder.encode(msg) instead of to_yaml is 2x faster. But won't be easy to
56
+ # debug. Worth it?
50
57
  end
51
58
  :ack
52
59
  end
@@ -5,47 +5,76 @@ require "socket"
5
5
 
6
6
  class MessageSubscriber
7
7
  include DefaultLogger
8
-
8
+
9
+ attr_reader :name, :start_time, :mps, :queue_name
10
+ attr_accessor :exchanges_out
11
+
9
12
  PIPE_PATH = "/tmp"
10
13
 
11
14
  def initialize(opts)
12
- @exchange_name, @exchange_type = opts[:exchange].split(":")
15
+ @exchange_name, @exchange_type = opts[:exchange_bind].split(":")
13
16
  @queue_name = opts[:queue]
14
17
  @use_ack = opts[:ack]
15
18
  @topic = opts[:topic]
16
19
  @msg_server_opts = opts.select_keys(:host, :port, :user, :pass, :vhost)
17
20
  @unackd_msgs = {}
18
21
  @max_unackd = opts[:max_unackd]
22
+
23
+ @http_port = opts.http_port || Socket.select_random_port(10_000, 11_000)
24
+ @name = opts.name || (Socket.gethostname + '_' + Process.pid.to_s)
25
+ self.init_dnssd if opts.dnssd
26
+ self.reset
27
+ end
28
+
29
+ def init_dnssd
30
+ # FIXME. DNS-SD breaks when under load. Not sure what problem is yet, have raised it with
31
+ # gem author:
32
+ # http://github.com/tenderlove/dnssd/issues#issue/3
33
+ require 'dnssd'
34
+ DNSSD.register!("#{@name}_pipe", "_http._tcp", nil, @http_port)
19
35
  end
20
36
 
21
37
  def start
22
- Signal.trap('INT') { AMQP.stop{ EM.stop } }
23
- Signal.trap('TERM'){ AMQP.stop{ EM.stop } }
38
+ # FIXME. Need to do more investigation on if/when messages are lost with shutdowns
39
+ Signal.trap('INT') { AMQP.stop{ EM.stop } }
40
+ Signal.trap('TERM') { AMQP.stop{ EM.stop } }
24
41
 
25
42
  begin
26
43
  self.create_sys_pipe
27
44
  AMQP.start(@msg_server_opts) do
28
- # For ack to work appropriatly you must shutdown AMQP gracefully,
29
- # otherwise all items in your queue will be returned
30
- # FIXME. Doesn't shut down cleanly with these commands included. Why?
31
-
45
+ @start_time = Time.now
32
46
  self.setup_queue
33
47
  # NB. prefetch limits the amount of unknowledged messages that come down the pipe.
34
48
  MQ.prefetch(@max_unackd)
35
49
  @queue.subscribe(:ack => @use_ack) do |header, body|
36
- self.process_msg(header, body)
50
+ self.process_message(header, body)
37
51
  end
38
52
 
39
- EM.attach(@sys_pipe, HandleAcks, @sys_pipe, @unackd_msgs)
53
+ conn = EM.watch(@sys_pipe, HandleCtlMessages, @sys_pipe, self)
54
+ conn.notify_readable = true
55
+
56
+ EM.start_server('0.0.0.0', @http_port, PipeHttpRequest, self)
57
+ EM.add_periodic_timer(5) { self.calc_stats }
40
58
  end
41
59
  rescue StandardError => e
42
- log.info e
60
+ log.error e.message + " " + e.backtrace.join("\n")
43
61
  raise e
44
62
  ensure
45
63
  self.shutdown
46
64
  end
47
65
  end
48
66
 
67
+ def calc_stats
68
+ @time_delta = Time.now - @prev_time
69
+ @mps = @count / @time_delta
70
+ self.reset
71
+ end
72
+
73
+ def reset
74
+ @count = 0
75
+ @prev_time = Time.now
76
+ end
77
+
49
78
  def shutdown
50
79
  log.info "Shutting down"
51
80
  self.destroy_sys_pipe
@@ -63,7 +92,7 @@ class MessageSubscriber
63
92
  end
64
93
 
65
94
  def create_exchange(name, type)
66
- MQ::Exchange.new(MQ.default, type.to_sym, @exchange_name, :durable => true, :passive => false)
95
+ MQ::Exchange.new(MQ.default, type.to_sym, @exchange_name, :durable => true, :passive => false)
67
96
  end
68
97
 
69
98
  def create_sys_pipe
@@ -103,34 +132,115 @@ class MessageSubscriber
103
132
  "#{@seed}#{@ix += 1}"
104
133
  end
105
134
 
106
- def process_msg(header, body)
135
+ def process_message(header, body)
107
136
  msg = YAML.load(body)
108
137
  store_ack(msg, header) if @use_ack
109
138
  write_msg(msg)
110
139
  end
111
140
 
112
141
  def write_msg(msg)
142
+ @count += 1
113
143
  $stdout.syswrite(MessageCoder.encode(msg) << "\n")
114
144
  end
115
145
 
146
+ def perform_ack(ack_id)
147
+ header = @unackd_msgs.delete(ack_id)
148
+ header.ack
149
+ end
150
+
116
151
  def store_ack(msg, header)
117
152
  msg.ack_id = header.delivery_tag.to_s
118
153
  @unackd_msgs[msg.ack_id] = header
119
154
  end
120
155
 
121
156
  # Handles msg acks
122
- module HandleAcks
157
+ module HandleCtlMessages
123
158
  include DefaultLogger
124
159
 
125
- def initialize(sys_pipe, unackd_msgs)
160
+ def initialize(sys_pipe, msg_sub)
126
161
  @sys_pipe = sys_pipe
127
- @unackd_msgs = unackd_msgs
162
+ @msg_sub = msg_sub
128
163
  end
129
164
 
130
165
  def notify_readable
131
- ack_id = @sys_pipe.gets.chomp!
132
- header = @unackd_msgs.delete(ack_id)
133
- header.ack
166
+ msg = MessageCoder.decode(@sys_pipe.gets.chomp!)
167
+ case msg[:msg_type]
168
+ when :ack
169
+ @msg_sub.perform_ack(msg.ack_id)
170
+ when :pipe_desc
171
+ @msg_sub.exchanges_out = msg.exchanges
172
+ else
173
+ raise Exception.new("Unknown control message received: #{message}")
174
+ end
175
+ end
176
+ end
177
+
178
+ class PipeHttpRequest < EM::Connection
179
+ include EM::HttpServer
180
+
181
+ def initialize(msg_sub)
182
+ @msg_sub = msg_sub
183
+ end
184
+
185
+ def post_init
186
+ super
187
+ no_environment_strings
188
+ end
189
+
190
+ def process_http_request
191
+ response = EM::DelegatedHttpResponse.new(self)
192
+ response.status = 200
193
+ response.content_type 'text/html'
194
+ response.content = <<-EOL
195
+ <html>
196
+ <head>
197
+ <title>Message Probe</title>
198
+ <style type="text/css">
199
+ body {
200
+ background: black;
201
+ color: #80c0c0;
202
+ }
203
+ h1 {
204
+ font: 12pt Monospace;
205
+ text-align:center;
206
+ }
207
+ table {
208
+ font: 10pt Monospace;
209
+ margin-left:auto;
210
+ margin-right:auto;
211
+ text-align:right;
212
+ }
213
+ .page {
214
+ position:relative;
215
+ top: 20%;
216
+ # border-style:solid;
217
+ # border-width:5px;
218
+ width: 30%;
219
+ margin-left:auto;
220
+ margin-right:auto;
221
+ }
222
+ </style>
223
+ </head>
224
+ <body>
225
+ <div class=page>
226
+ <h1><span class="name">#{@msg_sub.name}</span></h1>
227
+ <table>
228
+ <tr>
229
+ <td>Structure:</td><td><span class="queue_in">#{@msg_sub.queue_name}</span> -> <span class="exchanges_out">#{@msg_sub.exchanges_out}</span></td>
230
+ </tr>
231
+ <tr>
232
+ <td>Throughput:</td><td><span class="mps">#{@msg_sub.mps.to_i}</span></td>
233
+ </tr>
234
+ <tr>
235
+ <td>Uptime:</td><td><span class="uptime">#{(Time.now - @msg_sub.start_time).to_i / 60}mins</span></td>
236
+ </tr>
237
+ </table>
238
+ </div>
239
+ </body>
240
+ </html>
241
+ EOL
242
+
243
+ response.send_response
134
244
  end
135
245
  end
136
246
 
@@ -0,0 +1,24 @@
1
+
2
+ # Extend socket class
3
+ class Socket
4
+
5
+ def self.select_random_port(low, high, host = "localhost")
6
+ raise Exception.new("'low' must be lower than 'high'") unless low < high
7
+ port = nil
8
+ begin
9
+ port = low + rand(high - low)
10
+ end while Socket.socket_in_use?(host, port)
11
+ port
12
+ end
13
+
14
+ # OPTIMIZE. Is there a better way to do this? Feels ugly to me.
15
+ def self.socket_in_use?(host, port)
16
+ begin
17
+ TCPSocket.new(host, port)
18
+ rescue Errno::ECONNREFUSED => e
19
+ return false
20
+ end
21
+ return true
22
+ end
23
+
24
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{pipeline_toolkit}
8
- s.version = "1.0.1"
8
+ s.version = "1.0.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Aisha Fenton"]
12
- s.date = %q{2009-12-06}
12
+ s.date = %q{2010-01-15}
13
13
  s.email = %q{labs@visfleet.com}
14
14
  s.executables = ["msg_probe.rb", "msg_subscribe.rb", "msg_push.rb", "msg_sink.rb", "msg_generator.rb"]
15
15
  s.extra_rdoc_files = [
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
34
34
  "lib/pipeline_toolkit/message_sink.rb",
35
35
  "lib/pipeline_toolkit/message_subscriber.rb",
36
36
  "lib/pipeline_toolkit/open_hash.rb",
37
+ "lib/pipeline_toolkit/socket_util.rb",
37
38
  "monitor/munin.rb",
38
39
  "pipeline_toolkit.gemspec"
39
40
  ]
@@ -48,18 +49,24 @@ Gem::Specification.new do |s|
48
49
  s.specification_version = 3
49
50
 
50
51
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
- s.add_runtime_dependency(%q<amqp>, [">= 0.6.4"])
52
+ s.add_runtime_dependency(%q<amqp>, [">= 0.6.5"])
52
53
  s.add_runtime_dependency(%q<trollop>, [">= 1.14"])
53
- s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.8"])
54
+ s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.10"])
55
+ s.add_runtime_dependency(%q<eventmachine_httpserver>, [">= 0.2.0"])
56
+ s.add_runtime_dependency(%q<SyslogLogger>, [">= 1.4.0"])
54
57
  else
55
- s.add_dependency(%q<amqp>, [">= 0.6.4"])
58
+ s.add_dependency(%q<amqp>, [">= 0.6.5"])
56
59
  s.add_dependency(%q<trollop>, [">= 1.14"])
57
- s.add_dependency(%q<eventmachine>, [">= 0.12.8"])
60
+ s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
61
+ s.add_dependency(%q<eventmachine_httpserver>, [">= 0.2.0"])
62
+ s.add_dependency(%q<SyslogLogger>, [">= 1.4.0"])
58
63
  end
59
64
  else
60
- s.add_dependency(%q<amqp>, [">= 0.6.4"])
65
+ s.add_dependency(%q<amqp>, [">= 0.6.5"])
61
66
  s.add_dependency(%q<trollop>, [">= 1.14"])
62
- s.add_dependency(%q<eventmachine>, [">= 0.12.8"])
67
+ s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
68
+ s.add_dependency(%q<eventmachine_httpserver>, [">= 0.2.0"])
69
+ s.add_dependency(%q<SyslogLogger>, [">= 1.4.0"])
63
70
  end
64
71
  end
65
72
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pipeline_toolkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aisha Fenton
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-06 00:00:00 +13:00
12
+ date: 2010-01-15 00:00:00 +13:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.6.4
23
+ version: 0.6.5
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: trollop
@@ -40,7 +40,27 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 0.12.8
43
+ version: 0.12.10
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: eventmachine_httpserver
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.2.0
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: SyslogLogger
57
+ type: :runtime
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 1.4.0
44
64
  version:
45
65
  description:
46
66
  email: labs@visfleet.com
@@ -73,6 +93,7 @@ files:
73
93
  - lib/pipeline_toolkit/message_sink.rb
74
94
  - lib/pipeline_toolkit/message_subscriber.rb
75
95
  - lib/pipeline_toolkit/open_hash.rb
96
+ - lib/pipeline_toolkit/socket_util.rb
76
97
  - monitor/munin.rb
77
98
  - pipeline_toolkit.gemspec
78
99
  has_rdoc: true