Error Exception if script doesn't run


#1

I need to know if my script fails to run for any reason and capture the
exception. I know how to use “rescue” for small pieces of code but how
can I capture the stderr for anything in the script?

thanks

jack


#2

jackster the jackle wrote:

I need to know if my script fails to run for any reason and capture the
exception. I know how to use “rescue” for small pieces of code but how
can I capture the stderr for anything in the script?

If you want to capture only an exception then wrap it like this:

begin

… rest of script

rescue Exception => e
… do something with e, e.g. write it to a log file
end

However if you want to capture everything written to stderr then that’s
a different problem. That’s the responsibility of whoever started the
Ruby process, since it would have passed it an open file descriptor for
stderr (fd 2). For example, if you are starting ruby from a shell, then

$ ruby foo.rb 2>errors.log

But if you were launching it from another Ruby process, then look at
open3.rb in the standard library.


#3

that does exactly what I had hoped…thanks alot!

jack


#4

I notice that any shell commands that I have in the script that fail do
not trigger a Ruby exception, how do I get my Ruby script to send these?

thanks

jack

Brian C. wrote:

jackster the jackle wrote:

I need to know if my script fails to run for any reason and capture the
exception. I know how to use “rescue” for small pieces of code but how
can I capture the stderr for anything in the script?

If you want to capture only an exception then wrap it like this:

begin

… rest of script

rescue Exception => e
… do something with e, e.g. write it to a log file
end

However if you want to capture everything written to stderr then that’s
a different problem. That’s the responsibility of whoever started the
Ruby process, since it would have passed it an open file descriptor for
stderr (fd 2). For example, if you are starting ruby from a shell, then

$ ruby foo.rb 2>errors.log

But if you were launching it from another Ruby process, then look at
open3.rb in the standard library.


#5

It seems to work but not for this command, perhaps since scp gets
executed (but does not complete) the system variable is not false?

`scp -i /home/jsmith/.ssh/id_rsa /files*.tar jsmith@172.20.1.1:`

The error code I get when I run the script manually is as follows
because 172.20.1.1 is no longer on the network:

ssh: connect to host 172.20.1.1 port 22: No route to host
lost connection

I was hoping the system variable would trip when this command fails?

jack

Joel VanderWerf wrote:

jackster the jackle wrote:

I notice that any shell commands that I have in the script that fail do
not trigger a Ruby exception, how do I get my Ruby script to send these?

Check the return value of #system, like this:

irb(main):002:0> unless system “false”; puts “failed!”; end
failed!
=> nil


#6

jackster the jackle wrote:

ssh: connect to host 172.20.1.1 port 22: No route to host
lost connection

I was hoping the system variable would trip when this command fails?

jack

In the general case, when a command succeeds it returns 0 and when it
fails it returns something else. However, this is a convention, not a
rule. It is entirely possible for a command to fail and still return 0.
If so, you can’t determine if it fails by simply checking the return
code. I have no idea whether or not scp returns non-0 on failure. You
can check by running it yourself in a shell. Immediately after it fails
enter ‘echo $?’. This will show you the exit status. For example:

~$ ls test.rb
test.rb
~$ echo $?
0
~$ ls nothere
ls: nothere: No such file or directory
~$ echo $?
1

If your scp command returns 0 in this case then the only way to detect
that it failed is to inspect the message, which it probably is writing
to stderr.

More information about exit status and $? can be found on the Internet.


#7

Tim H. wrote:

~$ ls test.rb
test.rb
~$ echo $?
0
~$ ls nothere
ls: nothere: No such file or directory
~$ echo $?
1

Based on what you have described, I think I have figured out a way to
make it work…but I still have one question.

When the following command completes successfully:
y= cp /home/jsmith/js.txt /home/jsmith/js2.txt
puts $?

$? equals 0, however if I change the path to js.txt to something that
doesn’t exist in order to make it fail, $? has a value of 256.

I thought $? should always have a value of 1 when it fails? Why is it
256?

thanks
jack


#8

jackster the jackle wrote:

I notice that any shell commands that I have in the script that fail do
not trigger a Ruby exception, how do I get my Ruby script to send these?

Check the return value of #system, like this:

irb(main):002:0> unless system “false”; puts “failed!”; end
failed!
=> nil


#9

On Fri, Oct 17, 2008 at 6:11 PM, jackster the jackle <
removed_email_address@domain.invalid> wrote:

It seems to work but not for this command, perhaps since scp gets
executed (but does not complete) the system variable is not false?

`scp -i /home/jsmith/.ssh/id_rsa /files*.tar jsmith@172.20.1.1:`

I would recommend using rsync instead of scp.
You could do first an rsync and then perform a --dry-run to confirm that
your
data has been transferred correctly.

-drd


#10

On Sat, Oct 18, 2008 at 2:48 PM, jackster the jackle
removed_email_address@domain.invalid wrote:

Based on what you have described, I think I have figured out a way to
256?
It is an error code, so it’s sometimes other values than 1. Success is
always 0.


#11

jackster the jackle wrote:

$? equals 0, however if I change the path to js.txt to something that
doesn’t exist in order to make it fail, $? has a value of 256.

That’s because the low-order 8 bits of $? encode something different;
the next 7 bits are the exit code (0 to 127). Use $?.exitstatus to get
that.

http://www.ruby-doc.org/core/classes/Process/Status.html

I thought $? should always have a value of 1 when it fails? Why is it
256?

The exit status in this case is 256 >> 8, which is 1.


#12

Brian C. wrote:

jackster the jackle wrote:

$? equals 0, however if I change the path to js.txt to something that
doesn’t exist in order to make it fail, $? has a value of 256.

That’s because the low-order 8 bits of $? encode something different;
the next 7 bits are the exit code (0 to 127). Use $?.exitstatus to get
that.

http://www.ruby-doc.org/core/classes/Process/Status.html

I thought $? should always have a value of 1 when it fails? Why is it
256?

The exit status in this case is 256 >> 8, which is 1.

this code seems to work well for what I need:

cp /xhome/jsmith/js.txt /home/jsmith/js2.txt
unless $?.success?; raise “error with: #{$0}” ; end

I would like to be able to add the line number of the file into the
error message with the file name ($0) but when I try other global
variables such as $@ or $. I don’t get the line number of the script
that failed?

jack


#13

jackster the jackle wrote:

I would like to be able to add the line number of the file into the
error message with the file name ($0) but when I try other global
variables such as $@ or $. I don’t get the line number of the script
that failed?

Use FILE and LINE

You probably don’t want $0, although it will work if all your code is in
one file; if your script was called foo.rb but it did “require ‘bar’”
and the error was in bar.rb, then FILE would be bar.rb but $0 would
be foo.rb

But in any case, you don’t need this because

raise “Hell”

gives you a stack backtrace anyway, the first line of which is the line
where the raise occurred.

begin
raise “Hell”
rescue Exception => e
puts “Error: #{e.message} at #{e.backtrace.first}”
end


#14

On Sun, Oct 19, 2008 at 1:19 PM, jackster the jackle
removed_email_address@domain.invalid wrote:

I would like to be able to add the line number of the file into the
error message with the file name ($0) but when I try other global
variables such as $@ or $. I don’t get the line number of the script
that failed?

Look into LINE

HTH,
Michael G.


#15

That really helps clear things up…thanks.

I am almost there but have been struggling to get my e.message into my
sendmail statement.

This code works perfectly but does not contain the value of e in my
email:

rescue Exception => e
#puts e.message ->prints out correctly
#puts e.backtrace.first -> prints out correctly
if e
echo "Subject:Error Message\n" | /usr/sbin/sendmail -f my_server\@server.com john.smith\@email.com
end
end

When I try to add the value of e into my email message, it won’t send:

echo "Subject:Error Message\n #{e.message}" | /usr/sbin/sendmail -f my_server\@server.com john.smith\@email.com

I think it has something to do with the ` and " characters but I have
tried every possible combination and I can’t figure out why doesn’t
work?

thanks

jack

Brian C. wrote:

jackster the jackle wrote:

I would like to be able to add the line number of the file into the
error message with the file name ($0) but when I try other global
variables such as $@ or $. I don’t get the line number of the script
that failed?

Use FILE and LINE

You probably don’t want $0, although it will work if all your code is in
one file; if your script was called foo.rb but it did “require ‘bar’”
and the error was in bar.rb, then FILE would be bar.rb but $0 would
be foo.rb

But in any case, you don’t need this because

raise “Hell”

gives you a stack backtrace anyway, the first line of which is the line
where the raise occurred.

begin
raise “Hell”
rescue Exception => e
puts “Error: #{e.message} at #{e.backtrace.first}”
end


#16

I finally figured out the last problem which was why some of my Ruby
generated errors that were were not able to be included in my sendmail
command. The problem was the error that was contained in my “e” value
had some text with ` and ’ characters in them as follows:

undefined local variable or method `bad_code_here’ for main:Object

Once I added some gsub code to remove those characters, all is working
well and I get an email with the error regardless of whether a shell
command or ruby code were the cause of the error. Here is my final code
which I will now implement in all my scripts (unless someone sees
another problem) so I’m no longer blind sided by know-it-alls here at
work that come to me with “you know your scripts have failed, don’t
you?” :slight_smile:

begin

z = `cp /home/jsmith/js.txt /home/jsmith/js2.txt`
unless $?.success?; raise "Shell Command Failure for line #{__LINE__} in 
#{__FILE__}" ; end

# The following line of code will cause Ruby to generate an error
bad_code_here

rescue Exception => e
   if e
     puts e
     e.to_s.gsub!("'","-")
     e.to_s.gsub!("`","-")
     %x{echo "Subject: Script Error: #{__FILE__}:#{__LINE__}\n\n#{e}"  | 
/usr/sbin/sendmail -f my_server\@gmail.com john.smith\@email.com}
   end
end

Thanks to everyone for all the help, I learned alot.
jack


#17

Hi,

At Tue, 21 Oct 2008 03:30:44 +0900,
jackster the jackle wrote in [ruby-talk:318164]:

Once I added some gsub code to remove those characters, all is working
well and I get an email with the error regardless of whether a shell
command or ruby code were the cause of the error. Here is my final code
which I will now implement in all my scripts (unless someone sees
another problem) so I’m no longer blind sided by know-it-alls here at
work that come to me with “you know your scripts have failed, don’t
you?” :slight_smile:

I’d rather use popen.

rescue Exception => e
if e
puts e

   IO.popen("-", "w") do |mail|
     mail or exec(*%w"/usr/sbin/sendmail -f removed_email_address@domain.invalid 

removed_email_address@domain.invalid")
mail.puts “Subject: Script Error: #{e.backtrace[0]}”
mail.puts
mail.puts e

and anything what you want to send

   end

#18

Nobuyoshi N. wrote:

I’d rather use popen.

rescue Exception => e
if e
puts e

   IO.popen("-", "w") do |mail|
     mail or exec(*%w"/usr/sbin/sendmail -f removed_email_address@domain.invalid 

removed_email_address@domain.invalid")
mail.puts “Subject: Script Error: #{e.backtrace[0]}”
mail.puts
mail.puts e

and anything what you want to send

   end

Would you happen to know how to send an attachment using the popen code?

thanks

jack


#19

Nobuyoshi N. wrote:

I’d rather use popen.

rescue Exception => e
if e
puts e

   IO.popen("-", "w") do |mail|
     mail or exec(*%w"/usr/sbin/sendmail -f removed_email_address@domain.invalid 

removed_email_address@domain.invalid")
mail.puts “Subject: Script Error: #{e.backtrace[0]}”
mail.puts
mail.puts e

and anything what you want to send

   end

wow! so much better!

thanks alot for showing me that

jack


#20

Hi,

At Wed, 22 Oct 2008 03:55:39 +0900,
jackster the jackle wrote in [ruby-talk:318263]:

Would you happen to know how to send an attachment using the popen code?

See RFC5322 and RFC2387.