Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Re^2: Graceful handling of Log::Log4perl errors

by chaos_cat (Scribe)
on May 28, 2008 at 21:57 UTC ( [id://688936]=note: print w/replies, xml ) Need Help??


in reply to Re: Graceful handling of Log::Log4perl errors
in thread Graceful handling of Log::Log4perl errors

Thanks for the suggestion. I built the following code based on your idea, which seems to do the trick. It makes repeated attempts to load the config file and correct for missing path errors. If it encounters an error it doesn't recognize, or if it can't get a path created, it gives up and loads a blank config file (which it creates then and there to be sure it's blank). So far, it's passed all my tests but if anyone sees something broken here please drop me a note.
my %paths = (); my $init_fail = 0; INIT: while (1) { eval {Log::Log4perl->init_once($LOGGER_CONF_FILE)}; if ($@) { # Config file error of some kind # Send some alert message here # if we get a missing directory error, try some (sane) recover +y if ($@ =~ m{Can't\sopen\s/my/base/path/(.+)\s\(No such file or + directory\)}) { my $path = $1; if ( $paths{$path}++ ) { # only try once to create a give +n path. This prevents infinite loops here $init_fail = 1; last INIT; } my $dir = "/my/base/path"; # if the base path isn't th +ere, creating it is above this module's pay grade my @dir_list = split '/', $path; my $file = pop @dir_list; foreach my $sub_dir (@dir_list) { $dir .= "/$sub_dir"; if (! -d$dir) { eval {mkdir ($dir)}; # not too concerned with catc +hing errors here, the next round will bail on duplicate path attempt } } } # for other config file errors, throw our hands up in disgust +and move on else { $init_fail = 1; last INIT; } } else { $init_fail = 0; last INIT; } } # if we couldn't get the config file to initlize, load a blank one and + move on without logging if ($init_fail) { warn "Couldn't initilize logger, defaulting to blank config file"; my $default_config_file = "/my/base/path/etc/default.logger.conf"; open (my $fh, ">", $default_config_file); close ($fh); Log::Log4perl::init_once($default_config_file); }

Replies are listed 'Best First'.
Re^3: Graceful handling of Log::Log4perl errors
by kyle (Abbot) on May 29, 2008 at 02:29 UTC

    That looks pretty good! I'm gratified that you took my suggestion and ran with it. Thanks for sharing it with us! Looking at what you have, I think it could be made a bit more compact.

    use File::Path qw( mkpath ); my $base_path = '/my/base/path'; my $init_done = 0; my %paths = (); INIT: while ( ! $init_done ) { $init_done = eval { Log::Log4perl->init_once($LOGGER_CONF_FILE); 1 }; # If there's an error, and it's THIS one, if ( $@ =~ m{\A Can't \s open \s \Q$base_path\E (?: / ( \S+ ) )? / [^/]+ \s \( No \s such \s file \s or \s directory \)}xms ) { # This is the path that's missing my $target_path = "$base_path/$1"; # If we've already tried to create it once, don't try again if ( $paths{ $target_path }++ ) { last INIT; } # Try to create the path eval { mkpath( $target_path ) }; if ( ! -d $target_path ) { warn "Can't create missing directory '$target_path': $@\n" +; } } } # if we couldn't get the config file to initlize, load a blank one and + move on without logging if ( ! $init_done ) { warn "Couldn't initilize logger, defaulting to blank config file"; Log::Log4perl->init( \'' ); }

    Note the differences, though (good and bad).

    • I use File::Path::mkpath instead of just mkdir. This will try to create every necessary directory right up to the root. Yours won't try to create anything above /my/base/path. If attempting to create directories above /my/base/path will be a problem, you should go back to your own code.
    • Instead of tracking $init_fail, I track $init_done. This way the while condition is more natural (and doesn't look infinite), and I get to set it in only one place inside the loop.
    • I use Log::Log4perl->init with an empty string instead of an empty file I just created. It's shorter, and I don't run the risk of failing to create the empty file.
    • I re-complicated the regular expression (in particular adding the /x form back).
    • I haven't tested this. There could even be a syntax error.

    Thanks again for posting your work.

      I incorporated a few of your changes. In particular, I like the $init_done mechanic; it's much cleaner than what I was doing.

      my %paths = (); my $init_done = 0; my $base_path = "/my/base/path/"; INIT: while ( !$init_done ) { $init_done = eval { Log::Log4perl->init($LOGGER_CONF_FILE); 1; }; if ($@) { warn "Logger error was: $@"; # if we get a missing directory error, try some (sane) recover +y if ( $@ =~ m{Can't\sopen\s$base_path(.+)/[^/]+\s\(No such file + or directory\)} ) { my $path = $1; $path = $base_path . $path; warn "log directory $path does not exist, attempting to cr +eate it"; if ( $paths{$path}++ ) { warn "alredy tried to create this path"; last INIT; } eval { mkpath($path) }; warn "unable to create path $path" if ( !-d $path ); } # for other config file errors, throw our hands up in disgust +and move on else { last INIT; } } } # if we couldn't get the config file to initlize, load a blank one and + move on without logging if ( ! $init_done ) { warn "Couldn't initilize logger, defaulting to blank config file"; Log::Log4perl::init(\''); # this will throw a warning, but that's +not really a bad thing }

      One thing I learned while doing this: Log4perl sets its initialized flag at the beginning of its initialization, not at the end (on line 113 of Log::Log4perl::Config, in _init, on my install at least), so using init_once here is problematic, as it will not reload after the directory is created. I switched over to using init and relying on the $init_done to guard against unintentional reinitialization. Once I did that, it was necessary to put back in the two level error message check (the else last bit), otherwise it infinite loops because it is dieing on an unrecognized message.

      Thanks for all your help!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://688936]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (3)
As of 2024-04-24 02:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found