a new module log::report yapc::europe 2007, vienna by mark overmeer

37
A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

Upload: ferdinand-hensley

Post on 15-Jan-2016

217 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

A new module

Log::Report

YAPC::Europe 2007, Viennaby Mark Overmeer

Page 2: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

How to handle errors?

Good programs produce many errors and warnings, have debug and verbose

MailBox: 188 messages in 1010 methods, but does not even test extensively.

How are they documented in POD?

Where in the code is an error message produced? In what language and charset?

Page 3: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

Requirements (for CPAN6)

produce (error) messages which

can be used both graphically and command-line

internationalization: adapted to user's preference; Chinese to web-page English in syslog

extensively documented: one-liner message abstract for tool-tip extended description for web-page

Page 4: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

strategy “die”

print/die/warn/carp/croak/confess/cluck

clear program flow, the “problem” is handled where it appears

very simple to use

clumsy to catch/handle: eval, $SIG{__DIE__}

limited to text messages

only two levels: either to die or not to die.

Page 5: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

strategy “exceptions”

simulated try/catch

on location of error, throw exception object (die)

need to define exception classes (category). Not easy (quite a lot of typing) to use.

in some “unknown” caller environment, the object is caught and handled (eval) Less transparent program flow.

Very OO

Page 6: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

translating messages

Translations with Locale::Textdomain

use Locale::TextDomain 'mydomain';

print __”Hello, World!”; # double quotes! “Hello, World!”

print __x “found user {name}”, name => $user; “found user john”

print __xn “found one file”, “found {nr} files”, scalar @files, nr => scalar @files; “found one file” / “found 5 files”

my @colors = (N__”red”, N__”green”, N__”blue”);print __$colors[1];

Page 7: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

dispatching errors

Log::Log4perl

use Log::Log4perl;Log::Log4perl::init(“$ENV{HOME}/log4perl.conf”);

#everywhere when neededmy $log = Log::Log4perl->get_logger('my.config');

$log->notice('starting daemon');

Page 8: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

translated & dispatched

In combination, it becomes like this:

$logger->debug( __”Hello World” );

Page 9: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

translated & dispatched

In combination, it becomes like this:

However: too expensive: debug probably gets ignored

$logger->debug( __”Hello World” );

Page 10: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

translated & dispatched

In combination, it becomes like this:

However: too expensive: debug probably gets ignored which language/character-set? Multiple dispatchers

with different needs.

$logger->debug( __”Hello World” );

Page 11: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

translated & dispatched

In combination, it becomes like this:

However: too expensive: debug probably gets ignored which language/character-set? Multiple dispatchers

with different needs. exceptions? Already formatted data, but handler may

like the original values: avoid error-message parsing.

$logger->debug( __”Hello World” );

Page 12: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

language support, extensions

Locale::Textdomain

use Locale::TextDomain 'mydomain';

print __”Hello World”; # double quotes!

print __x “found user {name}”, name => $user;

print __xn “found one file”, “found {nr} files”, scalar @files, nr => scalar @files;

my @colors = (N__”red”, N__”green”, N__”blue”);print __$colors[1];

Page 13: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

language support, extensions

Locale::Textdomain and Log::Report

use Locale::TextDomain 'mydomain';use Log::Report 'mydomain';

print __”Hello World”; # double quotes!

print __x “found user {name}”, name => $user;

print __xn “found one file”, “found {nr} files”, scalar @files, nr => scalar @files;print __xn “found one file”, “found {_count} files”, +@files;

my @colors = N__w ”red green blue”;my @colors = (N__”red”, N__”green”, N__”blue”);print __$colors[1];

Page 14: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

language support, delayed

compare Local::TextDomain / Log::Report

→ translation is delayed

use <either> 'mydomain';use POSIX ':locale_h';

my $x = __”Hello, World!”;

print $x; # Hello, World! Hello, World!

setlocale LC_MESSAGES, 'nl_NL';

print $x; # Hello, World! Hallo Wereld

Page 15: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

language support, lexicon

xgettext-perl, using PPI

→ msgid extraction included

Makefile.PL: xgettext: $(TO_INST_PM)

xgettext-perl -p lib/My/Module/messages/

make xgettext # pm files from MANIFESTcd lib/My/Module/messagescp mydomain.utf-8.po mydomain/nl_NL.povi nl_NL.po # translate

nl_NL.po: msgid “Hello, World!” msgstr “Hallo Wereld!”

Page 16: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

language support, formatting

Gettext

Local::TextDomain

Log::Report

→ simplified formats

