Codebase list liblog-report-perl / v0.03
distribution Log-Report-0.03.tar.gz Mark Overmeer authored 16 years ago Mark Overmeer committed 6 years ago
20 changed file(s) with 333 addition(s) and 199 deletion(s). Raw diff Collapse all Expand all
00
11 ==== version history of Log::Report
2
3 version 0.03: Mon May 28 20:16:26 CEST 2007
4 - Log::Report::Message without msgid forgot _append.
5 - Log::Report::Message must clone at concatenation.
6 - remove translations from POT when not referenced anymore, and
7 not translated either.
8 - $@ after try will not show the message, because we want people
9 to use reportAll() or reportFatal().
10 - dispatchers now have a format_reason, defaulting to LOWERCASE
11 which looks nicer than uppercase.
12 - added docs to ::Try
13 - reorganized some docs.
14 - Log::Report::Util lacked the trailing "1;"
15 - fall-back to no translation in case of unknown locale in ::POT
16 - test functionality of setlocale, and hopefully fixed things
217
318 version 0.02: Mon May 28 00:49:52 CEST 2007
419 - added HTML documentation to http://perl.overmeer.net/log-report/
2035 . t/50file.t failed because no -t STDERR
2136
2237 version 0.01: Fri May 25 12:13:13 CEST 2007
23 - initial
38 - initial (quite complete) implementation.
2222 lib/Log/Report/messages/log-report.utf-8.po
2323 lib/Log/Report/messages/log-report/nl_NL.po
2424 t/00use.t
25 t/01locale.t
2526 t/05util.t
2627 t/10interp.t
2728 t/11concat.t
33
44 WriteMakefile
55 ( NAME => 'Log::Report'
6 , VERSION => '0.02'
6 , VERSION => '0.03'
77 , PREREQ_PM => { Test::More => 0.47 }
88 , AUTHOR => 'Mark Overmeer'
99 , ABSTRACT => 'report a problem, pluggable handlers and language support'
3030 Log::Report::Dispatcher::Syslog - send messages to syslog
3131
3232 =chapter SYNOPSIS
33 # add syslog dispatcher
3334 dispatcher SYSLOG => 'syslog', accept => 'NOTICE-'
35 , format_reason => 'IGNORE'
3436 , to_prio => [ 'ALERT-' => 'err' ];
3537
3638 # disable default dispatcher
37 dispatcher close => 'syslog';
39 dispatcher close => 'stderr';
3840
3941 =chapter DESCRIPTION
4042 This dispatchers produces output to syslog, based on the M<Sys::Syslog>
6466 =section Constructors
6567
6668 =c_method new TYPE, NAME, OPTIONS
69 With syslog, people tend not to include the REASON of the message
70 in the logs, because that is already used to determine the destination
71 of the message. Use M<new(format_reason)> with C<IGNORE> to achieve
72 that.
6773
6874 =option identity STRING
6975 =default identity <basename $0>
1010 Log::Report::Dispatcher::Try - capture all reports as exceptions
1111
1212 =chapter SYNOPSIS
13 try { ... }
14 print ref $@; # Log::Report::Dispatcher::Try
13 try { ... }; # mind the ';' !!
14 if($@) { # signals something went wrong
15
16 if(try {...}) { # block ended normally
17
18 try { ... } # no comma!!
19 mode => 'DEBUG', accept => 'ERROR-';
20
21 try sub { ... }, # with comma
22 mode => 'DEBUG', accept => 'ALL';
23
24 try \&myhandler, accept => 'ERROR-';
25
26 print ref $@; # Log::Report::Dispatcher::Try
27
28 $@->reportFatal; # redispatch result of try block
29 $@->reportAll; # ... also warnings etc
30 if($@) {...} # if errors
31 if($@->failed) { # same # }
32 if($@->success) { # no errors # }
33
34 try { report {to => 'stderr'}, FAILURE => 'no network' };
35 $@->reportFatal(to => 'syslog'); # overrule destination
1536
1637 =chapter DESCRIPTION
38 The M<Log::Report::try()> catches errors in the block (CODE
39 reference) which is just following the function name. All
40 dispatchers are temporarily disabled by C<try>, and messages
41 which are reported are collected within a temporary dispatcher
42 named C<try>. When the CODE has run, that C<try> dispatcher
43 is returned in C<$@>, and all original dispatchers reinstated.
44
45 Then, after the C<try> has finished, the routine which used
46 the "try" should decide what to do with the collected reports.
47 These reports are collected as M<Log::Report::Exception> objects.
48 They can be ignored, or thrown to a higher level try... causing
49 an exit of the program if there is none.
1750
1851 =chapter OVERLOADING
1952
3063
3164 use overload
3265 bool => 'failed'
33 , '""' => 'printError';
66 , '""' => 'showStatus';
3467
3568 =chapter METHODS
3669
112145 $self;
113146 }
114147
115 =method reportAll
148 =method reportAll OPTIONS
116149 Re-cast the messages in all collect exceptions into the defined
117 dispatchers, which were disabled during the try block.
118 =cut
119
120 sub reportAll() { $_->throw for shift->exceptions }
150 dispatchers, which were disabled during the try block. The OPTIONS
151 will end-up as HASH-of-OPTIONS to M<Log::Report::report()>; see
152 M<Log::Report::Exception::throw()> which does the job.
153 =cut
154
155 sub reportAll(@) { $_->throw(@_) for shift->exceptions }
121156
122157 =method reportFatal
123158 Re-cast only the fatal message to the defined dispatchers. If the
124 block was left without problems, then nothing will be done.
125 =cut
126
127 sub reportFatal() { $_->throw for shift->wasFatal }
159 block was left without problems, then nothing will be done. The OPTIONS
160 will end-up as HASH-of-OPTIONS to M<Log::Report::report()>; see
161 M<Log::Report::Exception::throw()> which does the job.
162 =cut
163
164 sub reportFatal(@) { $_->throw(@_) for shift->wasFatal }
128165
129166 =section Status
130167
148185 $self->{died} ? $self->{exceptions}[-1] : ();
149186 }
150187
151 =method printError
188 =method showStatus
152189 If this object is kept in C<$@>, and someone uses this as string, we
153190 want to show the fatal error message.
154 =cut
155
156 sub printError()
191
192 The message is not very informative for the good cause: we do not want
193 people to simply print the C<$@>, but wish for a re-cast of the message
194 using M<reportAll()> or M<reportFatal()>.
195 =cut
196
197 sub showStatus()
157198 { my $fatal = shift->wasFatal or return '';
158 # don't use '.', because it is overloaded for message
159 join('', $fatal->reason, ': ', $fatal->message, "\n");
199 __x"try-block stopped with {reason}", reason => $fatal->reason;
160200 }
161201
162202 1;
8686 You are adviced to use the symbolic mode names when the mode is
8787 changed within your program: the numerical values are available
8888 for smooth M<Getopt::Long> integration.
89
90 =option format_reason 'UPPERCASE'|'LOWERCASE'|'UCFIRST'|'IGNORE'|CODE
91 =default format_reason 'LOWERCASE'
92 How to show the reason text which is printed before the message. When
93 a CODE is specified, it will be called with a translated text and the
94 returned text is used.
95
8996 =cut
9097
9198 sub new(@)
9299 { my ($class, $type, $name, %args) = @_;
93100
94101 my $backend
95 = $predef_dispatchers{$type} ? $predef_dispatchers{$type}
96 : $type->isa('Log::Dispatch::Output')
97 ? __PACKAGE__.'::LogDispatch' # wrapper initializer
98 : $type->isa('Log::Log4perl')
99 ? __PACKAGE__.'::Log4perl' # wrapper initializer
102 = $predef_dispatchers{$type} ? $predef_dispatchers{$type}
103 : $type->isa('Log::Dispatch::Output') ? __PACKAGE__.'::LogDispatch'
104 : $type->isa('Log::Log4perl') ? __PACKAGE__.'::Log4perl'
100105 : $type;
101106
102107 eval "require $backend";
106111 ->init(\%args);
107112 }
108113
114 my %format_reason =
115 ( LOWERCASE => sub { (lc $_[0]) . ': ' }
116 , UPPERCASE => sub { (uc $_[0]) . ': ' }
117 , UCFIRST => sub { (ucfirst lc $_[0]) . ': '}
118 , IGNORE => sub { '' }
119 );
120
109121 sub init($)
110122 { my ($self, $args) = @_;
111123 my $mode = $self->_set_mode(delete $args->{mode} || 'NORMAL');
114126
115127 my $accept = delete $args->{accept} || $default_accept[$mode];
116128 $self->{needs} = [ expand_reasons $accept ];
129
130 my $f = delete $args->{format_reason} || 'LOWERCASE';
131 $self->{format_reason} = ref $f eq 'CODE' ? $f : $format_reason{$f}
132 or error __x"illegal format_reason '{format}' for dispatcher",
133 format => $f;
134
117135 $self;
118136 }
119137
224242
225243 my $text;
226244 if($translate)
227 { $text = (__$reason)->toString. ': '. $message->toString;
245 { $text = $self->{format_reason}->((__$reason)->toString)
246 . $message->toString;
228247 $text .= ': ' . strerror($opts->{errno}) if $opts->{errno};
229248 $text .= "\n";
230249 }
231250 else
232 { $text = $reason . ': ' . $message->untranslated;
251 { $text = $self->{format_reason}->($reason) . $message->untranslated;
233252 $text .= ': '. strerror($opts->{errno}) if $opts->{errno};
234253 $text .= "\n";
235254 }
5959 Insert the message contained in the exception into the currently
6060 defined dispatchers. The C<throw> name is commonly known
6161 exception related terminology for C<report>.
62
63 The OPTIONS overrule the captured options to M<Log::Report::report()>.
64 This can be used to overrule a destination.
65
66 =example overrule defaults to report
67 try { print {to => 'stderr'}, ERROR => 'oops!' };
68 $@->reportFatal(to => 'syslog');
6269 =cut
6370
6471 # if we would used "report" here, we get a naming conflict with
6572 # function Log::Report::report.
6673 sub throw(@)
6774 { my $self = shift;
68 report $self->{report_opts}, $self->reason, $self->message;
75 my $opts = @_ ? { %{$self->{report_opts}}, @_ } : $self->{report_opts};
76 report $opts, $self->reason, $self->message;
6977 }
7078
7179 1;
374374
375375 =method toString OPTIONS
376376 Format the object into a multi-lined string.
377
377378 =option nr_plurals INTEGER
378379 =default nr_plurals C<undef>
379380 If the number of plurals is specified, then the plural translation
452453 join '', @text;
453454 }
454455
456 =method unused
457 The message-id has no references anymore and no translations.
458 =cut
459
460 sub unused()
461 { my $self = shift;
462 ! $self->references && ! $self->msgstr(0);
463 }
464
455465 1;
201201 my $index = $self->index;
202202 foreach my $msgid (sort keys %$index)
203203 { next if $msgid eq '';
204 $fh->print("\n", $index->{$msgid}->toString(@opt));
204
205 my $po = $index->{$msgid};
206 next if $po->unused;
207
208 $fh->print("\n", $po->toString(@opt));
205209 }
206210
207211 $fh->close
404408 foreach my $po ($self->translations)
405409 { next if $po->msgid eq '';
406410 $stats{msgids}++;
407 $po->fuzzy and $stats{fuzzy}++;
408 $po->isActive or $stats{inactive}++;
411 $stats{fuzzy}++ if $po->fuzzy;
412 $stats{inactive}++ if !$po->isActive && !$po->unused;
409413 }
410414 \%stats;
411415 }
135135 my $count = $self->{_count} || 0;
136136
137137 $self->{_msgid} # no translation, constant string
138 or return $self->{_prepend};
138 or return (defined $self->{_prepend} ? $self->{_prepend} : '')
139 . (defined $self->{_append} ? $self->{_append} : '');
139140
140141 # create a translation
141142 my $text = Log::Report->translator($self->{_domain})->translate($self);
208209 sub concat($;$)
209210 { my ($self, $what, $reversed) = @_;
210211 if($reversed)
211 { $self->{_prepend}
212 = defined $self->{_prepend} ? $what . $self->{_prepend} : $what;
212 { $what .= $self->{_prepend} if defined $self->{_prepend};
213 return ref($self)->new(%$self, _prepend => $what);
213214 }
214 else
215 { $self->{_append}
216 = defined $self->{_append} ? $self->{_append} . $what : $what;
217 }
218 $self;
215
216 $what = $self->{_append} . $what if defined $self->{_append};
217 ref($self)->new(%$self, _append => $what);
219218 }
220219
221220 =chapter DETAILS
44 use base 'Log::Report::Translator';
55
66 use Locale::gettext;
7 use POSIX qw/setlocale/;
87
98 use Log::Report 'log-report';
109
55
66 use Log::Report 'log-report', syntax => 'SHORT';
77 use Log::Report::Lexicon::Index;
8 use Log::Report::Lexicon::POTcompact;
89
9 use POSIX qw/locale_h/;
10 use POSIX qw/:locale_h/;
1011
1112 my %indices;
1213
4142 { my ($self, $msg) = @_;
4243
4344 my $domain = $msg->{_domain};
44 my $locale = setlocale(LC_MESSAGES, '');
45 my $locale = setlocale(LC_MESSAGES)
46 or return $self->SUPER::translate($msg);
47
4548 my $pot = exists $self->{pots}{$locale} ? $self->{pots}{$locale}
4649 : $self->load($domain, $locale);
4750
2828 my @take = expand_reasons 'INFO-ERROR,PANIC';
2929
3030 =chapter DESCRIPTION
31 This module collects a few functions and definitions which are
32 shared between different components in the M<Log::Report>
33 infrastructure.
3134
3235 =chapter FUNCTIONS
3336
7679 { my $begin = $reason_code{$1 || 'TRACE'};
7780 my $end = $reason_code{$2 || 'PANIC'};
7881 $begin && $end
79 or error __x"unknown reason {which} in '{reasons}'"
80 , which => ($begin ? $2 : $1), reasons => $reasons;
82 or error __x "unknown reason {which} in '{reasons}'"
83 , which => ($begin ? $2 : $1), reasons => $reasons;
8184
8285 error __x"reason '{begin}' more serious than '{end}' in '{reasons}"
83 , begin => $1, end => $2, reasons => $reasons
84 if $begin >= $end;
86 , begin => $1, end => $2, reasons => $reasons
87 if $begin >= $end;
8588
8689 $r{$_}++ for $begin..$end;
8790 }
99102 }
100103
101104 =function escape_chars STRING
102 Replace all escape characters into their readible counterpart.
105 Replace all escape characters into their readible counterpart. For
106 instance, a new-line is replaced by backslash-n.
103107
104108 =function unescape_chars STRING
105 Replace all C<\.> by their escape character.
109 Replace all backslash-something escapes by their escape character.
110 For instance, backslash-t is replaced by a tab character.
106111 =cut
107112
108113 my %unescape
124129 $str;
125130 }
126131
132 1;
33 "Project-Id-Version: log-report 0.01\n"
44 "Report-Msgid-Bugs-To:\n"
55 "POT-Creation-Date: 2007-05-14 17:14+0200\n"
6 "PO-Revision-Date: 2007-05-28 00:48+0200\n"
6 "PO-Revision-Date: 2007-05-28 11:38+0200\n"
77 "Last-Translator: Mark Overmeer <mark@overmeer.net>\n"
88 "Language-Team:\n"
99 "MIME-Version: 1.0\n"
8585 msgid "WARNING"
8686 msgstr "WAARSCHUWING"
8787
88 #: lib/Log/Report/Dispatcher.pm:244 lib/Log/Report/Dispatcher.pm:255
88 #: lib/Log/Report/Dispatcher.pm:242 lib/Log/Report/Dispatcher.pm:253
8989 msgid "at {filename} line {line}"
9090 msgstr "in {filename} regel {line}"
9191
155155 msgid "no filename or file-handle specified for PO"
156156 msgstr "geen bestandsnaam of -handle meegegeven voor PO"
157157
158 #: lib/Log/Report/Lexicon/POT.pm:323
158 #: lib/Log/Report/Lexicon/POT.pm:327
159159 msgid "no header defined in POT for file {fn}"
160160 msgstr "geen kop opgegeven in POT in bestand {fn}"
161161
163163 msgid "no msgid in block {where}"
164164 msgstr "geen msgid in blok {where}"
165165
166 #: lib/Log/Report/Lexicon/PO.pm:445
166 #: lib/Log/Report/Lexicon/PO.pm:446
167167 msgid "no plurals for '{msgid}'"
168168 msgstr "geen meervoudsvormen voor '{msgid}'"
169169
195195 msgid "string '{text}' not between quotes at {location}"
196196 msgstr "tekst '{text}' niet tussen quotes in {location}"
197197
198 #: lib/Log/Report/Dispatcher.pm:166
198 #: lib/Log/Report/Dispatcher.pm:164
199199 msgid "switching to run mode {mode}"
200200 msgstr "overschakeling naar verwerkingsmode {mode}"
201201
227227 msgid "the 'needs' sub-command parameter '{reason}' is not a reason"
228228 msgstr "het 'needs' sub-commando argument '{reason}' is geen reden"
229229
230 #: lib/Log/Report/Lexicon/POT.pm:283
230 #: lib/Log/Report/Lexicon/POT.pm:287
231231 msgid "the only acceptable parameter is 'ACTIVE', not '{p}'"
232232 msgstr "het enige geaccepteerde argument is 'ACTIVE', niet '{p}'"
233233
234 #: lib/Log/Report/Lexicon/PO.pm:434
234 #: lib/Log/Report/Lexicon/PO.pm:435
235235 msgid "too many plurals for '{msgid}'"
236236 msgstr "te veel meervouden voor '{msgid}'"
237237
238 #: lib/Log/Report/Lexicon/POT.pm:266
238 #: lib/Log/Report/Lexicon/POT.pm:270
239239 msgid "translation already exists for '{msgid}'"
240240 msgstr "er bestaat al een vertaling voor '{msgid}'"
241241
243243 msgid "translator must be a Log::Report::Translator object"
244244 msgstr "vertaler moet een Log::Report::Translator object zijn"
245245
246 #: lib/Log/Report/Dispatcher/Try.pm:193
247 msgid "try-block stopped with {reason}"
248 msgstr "try-blok gestopt met {reason}"
249
246250 #: lib/Log/Report/Lexicon/PO.pm:326
247251 msgid "unknown comment type '{cmd}' at {where}"
248252 msgstr "onbekend commentaar type '{cmd}' in {where}"
255259 msgid "unknown reason {which} in '{reasons}'"
256260 msgstr "onbekende reden {which} is '{reasons}'"
257261
258 #: lib/Log/Report/Dispatcher.pm:164
262 #: lib/Log/Report/Dispatcher.pm:162
259263 msgid "unknown run mode '{mode}'"
260264 msgstr "onbekende verwerkingsmode '{mode}'"
261265
263267 msgid "unnamed file"
264268 msgstr ""
265269
266 #: lib/Log/Report/Lexicon/POT.pm:209
270 #: lib/Log/Report/Lexicon/POT.pm:213
267271 msgid "write errors for file {fn}"
268272 msgstr "schrijfproblemen bij bestand {fn}"
269273
33 "Project-Id-Version: log-report 0.01\n"
44 "Report-Msgid-Bugs-To:\n"
55 "POT-Creation-Date: 2007-05-14 17:14+0200\n"
6 "PO-Revision-Date: 2007-05-28 00:48+0200\n"
6 "PO-Revision-Date: 2007-05-28 11:38+0200\n"
77 "Last-Translator:\n"
88 "Language-Team:\n"
99 "MIME-Version: 1.0\n"
5353 msgid "Log::Log4perl back-end {name} requires a 'config' parameter"
5454 msgstr ""
5555
56 #, fuzzy
57 #~ msgid "Log::Log4perl back-end {name} requires a config argument"
58 #~ msgstr ""
59
6056 #: lib/Log/Report/Dispatcher/Log4perl.pm:111
6157 #, fuzzy
6258 msgid "Log::Log4perl level '{level}' must be in 0-5"
109105 msgid "WARNING"
110106 msgstr ""
111107
112 #: lib/Log/Report/Dispatcher.pm:244 lib/Log/Report/Dispatcher.pm:255
108 #: lib/Log/Report/Dispatcher.pm:242 lib/Log/Report/Dispatcher.pm:253
113109 #, fuzzy
114110 msgid "at {filename} line {line}"
115111 msgstr ""
196192 msgid "no filename or file-handle specified for PO"
197193 msgstr ""
198194
199 #: lib/Log/Report/Lexicon/POT.pm:323
195 #: lib/Log/Report/Lexicon/POT.pm:327
200196 #, fuzzy
201197 msgid "no header defined in POT for file {fn}"
202198 msgstr ""
206202 msgid "no msgid in block {where}"
207203 msgstr ""
208204
209 #: lib/Log/Report/Lexicon/PO.pm:445
205 #: lib/Log/Report/Lexicon/PO.pm:446
210206 #, fuzzy
211207 msgid "no plurals for '{msgid}'"
212208 msgstr ""
213209
214 #, fuzzy
215 #~ msgid "no reason found in report parameters"
216 #~ msgstr ""
217
218210 #: lib/Log/Report/Extract/PerlPPI.pm:155
219211 #, fuzzy
220212 msgid "no textdomain for translatable at {fn} line {line}"
221213 msgstr ""
222214
223 #, fuzzy
224 #~ msgid "not a CODE reference: {param}"
225 #~ msgstr ""
226
227215 #: lib/Log/Report/Extract/PerlPPI.pm:109
228216 #, fuzzy
229217 msgid "processing file {fn} in {charset}"
254242 msgid "string '{text}' not between quotes at {location}"
255243 msgstr ""
256244
257 #, fuzzy
258 #~ msgid "sub-command 'mode' expects name and setting"
259 #~ msgstr ""
260
261 #: lib/Log/Report/Dispatcher.pm:166
245 #: lib/Log/Report/Dispatcher.pm:164
262246 #, fuzzy
263247 msgid "switching to run mode {mode}"
264248 msgstr ""
265249
266 #, fuzzy
267 #~ msgid "syslog level '$level' not understood"
268 #~ msgstr ""
269
270250 #: lib/Log/Report/Dispatcher/Syslog.pm:105
271251 #, fuzzy
272252 msgid "syslog level '{level}' not understood"
297277 msgid "the 'list' sub-command doesn't expect additional parameters"
298278 msgstr ""
299279
300 #, fuzzy
301 #~ msgid "the 'needs' sub-command parameter '{reason} is not a reason"
302 #~ msgstr ""
303
304280 #: lib/Log/Report.pm:334
305281 #, fuzzy
306282 msgid "the 'needs' sub-command parameter '{reason}' is not a reason"
307283 msgstr ""
308284
309 #: lib/Log/Report/Lexicon/POT.pm:283
285 #: lib/Log/Report/Lexicon/POT.pm:287
310286 #, fuzzy
311287 msgid "the only acceptable parameter is 'ACTIVE', not '{p}'"
312288 msgstr ""
313289
314 #: lib/Log/Report/Lexicon/PO.pm:434
290 #: lib/Log/Report/Lexicon/PO.pm:435
315291 #, fuzzy
316292 msgid "too many plurals for '{msgid}'"
317293 msgstr ""
318294
319 #: lib/Log/Report/Lexicon/POT.pm:266
295 #: lib/Log/Report/Lexicon/POT.pm:270
320296 #, fuzzy
321297 msgid "translation already exists for '{msgid}'"
322298 msgstr ""
326302 msgid "translator must be a Log::Report::Translator object"
327303 msgstr ""
328304
305 #: lib/Log/Report/Dispatcher/Try.pm:193
306 #, fuzzy
307 msgid "try-block stopped with {reason}"
308 msgstr ""
309
329310 #: lib/Log/Report/Lexicon/PO.pm:326
330311 #, fuzzy
331312 msgid "unknown comment type '{cmd}' at {where}"
332313 msgstr ""
333314
334 #, fuzzy
335 #~ msgid "unknown dispatcher {type}"
336 #~ msgstr ""
337
338315 #: lib/Log/Report/Lexicon/PO.pm:294
339316 #, fuzzy
340317 msgid "unknown flag {flag} ignored"
345322 msgid "unknown reason {which} in '{reasons}'"
346323 msgstr ""
347324
348 #: lib/Log/Report/Dispatcher.pm:164
325 #: lib/Log/Report/Dispatcher.pm:162
349326 #, fuzzy
350327 msgid "unknown run mode '{mode}'"
351328 msgstr ""
355332 msgid "unnamed file"
356333 msgstr ""
357334
358 #: lib/Log/Report/Lexicon/POT.pm:209
335 #: lib/Log/Report/Lexicon/POT.pm:213
359336 #, fuzzy
360337 msgid "write errors for file {fn}"
361338 msgstr ""
66
77 # domain 'log-report' via work-arounds:
88 # Log::Report cannot do "use Log::Report"
9
10 use POSIX qw/setlocale LC_ALL/;
119
1210 my @make_msg = qw/__ __x __n __nx __xn N__ N__n N__w/;
1311 my @functions = qw/report dispatcher try/;
8886
8987 print __xn("found one file", "found {_count} files", @files), "\n";
9088
91 try { error };
92 if($@) {...}
89 try { error }; # catch errors with hidden eval/die
90 if($@) {...} # $@ isa Log::Report::Dispatcher::Try
91
92 use POSIX ':locale_h';
93 setlocale(LC_ALL, 'nl_NL');
94 info __"Hello World!"; # in Dutch, if translation table found
9395
9496 =chapter DESCRIPTION
9597 Handling messages to users can be a hassle, certainly when the same
120122 Multiple dispatchers in parallel can be active. M<Log::Report::Dispatcher>
121123 takes care that the back-end gets the messages of the severity it needs,
122124 translated and in the right character-set.
125
126 =item . Exception handling
127 A simple exception system is implemented via M<try()> and
128 M<Log::Report::Dispatcher::Try>.
123129
124130 =back
125131
961967 croak 7,emergency,emerg fatal failure
962968 confess 7,emergency,emerg fatal panic
963969
964 A typical perl5 program can look like this
965
966 my $dir = '/etc';
967
968 File::Spec->file_name is_absolute($dir)
969 or die "ERROR: directory name must be absolute.\n";
970
971 -d $dir
972 or die "ERROR: what platform are you on?";
973
974 until(opendir DIR, $dir)
975 { warn "ERROR: cannot read system directory $dir: $!";
976 sleep 60;
977 }
978
979 print "Processing directory $dir\n"
980 if $verbose;
981
982 while(defined(my $file = readdir DIR))
983 { if($file =~ m/\.bak$/)
984 { warn "WARNING: found backup file $dir/$f\n";
985 next;
986 }
987
988 die "ERROR: file $dir/$file is binary"
989 if $debug && -B "$dir/$file";
990
991 print "DEBUG: processing file $dir/$file\n"
992 if $debug;
993
994 open FILE, "<", "$dir/$file"
995 or die "ERROR: cannot read from $dir/$f: $!";
996
997 close FILE
998 or croak "ERROR: read errors in $dir/$file: $!";
999 }
1000
1001 Where C<die>, C<warn>, and C<print> are used for various tasks. With
1002 C<Log::Report>, you would write
1003
1004 use Log::Report syntax => 'SHORT';
1005 dispatcher stderr => 'FILE', mode => 'DEBUG', to => \*STDERR;
1006
1007 my $dir = '/etc';
1008
1009 File::Spec->file_name is_absolute($dir)
1010 or mistake "directory name must be absolute";
1011
1012 -d $dir
1013 or panic "what platform are you on?";
1014
1015 until(opendir DIR, $dir)
1016 { alert "cannot read system directory $dir";
1017 sleep 60;
1018 }
1019
1020 info "Processing directory $dir";
1021
1022 while(defined(my $file = readdir DIR))
1023 { if($file =~ m/\.bak$/)
1024 { notice "found backup file $dir/$f";
1025 next;
1026 }
1027
1028 assert "file $dir/$file is binary"
1029 if -B "$dir/$file";
1030
1031 trace "processing file $dir/$file";
1032
1033 unless(open FILE, "<", "$dir/$file")
1034 { error "no permission to read from $dir/$f"
1035 if $!==ENOPERM;
1036 fault "unable to read from $dir/$f";
1037 }
1038
1039 close FILE
1040 or failure "read errors in $dir/$file";
1041 }
1042
1043 A lot of things are quite visibly different, and there are a few smaller
1044 changes. There is no need for a new-line after the text of the message.
1045 When applicable (error about system problem), then the C<$!> is added
1046 automatically.
1047
1048 The distinction between C<error> and C<fault> is a bit artificial her, just
1049 to demonstrate the difference between the two. In this case, I want to
1050 express very explicitly that the user made an error by passing the name
1051 of a directory in which a file is not readible. In the common case,
1052 the user is not to blame and we can use C<fault>.
1053
1054970 =subsection Run modes
1055971 The run-mode change which messages are passed to a dispatcher, but
1056972 from a different angle than the dispatch filters; the mode changes
11361052
11371053 =section Comparison
11381054
1055 =subsection die/warn/Carp
1056
1057 A typical perl5 program can look like this
1058
1059 my $dir = '/etc';
1060
1061 File::Spec->file_name is_absolute($dir)
1062 or die "ERROR: directory name must be absolute.\n";
1063
1064 -d $dir
1065 or die "ERROR: what platform are you on?";
1066
1067 until(opendir DIR, $dir)
1068 { warn "ERROR: cannot read system directory $dir: $!";
1069 sleep 60;
1070 }
1071
1072 print "Processing directory $dir\n"
1073 if $verbose;
1074
1075 while(defined(my $file = readdir DIR))
1076 { if($file =~ m/\.bak$/)
1077 { warn "WARNING: found backup file $dir/$f\n";
1078 next;
1079 }
1080
1081 die "ERROR: file $dir/$file is binary"
1082 if $debug && -B "$dir/$file";
1083
1084 print "DEBUG: processing file $dir/$file\n"
1085 if $debug;
1086
1087 open FILE, "<", "$dir/$file"
1088 or die "ERROR: cannot read from $dir/$f: $!";
1089
1090 close FILE
1091 or croak "ERROR: read errors in $dir/$file: $!";
1092 }
1093
1094 Where C<die>, C<warn>, and C<print> are used for various tasks. With
1095 C<Log::Report>, you would write
1096
1097 use Log::Report syntax => 'SHORT';
1098 dispatcher stderr => 'FILE', mode => 'DEBUG', to => \*STDERR;
1099
1100 my $dir = '/etc';
1101
1102 File::Spec->file_name is_absolute($dir)
1103 or mistake "directory name must be absolute";
1104
1105 -d $dir
1106 or panic "what platform are you on?";
1107
1108 until(opendir DIR, $dir)
1109 { alert "cannot read system directory $dir";
1110 sleep 60;
1111 }
1112
1113 info "Processing directory $dir";
1114
1115 while(defined(my $file = readdir DIR))
1116 { if($file =~ m/\.bak$/)
1117 { notice "found backup file $dir/$f";
1118 next;
1119 }
1120
1121 assert "file $dir/$file is binary"
1122 if -B "$dir/$file";
1123
1124 trace "processing file $dir/$file";
1125
1126 unless(open FILE, "<", "$dir/$file")
1127 { error "no permission to read from $dir/$f"
1128 if $!==ENOPERM;
1129 fault "unable to read from $dir/$f";
1130 }
1131
1132 close FILE
1133 or failure "read errors in $dir/$file";
1134 }
1135
1136 A lot of things are quite visibly different, and there are a few smaller
1137 changes. There is no need for a new-line after the text of the message.
1138 When applicable (error about system problem), then the C<$!> is added
1139 automatically.
1140
1141 The distinction between C<error> and C<fault> is a bit artificial her, just
1142 to demonstrate the difference between the two. In this case, I want to
1143 express very explicitly that the user made an error by passing the name
1144 of a directory in which a file is not readible. In the common case,
1145 the user is not to blame and we can use C<fault>.
1146
1147 A module like M<Log::Message> is an object oriented version of the
1148 standard Perl functions, and as such not really contributing tp
1149 abstaction.
1150
11391151 =subsection Log::Dispatch and Log::Log4perl
11401152 The two major logging frameworks for Perl are M<Log::Dispatch> and
11411153 M<Log::Log4perl>; both provide a pluggable logging interface.
0 #!/usr/bin/perl
1 # test locale
2
3 use Test::More tests => 9;
4
5 BEGIN {
6 use_ok('POSIX', ':locale_h', 'setlocale');
7 }
8
9 my $default = setlocale(LC_MESSAGES, 'en_US');
10 ok(defined $default, 'has default locale');
11
12 $! = 2;
13 my $err_en = "$!";
14 ok(defined $err_en, $err_en); # platform dependent
15 my $try = setlocale LC_MESSAGES, 'nl_NL';
16 ok(defined $try, 'defined return');
17 is($try, 'nl_NL');
18
19 is(setlocale(LC_MESSAGES), 'nl_NL');
20 $! = 2;
21 my $err_nl = "$!";
22 ok(defined $err_nl, $err_nl);
23 isnt($err_en, $err_nl);
24
25 setlocale(LC_MESSAGES, 'en_US');
26 $! = 2;
27 my $err_en2 = "$!";
28 is($err_en, $err_en2, $err_en2);
1515 isa_ok($a, 'Log::Report::Message');
1616 my $b = $a . " World!\n";
1717 isa_ok($b, 'Log::Report::Message');
18 cmp_ok(refaddr $a, '==', refaddr $b);
18 cmp_ok(refaddr $a, '!=', refaddr $b); # must clone
1919 is("$b", "Hello World!\n");
2020
2121 my $c = 'a' . 'b' . __("c") . __("d") . "e" . __("f");
1919
2020 my $file1 = '';
2121 open my($fh1), ">", \$file1 or die $!;
22 my $d = dispatcher FILE => 'file1'
23 , to => $fh1;
22 my $d = dispatcher FILE => 'file1', to => $fh1;
2423
2524 @disp = dispatcher 'list';
2625 cmp_ok(scalar(@disp), '==', 1 + $disp_stderr);
4241 my $file2 = '';
4342 open my($fh2), ">", \$file2 or die $!;
4443 my $e = dispatcher FILE => 'file2'
44 , format_reason => 'UPPERCASE'
4545 , to => $fh2, accept => '-INFO';
4646 ok(defined $e, 'created second disp');
4747 isa_ok($e, 'Log::Report::Dispatcher::File');
9090 notice "note this!";
9191 my $s = length $file1;
9292 cmp_ok($s, '>', 0, 'disp1 take notice');
93 is($file1, "NOTICE: note this!\n");
93 is($file1, "notice: note this!\n"); # format_reason LOWERCASE
9494 my $t4 = length $file2;
9595 cmp_ok($t4, '==', $t3, 'disp2 ignores notice');
9696
9797 warning "oops, be warned!";
9898 my $s2 = length $file1;
9999 cmp_ok($s2, '>', $s, 'disp1 take warning');
100 like(substr($file1, $s), qr/^WARNING: oops, be warned!/);
100 like(substr($file1, $s), qr/^warning: oops, be warned!/);
101101 my $t5 = length $file2;
102102 cmp_ok($t5, '==', $t4, 'disp2 ignores warnings');
103103
88 use Test::More tests => 23;
99
1010 use Log::Report undef, syntax => 'SHORT';
11
12 use POSIX ':locale_h'; # avoid user's environment
1113
1214 # start a new logger
1315 my $text = '';
6466 my $text_l3 = length $text;
6567 cmp_ok($text_l3, '>', $text_l2, 'passed on loggings');
6668 is(substr($text, $text_l2), <<__EXTRA);
67 INFO: nothing wrong
68 TRACE: trace more
69 info: nothing wrong
70 trace: trace more
6971 __EXTRA
7072
7173 eval {
7476 };
7577 $@->reportAll;
7678 };
77 is($@, "FAILURE: oops! no network\n");
79 is($@, "try-block stopped with FAILURE");