tellmewhen 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  h1. tellmewhen
2
2
 
3
- Tell me when another program has finshed. Show me when it started, when it finished and how long it took. Show me the output and if it errored.
3
+ Tell me when another program has finshed. Tell me when it started, tell when it finished. Tell me how long it took. Tell me the output and if it failed.
4
4
 
5
5
  I created this utility because I had long running database scripts that I wanted a completion notification for - including a summary of the time and exit code. I had done this various ways in the past by using bash and other shell utilities. This program captures all of the features and behavior I wanted without having to script it from scratch again every time I needed it.
6
6
 
@@ -9,18 +9,31 @@ I created this utility because I had long running database scripts that I wanted
9
9
  * sends email
10
10
  * includes start/stop/elapsed timing
11
11
  * success/fail based on exit code
12
- * watch an already running process (by pid, by grep pattern over 'ps aux')
13
- * release as a gem so it's easy to use/install
12
+ * watch an already running process (by pid)
13
+ * released as a gem so it's easy to use/install
14
+
15
+ h1. Installation
16
+
17
+ gem install tellmewhen
14
18
 
15
19
  h1. Configuration
16
20
 
17
21
  Configuration Defaults:
18
22
 
23
+ <pre>
24
+ ---
25
+ notify-via: email
26
+ email:
27
+ from: `echo $LOGNAME`@`hostname
28
+ to: `echo $LOGNAME`@`hostname
29
+ </pre>
30
+
19
31
  Configuration is then merged from @$HOME/.tellmewhenrc@ if the file exists in @$HOME@. Configuration is also merged from @./.tellmewhenrc@ in the current directory, if the file exists. This allows you some flexibility in overriding settings.
20
32
 
21
33
  h1. Usage
22
34
 
23
- pre. Usage: ./tellmewhen command args...
35
+ <pre>
36
+ Usage: ./tellmewhen command args...
24
37
  -v, --[no-]verbose Run Verbosely.
25
38
  -c, --config=file Use alternate configuration file.
26
39
  -p, --pid=pid Wait for <pid> to terminate.
@@ -28,14 +41,90 @@ pre. Usage: ./tellmewhen command args...
28
41
  -m, --modified=file Wait for <file> to be modified.
29
42
  -t, --timeout=seconds Wait for up to <seconds> seconds for the command before sendin a 'pending' notification.
30
43
  -w, --write-config=file Write [fully merged] configuration to <file> (NB: will not be clobber).
31
-
44
+ </pre>
32
45
 
33
46
  h1. Examples
34
47
 
35
- pre. ./tellmewhen 'sleep 3; ls'
48
+ <pre>
49
+ ./tellmewhen 'sleep 3; ls'
36
50
  ./tellmewhen -p 12345
37
51
  ./tellmewhen -e some-file.txt # await existance
38
52
  ./tellmewhen -m some-file.txt # await update
53
+ </pre>
54
+
55
+ You can also have 'pending' notifications so that you know things are still going:
56
+
57
+ <pre>
58
+ ./tellmewhen -t 2 'sleep 5; ls'
59
+ </pre>
60
+
61
+ Produces 2 emails. The pending mail is:
62
+
63
+ <pre>
64
+ Subject: When! [NOT] I'm _still_ waiting for sleep...
65
+ Body:
66
+
67
+ Just wanted to let you know that:
68
+
69
+ sleep 5; ls
70
+
71
+ Is _STILL_ running on your-host.com, it has not exited. You did want me to let you know didn't you?
72
+
73
+ I started the darn thing at Tue Jan 25 23:25:01 -0500 2011 (1296015901) and it has taken a total of 3 seconds so far.
74
+
75
+ Just thought you'd like to know. I'll continue to keep watching what you asked me to. (boor-ring!)
76
+
77
+ Cordially,
78
+
79
+ Tellmewhen
80
+
81
+ P.S. stderr says:
82
+ --
83
+
84
+ --
85
+
86
+ P.S. stdout says:
87
+ --
88
+
89
+ --
90
+ </pre>
91
+
92
+
93
+ And a final mail when it completed:
94
+
95
+ <pre>
96
+ Subject: When! SUCCESS for sleep...
97
+ Body:
98
+
99
+ Just wanted to let you know that:
100
+
101
+ sleep 5; ls
102
+
103
+ completed on your-host.com, with an exit code of: 0
104
+
105
+ It started at Tue Jan 25 23:25:01 -0500 2011 (1296015901), finished at Tue Jan 25 23:25:06 -0500 2011 (1296015906) and took a total of 5 seconds.
106
+
107
+ May your day continue to be full of win.
108
+
109
+ Sincerely,
110
+
111
+ Tellmewhen
112
+
113
+ P.S. stderr says:
114
+ --
115
+
116
+ --
117
+
118
+ P.S. stdout says:
119
+ --
120
+ README.textile
121
+ Rakefile
122
+ bin
123
+ foo
124
+ tellmewhen.gemspec
125
+
126
+ --
127
+ </pre>
39
128
 
