Tim Bunce wrote:
On Fri, Dec 15, 2006 at 03:26:46PM -0800, Dean Arnold wrote:
One item: I'm currently using a separate 19fhtrace.t test script;
should I merge it into 09trace.t ? Or leave it separate ?
(I'll vote for separate, since its easier to test the feature
standalone that way)
I agree.
OK. And your 2 examples worked (w/ a little tweaking), so I've added
them to the test script. Revised POD for "Tracing To Layered Filehandles"
below. I'll checkin once you're OK w/ the POD.
- Dean
=head2 Tracing to Layered Filehandles
B<NOTE>:
=over 4
=item *
Tied filehandles are not currently supported, as
tie operations are not available to the PerlIO
methods used by the DBI.
=item *
PerlIO layer support requires Perl version 5.8 or higher.
=back
As of version 5.8, Perl provides the ability to layer various
"disciplines" on an open filehandle via the L<PerlIO> module.
A simple example of using PerlIO layers is to use a scalar as the output:
my $scalar = '';
open( my $fh, "+>:scalar", \$scalar );
$dbh->trace( 2, $fh );
Now all trace output is simply appended to $scalar.
A more complex application of tracing to a layered filehandle is the
use of a custom layer (I<Refer to >L<Perlio::via> I<for details
on creating custom PerlIO layers.>). Consider an application with the
following logger module:
package MyFancyLogger;
sub new
{
my $self = {};
my $fh;
open $fh, '>', 'fancylog.log';
$self->{_fh} = $fh;
$self->{_buf} = '';
return bless $self, shift;
}
sub log
{
my $self = shift;
return unless exists $self->{_fh};
my $fh = $self->{_fh};
$self->{_buf} .= shift;
#
# DBI feeds us pieces at a time, so accumulate a complete line
# before outputing
#
print $fh "At ", scalar localtime(), ':', $self->{_buf}, "\n" and
$self->{_buf} = ''
if $self->{_buf}=~tr/\n//;
}
sub close {
my $self = shift;
return unless exists $self->{_fh};
my $fh = $self->{_fh};
print $fh "At ", scalar localtime(), ':', $self->{_buf}, "\n" and
$self->{_buf} = ''
if $self->{_buf};
close $fh;
delete $self->{_fh};
}
1;
To redirect DBI traces to this logger requires creating
a package for the layer:
package PerlIO::via::MyFancyLogLayer;
sub PUSHED
{
my ($class,$mode,$fh) = @_;
my $logger;
return bless \$logger,$class;
}
sub OPEN {
my ($self, $path, $mode, $fh) = @_;
#
# $path is actually our logger object
#
$$self = $path;
return 1;
}
sub WRITE
{
my ($self, $buf, $fh) = @_;
$$self->log($buf);
return length($buf);
}
sub CLOSE {
my $self = shift;
$$self->close();
return 0;
}
1;
The application can then cause DBI traces to be routed to the
logger using
use PerlIO::via::MyFancyLogLayer;
open my $fh, '>:via(MyFancyLogLayer)', MyFancyLogger->new();
$dbh->trace('SQL', $fh);
Now all trace output will be processed by MyFancyLogger's
log() method.