printf dgettext(“mydomain”, “%5d bytes in %s”), $size, $fn;

printf __x “{size} bytes in {fn}”, size => sprintf(“%5d”, $size), fn => $fn;

printf __x “{size%5d} bytes in {fn}”, size => $size, fn => $fn;

Page 17: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

dispatching with Log::Log4perl

Log::Log4perl

use Log::Log4perl;Log::Log4perl::init(“$ENV{HOME}/.log4perl.conf”);

# everywhere when needed (!)my $log = Log::Log4perl->get_logger('mylogger');$log->error('oops!');

### content of ~markov/log4perl.conflog4perl.logger.mylogger = ERROR, somefilelog4perl.appender.somefile = Log::Log4perl::Appender::Filelog4perl.appender.somefile.filename = /var/log/my.loglog4perl.appender.somefile.layout = Log::Log4perl::Layout::SimpleLayout

Page 18: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

dispatching with Log::Dispatch

Log::Dispatch

use Log::Dispatch;

my $dispatcher = Log::Dispatch->new;

$dispatcher->add( Log::Dispatch::File->new( name => 'file1', filename => 'logfile' ) );

$dispatcher->log(level => 'info', message => 'Blah' );

$dispatcher->info(__“Blah”);

Page 19: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

dispatching with Log::Report

Log::Report (hidden controller singleton)

# Main programuse Log::Report;

dispatcher close => 'default';dispatcher SYSLOG => 'syslog', facility => LOCAL7;

# in all (other) filesuse Log::Report 'my.domain';

report ERROR =>report ERROR => __x__x“filename too long ({char} max {max})” chars => length($fn), max => MAX_PATH if length($fn) > MAX_PATH;

Page 20: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

dispatching with Log::Report

Log::Report short syntax

# Main programuse Log::Report;

dispatcher close => 'stderr';dispatcher SYSLOG => 'syslog', facility => LOCAL7;

# in all (other) filesuse Log::Report 'my.domain', syntax => 'SHORT'syntax => 'SHORT';

errorerror __x “filename too long ({char} max {max})”, chars => length($fn), max => MAX_PATH if length($fn) > MAX_PATH;

Page 21: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

(intermission)

