I'm not sure if this will work, but you might override DBI's notion of
a trace function.  If you look in DBI.pm you'll see this line:

  *trace_msg = \&DBD::_::common::trace_msg;

It appears that DBI uses the trace_msg function in the bowels of DBD
to actually do the printing.  Now, you can very likely override this
with something else..  Perhaps something like this:

use DBI;
.....
my $output;
my $oldhandle;
sub capture {
  $output .= join('', @_);
}

*DBI::trace_msg = \&capture;

$dbh = .....
# etc...


In an ideal world you could just subclass DBI and redefine the trace
message, alas DBI uses this construct quite often:

  DBI->trace_msg(...)



On Tue, Mar 05, 2002 at 01:14:11PM -0700, Mark Hazen wrote:
> I am hoping there is a someone brilliant on this list that can help me.  A
> little while ago, I posted to clp.perl asking how I can capture the trace
> output from DBI into a variable.  Since DBI is an external process, I
> couldn't do it just by piping STDERR.  Benjamin Goldberg came up with a
> module called IO::Capture (see below).  It works amazingly well in standard
> Perl.  Here is a sample script:
> 
> use IO::Capture;
> $capturer = IO::Capture->new(\*STDERR);
> 
> use DBI;
> $dbh = DBI->connect ("DBI:mysql:test:localhost", "username", "password", {
> RaiseError => 0, PrintError => 0 });
> 
> DBI->trace( 1 );
> 
> $sth = $dbh->prepare (qq{
>  CREATE TABLE IF NOT EXISTS test_table
>  (
>     a CHAR(15) NOT NULL,
>     b INT UNSIGNED NOT NULL
>  )
>  });
> $sth->execute ();
> $sth->finish ();
> 
> $dbh->disconnect ();
> 
> $text = $capturer->capture;
> 
> print qq{
> Output is:
> $text
> };
> 
> 
> 
> The problem is that once I try this script through mod_perl, it hangs the
> child process infinitely.  And then on subsequent requests, it has to create
> a new process.  This eventually results in the whole machine spiraling down
> because hundreds of Apache children are hung.  What I am hoping is that
> someone will spot something that neither Ben nor I have been able to spot.
> The module appears after my name.
> 
> Thanks for any help you can provide.
> Mark
> 
> 
> package IO::Capture;
> use strict;
> use warnings;
> use Symbol qw(gensym);
> 
> sub new {
>    (my ($class, $filehandle) = @_) == 2
>        or croak("Usage: IO::Capture->new(\$filehandle)");
>    if( ref $filehandle or ref \$filehandle eq "GLOB" ) {
>       $filehandle = \*$filehandle; # this is a sort of typecast.
>    } else {
>       $filehandle = caller() . "::" . $filehandle
>           unless $filehandle =~ /::/ or
>               $filehandle =~ /^STD(?:IN|OUT|ERR)\z/;
>       no strict 'refs';
>       $filehandle = \*$filehandle;
>    }
>    defined(fileno $filehandle)
>        or croak("Argument to IO::Capture->new has no fileno()");
>    my $save = gensym;
>    open $save, ">&".fileno($filehandle)
>       or die sprintf("Couldn't dup2(%s,%s): $!\n",
>          fileno($save),fileno($filehandle));
>    my  ($getresponse, $sendresponse) = (gensym, gensym);
>    pipe($getresponse, $sendresponse) or die "pipe: $!";
>    my  ($readnew, $writenew) = (gensym, gensym);
>    pipe($readnew, $writenew) or die "pipe: $!";
>    open( $filehandle, ">&" . fileno($writenew) )
>       or die sprintf("Couldn't dup2(%s,%s): $!\n",
>          fileno($filehandle),fileno($writenew));
>    close($writenew);
>    defined( my $pid = fork ) or do {
>       my $err = $!;
>       unless( open $filehandle, ">&".fileno $save ) {
>          my $err2 = $!;
>          open STDERR, $^O =~ /win/i ? ">con" : ">/dev/tty"
>              if $filehandle == \*STDERR;
>          die "fork: $err, dup2: $err2";
>       }
>       die "fork: $err";
>    };
>    # readnew, writenew, and sendresponse are automatically closed
>    # when we return here in the parent because they go out of scope,
>    # resulting in their their refcounts going to 0.
>    return bless [$filehandle, $save, $getresponse, $pid], $class
>       if $pid;
>    close($getresponse); # not used, so close it.
>    close($writenew); # MUST close this, or deadlock will occur!
>    # MUST close or re-open $filehandle, or deadlock will occur!
>    $filehandle == \*STDERR and (
>       open STDERR, ">&".fileno $save or
>       open STDERR, $^O =~ /win/i ? ">con" : ">/dev/tty"
>    ) or close $filehandle;
>    close $save; # not used from here on, so close it.
>    my ($got, $n) = "";
>    1 while $n = sysread $readnew, $got, 4096, length $got;
>    die "sysread: $!" unless defined $n;
>    print $sendresponse $got or die "print: $!";
>    exit;
> }
> 
> sub capture {
>    my $self = shift;
>    my ($fh, $saved, $get, $pid) = splice @$self, 0;
>    unless( open $fh, ">&" . fileno $saved ) {
>       open $fh, $^O =~ /win/i ? ">con" : ">/dev/tty"
>          if $fh == \*STDERR;
>       die "Couldn't restore filehandle: $!";
>    } else { close $saved }
>    my ($got, $n) = "";
>    while($n = sysread $get, $got, 4096, length $got) {}
>    defined($n) or die "sysread: $!";
>    if( waitpid $pid, 0 ) {
>       warn sprintf "Child exited with code 0x%04X", $? if $?;
>    } else { warn "waitpid: $!" } return $got;
> }
> 
> # like using autouse.pm but even more lightweight.
> sub croak {
>    undef &croak;
>    require Carp;
>    *croak = \&Carp::croak;
>    goto &croak;
> }
> 
> 1;
> __END__
> perl -MIO::Capture
>    $x = IO::Capture->new(\*STDERR);
>    print "now capturing\n";
>    warn qq[captured ok\n];
>    print "captured text 'captured ok' shouldn't have appeard\n";
>    $y = $x->capture;
>    print "capture didn't block\n";
>    print $y;
>    warn "Restored ok\n";
> __END__
> now capturing
> captured text 'captured ok' shouldn't have appeard
> capture didn't block
> captured ok
> Restored ok
> 
> perl -MIO::Capture
>    $x = IO::Capture->new(\*STDERR);
>    print "now capturing\n";
>    system(q[perl -e "print STDERR qq[captured ok\n]"]);
>    print "captured text 'captured ok' shouldn't have appeard\n";
>    $y = $x->capture;
>    print "capture didn't block\n";
>    print $y;
>    warn "Restored ok\n";
> __END__
> now capturing
> captured text 'captured ok' shouldn't have appeard
> capture didn't block
> captured ok
> Restored ok

-- 
Paul Lindner    [EMAIL PROTECTED]   ||||| | | | |  |  |  |   |   |

    mod_perl Developer's Cookbook   http://www.modperlcookbook.org/
         Human Rights Declaration   http://www.unhchr.ch/udhr/index.htm

Reply via email to