The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

use strict;

package Plack::Middleware::Debug::Log4perl;

use parent qw(Plack::Middleware::Debug::Base);

our $VERSION = '0.04';

use Log::Log4perl qw(get_logger :levels);
use Log::Log4perl::Layout;
use Log::Log4perl::Level;

use Data::Dumper;

# let's try keeping a handle on the layout
my $timer;

sub run
{
	my($self, $env, $panel) = @_;

	if (Log::Log4perl->initialized()) {

		if (my $appender = Log::Log4perl->appender_by_name('psgi_debug_panel')) {

			$appender->clear();

			$timer->reset() if $timer;
		}
		else {

			my $logger = Log::Log4perl->get_logger("");

			# Define a layout
			my $layout = Log::Log4perl::Layout::PatternLayout->new("%r >> %p >> %m >> %c >> at %F line %L%n");

			# Define an 'in memory' appender
			my $appender = Log::Log4perl::Appender->new(
				"Log::Log4perl::Appender::TestBuffer",
				name => "psgi_debug_panel");

			$appender->layout($layout);

			$logger->add_appender($appender);
			$logger->level($TRACE);

			# hang on to the timer, so we can reset it
			$timer = $layout->{timer};
		}
	}

	return sub {
		my $res = shift;

		if (my $appender = Log::Log4perl->appenders()->{psgi_debug_panel}) {

			my $log = $appender->{appender}->{buffer};

			$log =~ s/ >> /\n/g;
			my $list = [ split '\n', $log ];

			$panel->content( sub { $self->render_list_pairs($list) } );
		}
		else {

			$panel->content( 'Log4perl appender not enabled' );
		}
	};
}

my $list_template = __PACKAGE__->build_template(<<'EOTMPL');
<table>
    <thead>
        <tr>
            <th>Time</th>
            <th>Level</th>
            <th>Message</th>
            <th>Source</th>
            <th>Line</th>
        </tr>
    </thead>
    <tbody>
% my $i;
% while (@{$_[0]->{list}}) {
% my($time, $level, $message, $source, $line) = splice(@{$_[0]->{list}}, 0, 5);
            <tr class="<%= ++$i % 2 ? 'plDebugOdd' : 'plDebugEven' %>">
                <td><%= $time %></td>
                <td><%= $level %></td>
                <td><%= $message %></td>
                <td><%= $source %></td>
                <td><%= $line %></td>
            </tr>
% }
    </tbody>
</table>
EOTMPL

sub render_list_pairs {

    my ($self, $list, $sections) = @_;
    if ($sections) {
        $self->render($list_template, { list => $list });
    }else{
        $self->render($list_template, { list => $list });
    }
}

1;
__END__

=head1 NAME

Plack::Middleware::Debug::Log4perl

Plack debug panel to show detailed Log4perl debug messages.

=head1 SYNOPSIS

    use Plack::Builder;
    use Plack::Middleware::Debug::Log4perl;

    builder {
      enable 'Debug', panels => [qw/Memory Timer Log4perl/];
      enable 'Log4perl', category => 'plack', conf => \$log4perl_conf;
      $app;
    };

=head1 DESCRIPTION

This module provides a plack debug panel that displays the Log4perl messages for the current HTTP request.

Ideally configure Log4perl using Plack::Midleware::Log4perl, or directly in your .psgi file.  This way we can hook into the root logger at run time and create the required stealth logger automatically.  If you're able to do this, you can skip the next bit.

For applications that configure / init their own logger, you must create a Log4perl appender using TestBuffer, named 'log4perl_debug_panel'.

In your Log4perl.conf:

    log4perl.rootLogger = TRACE, DebugPanel

    log4perl.appender.DebugPanel              = Log::Log4perl::Appender::TestBuffer
    log4perl.appender.DebugPanel.name         = psgi_debug_panel
    log4perl.appender.DebugPanel.mode         = append
    log4perl.appender.DebugPanel.layout       = PatternLayout
    log4perl.appender.DebugPanel.layout.ConversionPattern = %r >> %p >> %m >> %c >> at %F line %L%n
    log4perl.appender.DebugPanel.Threshold = TRACE

=head1 SEE ALSO

Log4perl: L<Log::Log4perl>

Plack Debug Panel: L<Plack::Middleware::Debug>

Source Repository: L<http://github.com/miketonks/Plack-Middleware-Debug-Log4perl>

=head1 AUTHORS

Mike Tonks

Thanks to Lyle Hopkins (Bristol & Bath Perl Mongers) for help with the threading tests.

=head1 LICENSE

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut