Re: Perl Style: About error messges opening files
by Abigail-II (Bishop) on Apr 27, 2004 at 10:56 UTC
|
My style highly depends on the intended users, and how often it will be used. If it's a program I distribute, or write for someone else to use, I use something like:
open my $fh => $file or die "Failed to open file '$file': $!\n";
If it's code I just write for myself, I use something like:
open my $fh => $file or die "open: $!\n";
or
open my $fh => $file or die "open '$file': $!\n";
depending on how many files the program opens.
If it's a 'write-today-discard-tomorrow' program, I use:
open my $fh => $file or die "$!\n";
or even
open my $fh => $file or die;
I use the latter style when writing on the command line too.
Note that (except in the last case) I include a trailing newline. Most of the time, I couldn't care less on which line of the program an error occurs, especially not when
it's about opening files.
I've been writing some C lately, and I've started appreciating perror. Perhaps I should write a
little module give similar functionality.
Abigail | [reply] [d/l] [select] |
|
I've been writing some C lately, and I've started appreciating perror. Perhaps I should write a little module give similar functionality.
Hmm. A start would be to just tell those of us who have never heard of it a bit about it. :-) (Like me.)
And I usually leave the die line numbering enabled in my scripts. Most of the time my scripts are running on cron jobs in the background and when files arent there its usually a serious matter and I want to be able to track it back from the line it died from. Since the error messages get logged automatically it doesnt much bother folks. When its user displayed ill often do something like
die "File '$foo' doesnt seem to exist!\n" unless -e $foo;
open my $foo_fh,"<"',$foo or die "<$!:$foo";
So that the common case errors are trapped specifically and the general case stuff that probably indicate more serious things are trapped by the open.
---
demerphq
First they ignore you, then they laugh at you, then they fight you, then you win.
-- Gandhi
| [reply] [d/l] [select] |
|
A start would be to just tell those of us who have never heard of it a bit about it.
PERROR(3) Library functions PERROR(3)
NAME
perror - print a system error message
SYNOPSIS
#include <stdio.h>
void perror(const char *s);
#include <errno.h>
const char *sys_errlist[];
int sys_nerr;
DESCRIPTION
The routine perror() produces a message on the standard
error output, describing the last error encountered during
a call to a system or library function. First (if s is
not NULL and *s is not NUL) the argument string s is
printed, followed by a colon and a blank. Then the mes-
sage and a new-line.
To be of most use, the argument string should include the
name of the function that incurred the error. The error
number is taken from the external variable errno, which is
set when errors occur but not cleared when non-erroneous
calls are made.
The global error list sys_errlist[] indexed by errno can
be used to obtain the error message without the newline.
The largest message number provided in the table is
sys_nerr -1. Be careful when directly accessing this list
because new error values may not have been added to
sys_errlist[].
When a system call fails, it usually returns -1 and sets
the variable errno to a value describing what went wrong.
(These values can be found in <errno.h>.) Many library
functions do likewise. The function perror() serves to
translate this error code into human-readable form. Note
that errno is undefined after a successful library call:
this call may well change this variable, even though it
succeeds, for example because it internally used some
other library function that failed. Thus, if a failing
call is not immediately followed by a call to perror, the
value of errno should be saved.
CONFORMING TO
ANSI C, BSD 4.3, POSIX, X/OPEN
SEE ALSO
strerror(3)
2001-12-14 PERROR(3)
And here's a way one might do it in Perl:
package PError;
use strict;
use warnings;
our ($VERSION) = q $Revision: 1.1 $ =~ /([\d.]+)/g;
sub perror {warn @_ ? "@_: $!\n" : "$!\n"}
sub pdie {die @_ ? "@_: $!\n" : "$!\n"}
my %symbols = map {$_ => 1} qw /perror pdie/;
sub import {
my $class = shift;
my $caller = caller;
foreach my $name (@_ ? @_ : keys %symbols) {
die "'$name' is not exported.\n" unless $symbols {$name};
my $func = $name eq "pwarn" ? "perror" : $name;
no strict 'refs';
*{$caller . "::$name"} = \&{$class . "::$func"}
}
}
1;
__END__
when files arent there its usually a serious matter and I want to be able to track it back from the line it died from.
I guess you and I differ. If a file is missing, than I will investigate why the file isn't there, and I'll start at the place that's supposed to produce the file. A line number in the program that figured out the file wasn't there doesn't do much for me.
Abigail | [reply] [d/l] [select] |
|
|
|
|
OT, but yet another style question for Abigail, since '=>' was like crazy again...
I've noticed you use => in place of commas .. a lot. <seinfeld>not that there is anything wrong with that</seinfeld>. I'm still one that uses => only for hash construction, when I need to imply a key-value pair, or maybe in a map, but anyway, when I need the implicit LHS quoting and a comma.
In one of your examples, you gave something like
system mkdir => -p => $foo;
while most would do something closer to:
system("mkdir -p $foo");
Care to explain why this is syllistically more interesting to you? My guess is no, but we're on a style thread and this just looks odd to me. I'm thinking you were nearly eaten by a pack of rabid commas when you were a child or something :) Ok, so I'm not going to use '=>' any more because of what you might say, I'm just curious ... sort of like a 'where did that accent come from' type of question.
(commence with the moose stoning)
| [reply] [d/l] [select] |
|
push @array => 1, 2, 3, 4;
printf "%s %6d %s" => $foo, $bar, $baz;
pack "C" => $var;
splice @array => 0, 3 => "foo", "bar", "baz";
Etc. I've used that long before people started preaching that => was some kind of pair creator. It never was, and still isn't. And I'm not the only one using this style, Larry Rosler (of GRT fame) was a vivid user of this style as well.
Abigail | [reply] [d/l] [select] |
|
|
system("mkdir -p $foo");
because that would be interpreted by the shell, and would foul up if (for example) $foo contained a filename with spaces. The advantage of using the arrow instead of the comma is that you can get away with less quoting, compare:
system mkdir => -p => $foo;
system 'mkdir', '-p', $foo;
Same number of chars, arguably more readable.
| [reply] [d/l] [select] |
|
|
You surely mean the list variant of system:
system "mkdir", "-p", $foo
| [reply] [d/l] |
|
|
|
|
I never put a newline there, the line numbers at the error message do not cause any harm.
(Line numbers as there are two: one for the source file and one for <>.)
In one-liners I usually just use numbers after die:
open my $F, "<", $name or die 1;
I use numbers as they show where the error occured if there are
multiple die statements in a one-liner, but they are short and easy to write.
I add $! if the error really occurs and I don't know why it happened.
| [reply] [d/l] |
Re: Perl Style: About error messges opening files
by grinder (Bishop) on Apr 27, 2004 at 11:14 UTC
|
I like having the error messages following the resource in question and a colon; all the rest of the Unix toolkit tends to follow that philosophy, and I don't see any value in bucking the trend.
By force of habit I write my error messages out in longhand, in a vague attempt to make things clearer:
open IN, '<', $file or die "Cannot open $file for input: $!\n";
open OUT, '>>', $file or die "Cannot open $file for append: $!\n";
open P, '|', $cmd or die "Cannot open input pipe from $cmd: $!\n";
I'm in two minds about your idea. If a non-programmer were to read me the message (or a programmer without shell-redirection experience, which is pretty much the same thing) they might omit pronouncing < altogether or describe it uselessly (e.g. "arrow"). That's why I like wordy error messages.
On the other hand, if I were to adopt this idea, I wouid be tempted to push things to extremes, and factor out the redirection into a variable:
my $whence = '<';
open my $fh, $whence, $file or die "$whence $!:$file";
... on the principle that if you change it to <+ or something else you only have to do that in one place. But I'll be the first to say that that's getting silly.
Colour me unconvinced. But I think the 3-arg open is the thing. For all of you who have tuned in recently, here's the canonical thread on the subject: Two-arg open() considered dangerous. | [reply] [d/l] [select] |
|
On the other hand, if I were to adopt this idea, I wouid be tempted to push things to extremes, and factor out the redirection into a variable:
Yep, I use a subroutine very much like that quite often. The sub usually looks more like:
sub my_open {
my ($file,$mode,$error_text)=@_;
$mode||='<';
$error_text||="While opening in '$mode':$!:$file";
open my $fh, $mode, $file
or Carp::confess $error_text;
return $fh
}
I like having the error messages following the resource in question and a colon; all the rest of the Unix toolkit tends to follow that philosophy, and I don't see any value in bucking the trend.
Good point.
Colour me unconvinced.
I wasnt trying to convince people, just to see what they thought. :-)
---
demerphq
First they ignore you, then they laugh at you, then they fight you, then you win.
-- Gandhi
| [reply] [d/l] [select] |
Re: Perl Style: About error messges opening files
by Corion (Patriarch) on Apr 27, 2004 at 11:11 UTC
|
I use the 3-argument form of open when I don't intend the script to be usable on 5.5, which happens more and more often.
But I always make sure to quote the filename, because users give their files weird names that even can look like an error message. I always give the error message some more context, so I can later on grep the source program for the line where the error was raised:
open F, "<", $file
or die "Couldn't open '$file' : $!\n";
Supposedly, there is only one place in the program where the message Couldn't open occurs of course. The idea of reversing the filename is interesting - that way, the interesting bits (filename and error message) are at the start and at the end of the "line" - using my way, the interesting bits clog together at the end.
I prefer my style, of course :). | [reply] [d/l] |
|
I'll raise a glass to that! Through a bug in my code I recently scattered a bunch of fields all over a database I was working on where in qw(field_name value value value ...) the name was discarded, the first value became the name and everything else after was the new value. Quite ugly. It also explains why I had filenames which were SQL fragments.
| [reply] [d/l] |
Re: Perl Style: About error messges opening files
by Juerd (Abbot) on Apr 27, 2004 at 14:10 UTC
|
use Fatal qw(open);
| [reply] [d/l] |
Re: Perl Style: About error messges opening files
by dragonchild (Archbishop) on Apr 27, 2004 at 12:09 UTC
|
Although this isn't completely on point, I tend to put single-quotes around every variable in a print/warn/die statement. So, my version of your line would be:
open my $fh,"<",$file or die "< $!:'$file'";
That way, I can determine if it's zero, one, or two spaces in my filename. Or, if there are postpended spaces. (Once bitten, twice shy, I guess.)
------
We are the carpenters and bricklayers of the Information Age.
Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose
| [reply] [d/l] |
Re: Perl Style: About error messges opening files
by jonadab (Parson) on Apr 27, 2004 at 20:10 UTC
|
I agree with Abigail that it definitely matters who's
going to see this message. If it's going to show up
in an error log, I just make sure it's a unique string
that I can grep for easily, something like this:
foo or die "sorrow, pestilence, Notepad: $!$/";
As long as I don't use the same error string twice,
it takes about two seconds to find the place where
the problem is.
If it's an error message that an end user is going to
see, I do something rather different...
open FOO, "<$foo" or fatalerror "Couldn't Read Foo: $!";
# and off in an include file somewhere I define...
sub fatalerror {
my $email = $ENV{SERVER_ADMIN};
use HTML::Entities;
my $code = encode_entities(shift);
my $fm = <<"FRIENDLYMESSAGE";
<p class=\"error\">Oops! I seem to have run
into a problem! This is probably a bug
in the software on this site, something
that the webmaster needs to fix. If
this problem persists, you can contact the
webmaster at <a href="mailto:$email">$email</a>
and report the problem. It might get fixed
faster if you include the exact technical
error code that follows.
</p>
<p class=\"error\">Technical Error Code: $code</p>
FRIENDLYMESSAGE
# And then I output a page containing $fm in the
# usual fashion.
}
This is for CGI, which in my case is the only kind
of interface used for stuff that end users see, but
you can imagine a similar sort of thing for GUI stuff.
;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}}
split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print
| [reply] [d/l] [select] |
|
I have a logging module that "plugs in" to perl. Anything (or nearly anyway) going out on STDERR or STDOUT, even via die or warn, is automatically captured and logged with the time it happened, the line of code responsible, what "channel" was used (ie STDOUT or STDERR) and a few other bits and bobs, some automatic and some provided by the author of the script using the module. It also send automatic success/failure emails including a full stack backtrace and running enviornment of the script (in the case of error anyway.) The result of all this is I havent had to grep a logfile for a specific message in a long time. When something I wrote or maintain crashes I get an email with all the relevent details. If I need to review the logfiles to see what else was happening at the time I have alot more to go on than the fact that I was sufficiently creative with my message such that it was unique in the script. Which I know from experience is not a given at all. :-)
My point here is that if you are using proper logging then unique error messages and the like are unnecessary. If its going to be an end-user-facing error message of course this is different. But as I said elsewhere in this thread virtually all of my code runs as background tasks and pretty error messages arent called for.
I actually have permission from my boss to release the module, but ive never had the time to clean it up and make it more portable. Its somewhat Win32 biased, with hooks for the event log and other win32 tricks, and since the equivelent Unixy bias annoys me (because I cant play with the toys) id rather not be responsible for the opposite.
BTW, I assume your use of $/ is only for brevity... Ive been bitten once too often by that trick to think its particularly useful out of one liners.
---
demerphq
First they ignore you, then they laugh at you, then they fight you, then you win.
-- Gandhi
| [reply] [d/l] |
|
If it's going to show up in an error log, I just make sure it's a unique string that I can grep for easily
Ehm. I always thought the filename and line number included in the error message (if you don't let it end in \n) made that unnecessary. They're not scary, not even to beginners. Beginners learn to ignore these things the minute they start using a unixish system, developers learn to look at the line mentioned. That way, you increase the chance of getting a patch with the bug report if it happens to be a bug.
Besides, going to a certain line number is much faster and easier than grepping or searching.
| [reply] |
|
s/mumble foo:/missing input file:/
s/bonk:/unknown request:/
s/what the frell:/data base seems broken:/
| [reply] [d/l] |
|
going to a certain line number is much faster and easier than grepping or searching
Not in my experience. A line number is harder to hold
in your head, so you probably have to copy-and-paste
it from wherever (browser, email, log, ...) into
the jump-to-line feature of your text editor. As
opposed to just hitting ctrl-S and typing the first
N characters of a phrase. By the time you get to
the second word, you're there usually there.
I always thought the filename and line number included in the error message
If you're getting the error message from a logfile or
at the command prompt maybe. If an end user sees the
message and tries to remember it to tell you, the
chances of a full filepath coming through accurately,
much less a line number, are vanishingly close to
zero. A phrase like "Twinkies and Spandex"
is significantly more likely to get to you intact.
;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}}
split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print
| [reply] |
|
|
|