Log::Report::View (soon)<report label=”filename too long ({chars} max {max}”> <level>error</level>

<gettext lang=”nl”> bestandsnaam te lang ({chars} max {max}) </gettext>

<abstract lang=”en”> The filename is longer than supported by the file-system. Abbreviations are not automatically generated to avoid name clashes. </abstract></report>

Page 22: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

dispatching

Log::Report

dispatcher PERL => 'default', mode => 'DEBUG';

dispatcher SYSLOG => 'syslog', accept => 'ERROR-', locale => 'nl_NL', charset => 'iso-8859-1';

Page 23: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

dispatching

Log::Report

dispatcher PERL => 'default', mode => 'DEBUG';

dispatcher SYSLOG => 'syslog', accept => 'ERROR-', locale => 'nl_NL', charset => 'iso-8859-1';

# borrow back-ends from Log::Log4perldispatcher Log::Log4perl => 'mylogger', config => “$ENV{HOME}/.log4perl.conf;

# borrow back-ends from Log::Dispatchdispatcher Log::Dispatch::File => 'mydisp', filename => 'logfile', locale => 'pt_BR';

Page 24: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

report()

any (single line) report to user

use Log::Report 'mydomain';report ERROR => __“Oops” if $problem;

report {to => 'syslog', errno => ENOENT} , FAILURE => 'network unreachable';

Page 25: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

report()

any (single line) report to user

use Log::Report 'mydomain';report ERROR => __“Oops” if $problem;

report {to => 'syslog', errno => ENOENT} , FAILURE => 'network unreachable';

use Log::Report 'mydomain', syntax => 'SHORT';

error __“Oops” if $problem;

Page 26: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

Perl5's waymy $dir = '/etc';File::Spec->file_name is_absolute($dir) or die "ERROR: directory name must be absolute.\n";

-d $dir or die "ERROR: what platform are you on?";

until(opendir DIR, $dir) { warn "ERROR: cannot read system dir $dir: $!"; sleep 60 }

$verbose && print "Processing directory $dir\n";

while(defined(my $file = readdir DIR)) { if($file =~ m/\.bak$/) { warn "WARNING: found backup file $dir/$f\n"; next }

die "ERROR: file $dir/$file is binary" if $debug && -B "$dir/$file";

$debug && print "DEBUG: processing file $dir/$file\n";

open FILE, "<", "$dir/$file" or die "ERROR: cannot read from $dir/$f: $!";

close FILE or croak "ERROR: read errors in $dir/$file: $!"; }

Page 27: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

Log::Report my $dir = '/etc'; File::Spec->file_name is_absolute($dir) or mistake "directory name must be absolute";

-d $dir or panic "what platform are you on?";

until(opendir DIR, $dir) { alert "cannot read system directory $dir"; sleep 60 }

info "Processing directory $dir";

while(defined(my $file = readdir DIR)) { if($file =~ m/\.bak$/) { notice "found backup file $dir/$f"; next }

assert "file $dir/$file is binary" if -B "$dir/$file";

trace "processing file $dir/$file";

open FILE, "<", "$dir/$file" or fault "unable to read from $dir/$f";

close FILE or failure "read errors in $dir/$file"; }

Page 28: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

message “reasons”

Perl5 Log::Dispatch Syslog Log4Perl Log::Report print 0,debug debug debug trace print 0,debug debug debug assert print 1,info info info info warn\n 2,notice notice info notice warn 3,warning warn warn mistake carp 3,warning warn warn warning die\n 4,error err error error die 5,critical crit fatal fault croak 6,alert alert fatal alert croak 7,emergency emerg fatal failure confess 7,emergency emerg fatal panic

Focus purely on reason, not handling Takes a little effort to learn (sorry)

Page 29: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

report()

concatenation works! (still delayed)

info __”Hello” . “, “ . __”World” . “!”;

Page 30: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

report()

concatenation works! (still delayed)

$! added automatically

info __”Hello” . “, “ . __”World” . “!”;

open IN, '<', $filename or fault __x“cannot read from {fn}”, fn => $filename;

“fault: cannot read from /etc/hosts: No such...\n”;

Page 31: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

report()

concatenation works! (still delayed)

$! added automatically

info __”Hello” . “, “ . __”World” . “!”;

open IN, '<', $filename or fault __x“cannot read from {fn}”, fn => $filename;

“fault: cannot read from /etc/hosts: No such...\n”; “REASON: MSG: $!\n” # translatable!

REASON in domain “log-report”MSG in domain from user$! in domain libc

Page 32: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

display mode

mode = 'NORMAL', 'VERBOSE', 'DEBUG'(per dispatcher)

-v / -vv / -vvv; --verbose 2; --mode=”DEBUG”

use Log::Report syntax => 'SHORT';use Getopt::Long qw(:config no_ignore_case bundling);

my $mode; # defaults to NORMALGetOptions 'v+' => \$mode , 'verbose=i' => \$mode , 'mode=s' => \$mode or exit 1;

dispatcher PERL => 'default', mode => $mode;

Page 33: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

display mode

mode adapted formatting

S=show, C=confess, L=location, T=translate

mode mode mode mode REASON SOURCE TE! NORM -v -vv -vvv trace program ... S assert program ... SL SL info program T.. S S S notice program T.. S S S S mistake user T.. S S S SL warning program T.. SL SL SL SL error user/prog TE. S S SL SC fault system TE! S S SL SC alert system T.! S S SC SC failure system TE! S S SC SC panic program .E. SC SC SC SC

Page 34: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

exceptions

# exceptions are not too specialtry { error __”help!” };if($@) { ... }

# implemented as dispatchertry \&doit, mode => 'DEBUG';

Page 35: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

exceptions

# exceptions are not too specialtry { error __”help!” };if($@) { ... }

# implemented as dispatchertry \&doit, mode => 'DEBUG';

# very much like eval()my $x = try { sqrt $y };my @x = try { @lines };

# translates die/croak/confessmy $x = try { confess “help!” };

Page 36: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

exceptions

# exceptions are not too specialtry { error __”help!” };if($@) { ... }print ref $@; # Log::Report::Dispatcher::Try

print $@; # “Died in $fn line 42”if($@->failed) ...if($@->success) ...

$@->reportAll; # also non-fatal$@->reportFatal(to => 'syslog');

if(my $exception = $@->wasFatal){ print $exception->reason; $exception->throw; # not report() print $exception->message->untranslated;}

Page 37: A new module Log::Report YAPC::Europe 2007, Vienna by Mark Overmeer

Status

Translations lazy translation objects, with syntax of

Locale::TextDomain with a few extensions. extract gettext labels using PPI building and merging gettext-PO files

Dispatch direct stringification to own File, Syslog, Perl, Try back-ends to any Log::Dispatch back-end to any Log::Log4perl back-end