tellmewhen 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.textile +95 -6
- data/bin/tellmewhen +56 -22
- data/pkg/tellmewhen-1.0.1.gem +0 -0
- data/tellmewhen.gemspec +1 -1
- metadata +5 -4
data/README.textile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
h1. tellmewhen
|
2
2
|
|
3
|
-
Tell me when another program has finshed.
|
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
|
13
|
-
*
|
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
|
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
|
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
|
|
data/bin/tellmewhen
CHANGED
@@ -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 -
|
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
|
-
#{
|
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 #{
|
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(
|
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
|
-
|
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
|
data/tellmewhen.gemspec
CHANGED
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:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 1.0.
|
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-
|
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
|