LINUX.ORG.RU

perl, дублирование STDERR в переменную


0

0

Как бы так ухитриться сделать, чтобы при выводе чего-нибудь в стандартный поток ошибок оно бы туда выводилось, и ещё дописывалось в скалярную переменную?

Есть вот такой вариант:

my $s = '';
close(STDERR);
open(STDERR, ">", \$s);

но в стандартный поток ошибок ничего не выводится.
Можно сделать что-то вроде

open(my $old_stream, ">&STDERR");
close(STDERR);
...
и выводить в $old_stream как в STDERR, но надо самому выводить, автоматически выводится не будет.

А вот как сделать, чтобы одновременно выводилось и туда и туда?

Объясню, зачем мне это надо - если в web-скрипте будут какие-нибудь предупреждения, чтобы они и в логи апача писались, и чтобы я их мог вывести где-нибудь на HTML-страничке. В принципе можно последний вариант использовать, но хочется покрасивей сделать.

★★★★★


На ум приходит tied handle, смотри perldoc perltie (секцию Tying FileHandles) и perldoc Tie::Handle. Вроде нет причин, чтобы оно не
работало ;-)
Ну и на CPAN посмотри, там много чего tied было.

HTH

Onanim
()

Большое спасибо, судя по всему это как раз то, что мне надо.

Legioner ★★★★★
() автор топика

> А вот как сделать, чтобы одновременно выводилось и туда и туда?

Могу подсказать решение, оно прямо-таки гениально. Создай процедуру, назови её как-нибудь, log_msg() например, и код её будет состоять из двух строк - одна пишет в STDERR, другая туда, куда тебе там ещё нужно. Гениально, потому что просто.

ddo
()
Ответ на: комментарий от ddo

Это конечно так, но стандартные ошибки типа using uninitialized variable про это знать не будут =) Я уже сделал, если интересно, могу показать.

Legioner ★★★★★
() автор топика

HandleDuplicator.pm:
# class to duplicate file handle
# Usage: tie *HNDL, 'HandleDuplicator', *ANOTHER_HANLE, \$var
# Each time when the writing to the HNDL requsted,
# data will be written to the ANOTHER_HANDLE and
# added to the $var
package HandleDuplicator;
use warnings;
use strict;
use base 'Tie::Handle';

# Parameters:
#  1. File handle
#  2. Scalar ref
sub TIEHANDLE
{
    my $class = shift;
    my $self;
    $self->{handle} = shift;
    $self->{variable} = shift;
    bless $self, $class;
}

sub WRITE
{
    my $self = shift;
    my $data = shift;

    ${$self->{variable}} .= $data;
    my $hndl = $self->{handle};
    print $hndl $data;
}

1;

StdErrLog.pm:
# all messages passed through the stderr will be logged.
# just use StdErrLog; and call StdErrLog::log to get the data.
# StdErrLog::clear clears the internal buffer.
package StdErrLog;
use warnings;
use strict;
use HandleDuplicator;

my $log = '';

sub log()
{
    return $log;
}

sub clear()
{
    $log = '';
}

sub BEGIN
{
    open(my $stderr, ">&2") || die "Can't duplicate stderr: $!";
    tie *STDERR, 'HandleDuplicator', $stderr, \$log;
}

1;

Английский ужасен, я знаю :)

Legioner ★★★★★
() автор топика
Ответ на: комментарий от Legioner

2Legioner:

Гы ;-) Я думал, больше кода потребуется. Выглядит вроде симпатично :-)

Onanim
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.