40
129
  h1. Authors
41
130
 
@@ -15,6 +15,11 @@ class TellMeWhen
15
15
  @stderr_file = Tempfile.new('tellmewhen.stdout').path
16
16
  end
17
17
 
18
+
19
+ def max_bytes_to_read_from_file
20
+ 8 * 1024
21
+ end
22
+
18
23
  def hostname
19
24
  `hostname`.chomp
20
25
  end
@@ -102,8 +107,8 @@ class TellMeWhen
102
107
  exit app.run args
103
108
  end
104
109
 
105
- def elapsed_time
106
- Time.now.to_i - @start_time.to_i
110
+ def elapsed_time since
111
+ Time.now.to_i - since.to_i
107
112
  end
108
113
 
109
114
  def wait_timeout
@@ -112,10 +117,12 @@ class TellMeWhen
112
117
 
113
118
  def wait_on_command args
114
119
  puts "Do run: #{args}"
120
+ @current_command = args.to_s
115
121
  if args.to_s.empty?
116
122
  raise "Error: you must supply a command to execute"
117
123
  end
118
124
  child_pid = Kernel.fork
125
+ last_check_time = Time.now
119
126
  if child_pid.nil?
120
127
  # in child
121
128
  STDOUT.reopen(File.open(@stdout_file, 'w+'))
@@ -132,7 +139,8 @@ class TellMeWhen
132
139
  child_exited = true
133
140
  end
134
141
  sleep(0.250)
135
- if elapsed_time > wait_timeout
142
+ if elapsed_time(last_check_time) > wait_timeout.to_i
143
+ last_check_time = Time.now
136
144
  puts "Exceeded timeout #{wait_timeout}, sending 'pending' notificaiton"
137
145
  send_pending_notification
138
146
  end
@@ -148,7 +156,7 @@ Just wanted to let you know that:
148
156
 
149
157
  completed on #{hostname}, with an exit code of: #{@exit_status}
150
158
 
151
- It started at #{@start_time.to_s} (#{@start_time.to_i}), finished at #{@end_time.to_s} (#{@end_time.to_i}) and took a total of #{elapsed_time} seconds.
159
+ It started at #{@start_time.to_s} (#{@start_time.to_i}), finished at #{@end_time.to_s} (#{@end_time.to_i}) and took a total of #{elapsed_time(@start_time)} seconds.
152
160
 
153
161
  May your day continue to be full of win.
154
162
 
@@ -168,7 +176,7 @@ Just wanted to let you know that:
168
176
 
169
177
  FAILED! on #{hostname}, with an exit code of: #{@exit_status}
170
178
 
171
- It started at #{@start_time.to_s} (#{@start_time.to_i}), finished at #{@end_time.to_s} (#{@end_time.to_i}) and took a total of #{elapsed_time} seconds to collapse in a steaming heap of failure.
179
+ It started at #{@start_time.to_s} (#{@start_time.to_i}), finished at #{@end_time.to_s} (#{@end_time.to_i}) and took a total of #{elapsed_time(@start_time)} seconds to collapse in a steaming heap of failure.
172
180
 
173
181
  Have a nice day.
174
182
 
@@ -187,11 +195,11 @@ BODY
187
195
  body = <<-BODY
188
196
  Just wanted to let you know that:
189
197
 
190
- #{args.to_s}
198
+ #{@current_command}
191
199
 
192
200
  Is _STILL_ running on #{hostname}, it has not exited. You did want me to let you know didn't you?
193
201
 
194
- I started the darn thing at #{@start_time.to_s} (#{@start_time.to_i}) and it has taken a total of #{elapsed_time} seconds so far.
202
+ I started the darn thing at #{@start_time.to_s} (#{@start_time.to_i}) and it has taken a total of #{elapsed_time(@start_time)} seconds so far.
195
203
 
196
204
  Just thought you'd like to know. I'll continue to keep watching what you asked me to. (boor-ring!)
197
205
 
@@ -202,19 +210,19 @@ Tellmewhen
202
210
  #{email_footer}
203
211
  BODY
204
212
 
205
- send_email_notification "When! [NOT] I'm _still_ waiting for #{args.split.first}...", body
213
+ send_email_notification "When! [NOT] I'm _still_ waiting for #{@current_command.split.first}...", body
206
214
  end
207
215
 
208
216
  def email_footer
209
217
  return <<-END
210
218
  P.S. stderr says:
211
219
  --
212
- #{File.read(@stderr_file)}
220
+ #{File.read(@stderr_file,max_bytes_to_read_from_file)}
213
221
  --
214
222
 
215
223
  P.S. stdout says:
216
224
  --
