From: Robert J. <yad...@sn...> - 2006-09-22 17:24:46
|
I've configured my program to log to a MySQL database using Log::Log4perl::Appender::DBI. However, if the database is not available, my program hangs on trying to write log messages. Is there a workaround for this? Thanks, Rob |
From: John O. <joh...@o-...> - 2006-09-22 18:19:52
|
I'd recommend writing another appender which wraps around Appender::DBI and checks for availability. Alternatively, write to a text log file for speed, then have a daily script which pushes the log entries into the DB. hope that helps, John Robert Jacobson wrote: >I've configured my program to log to a MySQL database using >Log::Log4perl::Appender::DBI. However, if the database is not >available, my program hangs on trying to write log messages. Is >there a workaround for this? > >Thanks, >Rob > > >------------------------------------------------------------------------- >Take Surveys. Earn Cash. Influence the Future of IT >Join SourceForge.net's Techsay panel and you'll get the chance to share your >opinions on IT & business topics through brief surveys -- and earn cash >http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV >_______________________________________________ >log4perl-devel mailing list >log...@li... >https://lists.sourceforge.net/lists/listinfo/log4perl-devel > > > |
From: Robert J. <yad...@sn...> - 2006-09-26 17:54:43
|
At 02:18 PM 9/22/2006, you wrote: >I'd recommend writing another appender which wraps around >Appender::DBI and checks for availability. Ok, having looked at some other options, this sounds like the way to go. But I have a noob question: How do I write that wrapper? I can handle writing the database availability code (I think! :) ) But I don't even know where to start for writing a wrapper to Appender::DBI. If it helps, I've written my own, albeit simple, Appender, that just implemented the new() and log() methods. -- Rob |
From: Robert J. <yad...@sn...> - 2006-09-26 20:14:42
|
At 02:18 PM 9/22/2006, John ORourke wrote: >I'd recommend writing another appender which wraps around >Appender::DBI and checks for availability. Ok, I've managed to write a basic wrapper (without checking for availability). It seems to work (i.e. messages are logged to the database), but in the Layout I'm using %F{2}, and I get "Log4perl/Logger.pm" instead of the path of my script. Do I need to mess with caller_depth or something? --------------------------------------------- package Mylog; use warnings; use strict; require Log::Log4perl::Appender::DBI; sub new { my ($class, %options) = @_; my $appender = Log::Log4perl::Appender::DBI->new( map { $_ => $options{$_} } keys %options, ); my $self = { appender => $appender, name => $options{name}, }; bless $self, $class; return $self; } sub log { my ($self, %p) = @_; $self->{appender}->log( %p, ); return 1; } 1; --------------------------------------------- -- Rob |
From: Mike S. <m...@pe...> - 2006-09-27 05:46:58
|
On Tue, 26 Sep 2006, Robert Jacobson wrote: > At 02:18 PM 9/22/2006, John ORourke wrote: > >I'd recommend writing another appender which wraps around > >Appender::DBI and checks for availability. > > Ok, I've managed to write a basic wrapper (without checking for > availability). It seems to work (i.e. messages are logged to the > database), but in the Layout I'm using %F{2}, and I get > "Log4perl/Logger.pm" instead of the path of my script. Do I need to > mess with caller_depth or something? If you're using wrapper classes, you need to adjust the caller level: http://log4perl.sourceforge.net/d/Log/Log4perl.html#6acb7 -- Mike Mike Schilli m...@pe... > > --------------------------------------------- > > package Mylog; > > use warnings; > use strict; > > require Log::Log4perl::Appender::DBI; > > sub new { > my ($class, %options) = @_; > > my $appender = Log::Log4perl::Appender::DBI->new( > map { $_ => $options{$_} } keys %options, > ); > > my $self = { > appender => $appender, > name => $options{name}, > }; > > bless $self, $class; > > return $self; > > } > > sub log { > my ($self, %p) = @_; > > $self->{appender}->log( > %p, > ); > > return 1; > } > > 1; > --------------------------------------------- > > -- > Rob > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share your > opinions on IT & business topics through brief surveys -- and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > log4perl-devel mailing list > log...@li... > https://lists.sourceforge.net/lists/listinfo/log4perl-devel > |
From: Mike S. <m...@pe...> - 2006-09-27 05:49:56
|
On Tue, 26 Sep 2006, Robert Jacobson wrote: > At 02:18 PM 9/22/2006, you wrote: > >I'd recommend writing another appender which wraps around > >Appender::DBI and checks for availability. > > Ok, having looked at some other options, this sounds like the way to > go. But I have a noob question: How do I write that wrapper? Similar to writing your own appender, just call the methods of the 'wrapped' appender from within your wrapper appender: http://log4perl.sourceforge.net/d/Log/Log4perl/FAQ.html#e8a46 -- Mike Mike Schilli m...@pe... > > I can handle writing the database availability code (I think! :) > ) But I don't even know where to start for writing a wrapper to Appender::DBI. > > If it helps, I've written my own, albeit simple, Appender, that just > implemented the new() and log() methods. > > -- > Rob > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share your > opinions on IT & business topics through brief surveys -- and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > log4perl-devel mailing list > log...@li... > https://lists.sourceforge.net/lists/listinfo/log4perl-devel > |
From: Mike S. <m...@pe...> - 2006-09-28 02:20:38
|
On Wed, 27 Sep 2006, Robert Jacobson wrote: > However, the dumped log messages have the time of the dump, not the > original log message time. Is there a way to get Log4perl to use the > original time of the message? Take a look at Log::Log4perl::Appender::Buffer, it does something similar: # Trick the renderer into using the original event time local $self->{app}->{layout}->{time_function}; $self->{app}->{layout}->{time_function} = sub { $_->{log4p_logtime} }; It saves the event time when the log message comes in, saves it under the 'log4p_logtime' key and feeds it to the renderer later on. -- Mike Mike Schilli m...@pe... dd It doesn't seem to be in the hash that > the log() method gets; but maybe I'm just not looking in the right spot? > > I guess I could workaround the issue by prepending the original time > to the "message" field, but I'd like to avoid modifying the original > as much as possible. Can I do something like: 1) store the original > time internally in my buffer and 2) when dumping the buffer to the > appender, set some internal Log4perl time variable to the buffered time? > > ----------------------------------------------------------- > package Mylog; > > use warnings; > use strict; > > use Carp; > use DBI; > > require Log::Log4perl::Appender::DBI; > > sub new { > my ($class, %options) = @_; > > my $appender = Log::Log4perl::Appender::DBI->new( > map { $_ => $options{$_} } keys %options, > ); > > my $self = { > appender => $appender, > name => $options{name}, > }; > > > bless $self, $class; > $self->_init(%options); > > return $self; > > } > > sub log { > my ($self, %p) = @_; > > # Check for DB connection > if (! $self->{dbh}->ping() ) { > # Buffer the message > push @{$self->{BUFFER}}, \%p; > > # Notify FOT > $self->_notify(%p); > # Try to reconnect > eval { > $self->{dbh} = $self->{connect}->(); > }; > return 1; > } else { > $self->{connected_time} = scalar gmtime(); > } > > $self->check_buffer(); > > $Log::Log4perl::caller_depth++; > > $self->{appender}->log( > %p, > ); > > $Log::Log4perl::caller_depth--; > return 1; > } > > sub _init { > my $self = shift; > my %params = @_; > > if ($params{dbh}) { > $self->{dbh} = $params{dbh}; > } else { > $self->{connect} = sub { > DBI->connect(@params{qw(datasource username password)}, > {PrintError => 0}) > or croak "Log4perl: $DBI::errstr"; > }; > $self->{dbh} = $self->{connect}->(); > $self->{_mine} = 1; > } > } > > sub _notify { > my $self = shift; > my %params = @_; > > # eventually send an email or something > # for now just print a message > print "Database is down\n"; > > } > > sub check_buffer { > my $self = shift; > > return unless ($self->{BUFFER} && ref $self->{BUFFER} eq 'ARRAY'); > > while ( @{$self->{BUFFER}} ) { > my $ref = shift @{$self->{BUFFER}}; > $Log::Log4perl::caller_depth += 2; > $self->{appender}->log( > %$ref, > ); > $Log::Log4perl::caller_depth -= 2; > } > > return 1; > } > > 1; > > ----------------------------------------------------------- > > -- > Rob > > |
From: Robert J. <yad...@sn...> - 2006-09-28 13:20:06
|
At 10:20 PM 9/27/2006, you wrote: >Take a look at Log::Log4perl::Appender::Buffer, it does something similar: Thanks much! I'm using the DBI appender, with the NoopLayout and the data in param.1, so I had to use: $self->{appender}->{'bind_value_layouts'}{'1'}{'time_function'}; But it works great :) Another question, mostly just curiousity -- I used Data::Dumper to look at the appender structure. How/where does the time_function get defined as sub {"DUMMY"}? I don't see that anywhere in the Log4perl code... Is it a perl internal thing? Below is an excerpt from the dump for the DBI appender. $VAR1 = bless( { 'bind_value_layouts' => { '6' => bless( { 'stack' => [ [ 'm', undef ] ], 'printformat' => '%s', 'dontCollapseArrayRefs' => undef, 'format' => undef, 'info_needed' => { 'm' => 1 }, 'time_function' => sub { "DUMMY" }, 'CSPECS' => 'cCdFHIlLmMnpPrtTxX%', 'message_chompable' => 0 }, 'Log::Log4perl::Layout::PatternLayout' ), -- Rob |
From: Robert J. <yad...@sn...> - 2006-09-27 14:04:20
|
I've implemented a buffering mechanism in my wrapper's log() call. Basically I check using {dbh}->ping() if the database is up. If not, I buffer the message in an array and return success so that the parent program can proceed. When the database comes back up I dump the buffer to the DBI appender. However, the dumped log messages have the time of the dump, not the original log message time. Is there a way to get Log4perl to use the original time of the message? It doesn't seem to be in the hash that the log() method gets; but maybe I'm just not looking in the right spot? I guess I could workaround the issue by prepending the original time to the "message" field, but I'd like to avoid modifying the original as much as possible. Can I do something like: 1) store the original time internally in my buffer and 2) when dumping the buffer to the appender, set some internal Log4perl time variable to the buffered time? ----------------------------------------------------------- package Mylog; use warnings; use strict; use Carp; use DBI; require Log::Log4perl::Appender::DBI; sub new { my ($class, %options) = @_; my $appender = Log::Log4perl::Appender::DBI->new( map { $_ => $options{$_} } keys %options, ); my $self = { appender => $appender, name => $options{name}, }; bless $self, $class; $self->_init(%options); return $self; } sub log { my ($self, %p) = @_; # Check for DB connection if (! $self->{dbh}->ping() ) { # Buffer the message push @{$self->{BUFFER}}, \%p; # Notify FOT $self->_notify(%p); # Try to reconnect eval { $self->{dbh} = $self->{connect}->(); }; return 1; } else { $self->{connected_time} = scalar gmtime(); } $self->check_buffer(); $Log::Log4perl::caller_depth++; $self->{appender}->log( %p, ); $Log::Log4perl::caller_depth--; return 1; } sub _init { my $self = shift; my %params = @_; if ($params{dbh}) { $self->{dbh} = $params{dbh}; } else { $self->{connect} = sub { DBI->connect(@params{qw(datasource username password)}, {PrintError => 0}) or croak "Log4perl: $DBI::errstr"; }; $self->{dbh} = $self->{connect}->(); $self->{_mine} = 1; } } sub _notify { my $self = shift; my %params = @_; # eventually send an email or something # for now just print a message print "Database is down\n"; } sub check_buffer { my $self = shift; return unless ($self->{BUFFER} && ref $self->{BUFFER} eq 'ARRAY'); while ( @{$self->{BUFFER}} ) { my $ref = shift @{$self->{BUFFER}}; $Log::Log4perl::caller_depth += 2; $self->{appender}->log( %$ref, ); $Log::Log4perl::caller_depth -= 2; } return 1; } 1; ----------------------------------------------------------- -- Rob |
From: John O. <jo...@ve...> - 2006-09-27 17:25:33
|
Robert Jacobson wrote: >I've implemented a buffering mechanism in my wrapper's log() >call. Basically I check using {dbh}->ping() if the database is >up. If not, I buffer the message in an array and return success so >that the parent program can proceed. > >When the database comes back up I dump the buffer to the DBI appender. > > I can't help with the timestamp issue but I'd recommend having a maximum buffer size too, after which you stop saving up the messages - it could be used on a system where the DB might be down for days in the event of a disaster. Maybe if you're feeling very clever, revert to a file appender if the DB is down! cheers John |