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.

Reply via email to