217
- #{File.read(@stdout_file)}
225
+ #{File.read(@stdout_file,max_bytes_to_read_from_file)}
218
226
  --
219
227
  END
220
228
  end
@@ -226,13 +234,16 @@ P.S. stdout says:
226
234
 
227
235
  def wait_on_pid args
228
236
  # wait until pid exits
237
+ @current_command = "wait on pid: #{@options[:pid]}"
238
+ last_check_time = Time.now
229
239
  while pid_running? @options[:pid]
230
240
  sleep 0.250
231
- if elapsed_time > wait_timeout
241
+ if elapsed_time(last_check_time) > wait_timeout
242
+ last_check_time = Time.now
232
243
  puts "Exceeded timeout #{wait_timeout}, sending 'pending' notificaiton"
233
244
  send_email_notification "When! [NOT] still awaiting pid:#{pid} to exit", <<-END
234
245
 
235
- I started watching #{pid} on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), I've been watching 'em for #{elapsed_time} seconds so far.
246
+ I started watching #{pid} on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), I've been watching 'em for #{elapsed_time(@start_time)} seconds so far.
236
247
 
237
248
  Awaiting it's demise,
238
249
 
@@ -245,7 +256,7 @@ TellMeWhen
245
256
 
246
257
  send_email_notification "When! pid:#{@options[:pid]} has come to its end", <<-END
247
258
 
248
- I started watching #{@options[:pid]} on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), and now, after #{elapsed_time} seconds it has finally gone bellly up. #{@options[:pid]} will rest in peace as of #{@end_time.to_s} (#{@end_time.to_i})
259
+ I started watching #{@options[:pid]} on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), and now, after #{elapsed_time(@start_time)} seconds it has finally gone bellly up. #{@options[:pid]} will rest in peace as of #{@end_time.to_s} (#{@end_time.to_i})
249
260
 
250
261
  #{@options[:pid]} will be missed, it was a good little process. :,)
251
262
 
@@ -255,13 +266,16 @@ TellMeWhen
255
266
  end
256
267
 
257
268
  def wait_on_file_exists args
269
+ @current_command = "wait on file exists: #{@options[:trigger_file]}"
270
+ last_check_time = Time.now
258
271
  while !File.exist? @options[:trigger_file]
259
272
  sleep 0.250
260
- if elapsed_time > wait_timeout
273
+ if elapsed_time(last_check_time) > wait_timeout
274
+ last_check_time = Time.now
261
275
  puts "Exceeded timeout #{wait_timeout}, sending 'pending' notificaiton"
262
276
  send_email_notification "When! [NOT] still awaiting #{@options[:trigger_file]} to exist", <<-END
263
277
 
264
- I started watching for #{@options[:trigger_file]} on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), I've been watching for it #{elapsed_time} seconds so far.
278
+ I started watching for #{@options[:trigger_file]} on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), I've been watching for it #{elapsed_time(@start_time)} seconds so far.
265
279
 
266
280
  Awaiting it's arrival,
267
281
 
@@ -273,7 +287,7 @@ TellMeWhen
273
287
 
274
288
  send_email_notification "When! #{@options[:trigger_file]} now exists.", <<-END
275
289
 
276
- I started watching for #{@options[:trigger_file]} on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), and now, after #{elapsed_time} seconds it has finally shown up as of #{@end_time.to_s} (#{@end_time.to_i})
290
+ I started watching for #{@options[:trigger_file]} on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), and now, after #{elapsed_time(@start_time)} seconds it has finally shown up as of #{@end_time.to_s} (#{@end_time.to_i})
277
291
 
278
292
  What is thy next bidding my master?
279
293
 
@@ -282,16 +296,19 @@ TellMeWhen
282
296
  end
283
297
 
284
298
  def wait_on_file_modified args
299
+ @current_command = "wait on file modified: #{@options[:trigger_file]}"
285
300
  trigger_file = @options[:trigger_file]
286
301
  initial_mtime = File.mtime trigger_file
287
302
 
303
+ last_check_time = Time.now
288
304
  while initial_mtime == File.mtime(trigger_file)
289
305
  sleep 0.250
290
- if elapsed_time > wait_timeout
306
+ if elapsed_time(last_check_time) > wait_timeout
307
+ last_check_time = Time.now
291
308
  puts "Exceeded timeout #{wait_timeout}, sending 'pending' notificaiton"
292
309
  send_email_notification "When! [NOT] still awaiting #{@options[:trigger_file]} to change", <<-END
293
310
 
294
- I started watching for #{@options[:trigger_file]} to be updated on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), I've been watching for it #{elapsed_time} seconds so far.
311
+ I started watching for #{@options[:trigger_file]} to be updated on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), I've been watching for it #{elapsed_time(@start_time)} seconds so far.
295
312
 
296
313
  Awaiting it's update,
297
314
 
@@ -304,7 +321,7 @@ TellMeWhen
304
321
 
305
322
  send_email_notification "When! #{@options[:trigger_file]} was updated.", <<-END
306
323
 
307
- I started watching for #{@options[:trigger_file]} to be updated on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), and now, after #{elapsed_time} seconds it has finally been modified as of #{@end_time.to_s} (#{@end_time.to_i})
324
+ I started watching for #{@options[:trigger_file]} to be updated on #{hostname} at #{@start_time.to_s} (#{@start_time.to_i}), and now, after #{elapsed_time(@start_time)} seconds it has finally been modified as of #{@end_time.to_s} (#{@end_time.to_i})
308
325
 
309
326
  POSIX is my zen,
310
327
 
@@ -321,11 +338,21 @@ TellMeWhen
321
338
  end
322
339
 
323
340
  def send_email_notification subject, body
341
+ if @settings["email"]["method"] == "smtp"
342
+ send_email_notification_via_smtp subject, body
343
+ elsif @settings["email"]["method"] == "mailtools"
344
+ send_email_notification_via_mailtools subject, body
345
+ else
346
+ send_email_notification_via_smtp subject, body
347
+ end
348
+ end
349
+
350
+ def send_email_notification_via_smtp subject, body
324
351
  # optionally send via /usr/bin/mail or sendmail binary if it exists...
325
- puts "Sending email: from:#{@settings["email"]["from"]} to:#{@settings["email"]["to"]}"
352
+ puts "[SMTP] Sending email: from:#{@settings["email"]["from"]} to:#{@settings["email"]["to"]}"
326
353
  begin
327
354
  Net::SMTP.start(smtp_host, smtp_port) do |smtp|
328
- smtp.open_message_stream('from_addr', @settings["email"]["to"].split(',')) do |f|
355
+ smtp.open_message_stream(@settings["email"]["from"], @settings["email"]["to"].split(',')) do |f|
329
356
  f.puts "From: #{@settings["email"]["from"]}"
330
357
  f.puts "To: #{@settings["email"]["to"]}"
331
358
  f.puts "Subject: #{subject}"
@@ -335,7 +362,12 @@ TellMeWhen
335
362
  end
336
363
  end
337
364
  rescue Errno::ECONNREFUSED => e
365
+ send_email_notification_via_mailtools subject, body
366
+ end
367
+
368
+ def send_email_notification_via_mailtools subject, body
338
369
  if File.exist? "/usr/sbin/sendmail"
370
+ puts "[mailtools/sendmail] Sending email: from:#{@settings["email"]["from"]} to:#{@settings["email"]["to"]}"
339
371
  body_file = Tempfile.new("tellmewhen.mail.body")
340
372
  File.open(body_file.path,"w") do |f|
341
373
  f.puts "From: #{@settings["email"]["from"]}"
@@ -344,9 +376,11 @@ TellMeWhen
344
376
  f.puts ""
345
377
  f.write body
346
378
  end
379
+ puts "[sendmail] /usr/sbin/sendmail -f #{@settings["email"]["from"]} '#{@settings["email"]["to"]}' < #{body_file.path}"
380
+ #require 'ruby-debug'; debugger; 1;
347
381
  system "/usr/sbin/sendmail -f #{@settings["email"]["from"]} '#{@settings["email"]["to"]}' < #{body_file.path}"
348
382
  elsif File.exist? "/usr/bin/mail"
349
- raise "Implement sending via /usr/bin/mail"
383
+ puts "[mailtools/mail] Sending email: from:#{@settings["email"]["from"]} to:#{@settings["email"]["to"]}"
350
384
  body_file = Tempfile.new("tellmewhen.mail.body")
351
385
  File.open(body_file.path,"w") do |f|
352
386
  f.puts "From: #{@settings["email"]["from"]}"
Binary file
@@ -3,7 +3,7 @@ require 'rubygems'
3
3
 
4
4
  SPEC = Gem::Specification.new do |s|
5
5
  s.name = "tellmewhen"
6
- s.version = "1.0.1"
6
+ s.version = "1.0.2"
7
7
  s.author = "Kyle Burton"
8
8
  s.email = "kyle.burton@gmail.com"
9
9
  s.platform = Gem::Platform::RUBY
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tellmewhen
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 1
10
- version: 1.0.1
9
+ - 2
10
+ version: 1.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kyle Burton
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-25 00:00:00 -05:00
18
+ date: 2011-01-26 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -39,6 +39,7 @@ extra_rdoc_files: []
39
39
  files:
40
40
  - bin/tellmewhen
41
41
  - pkg/tellmewhen-1.0.0.gem
42
+ - pkg/tellmewhen-1.0.1.gem
42
43
  - Rakefile
43
44
  - README.textile
44
45
  - tellmewhen.gemspec