Как получить вывод кода Perl в STDOUT / STDERR и файл в реальном времени и кросс-платформенный?

Мне нужно, чтобы вывод обычного кода Perl одновременно выводился на экран и в файл журнала. Однако проблема в том, что время работы инструмента может составлять часы. Использование тройника Capture :: Tiny означает, что файл журнала будет записан только после завершения скрипта, что не очень полезно.

Чтобы еще больше усложнить ситуацию, мне нужно захватить вывод прямого perl из того же процесса, а также процессов, вызываемых с помощью system ().

Наконец, из-за ограничений работодателя он должен работать и на Win32.

Какие еще у меня есть варианты?


person Mithaldu    schedule 16.03.2011    source источник


Ответы (5)


Используйте PerlIO :: Util.

Просто протестировал его под Strawberry Perl 5.12.1 32 бит, и он отлично работает, так что он будет кроссплатформенным. Приведенный ниже код работает именно так, как вы ожидаете. И поскольку он изменяет фактические дескрипторы файлов STDOUT и STDERR, любая запись в них будет автоматически выполняться.

use strict;
use warnings;

use IO::Handle;
use PerlIO::Util;
use 5.012;

for (*STDOUT, *STDERR) {
  $_->autoflush; $_->push_layer(tee => ">>stdout.txt");
}

for (1..10) {
  say $_;
  warn $_ unless $_ % 2;
}
person Oesor    schedule 16.03.2011
comment
Да, я тоже попробовал, и он мне очень понравился. Однако, если вы добавите что-то вроде system( 'dir' );, он этого не поймёт. - person Mithaldu; 16.03.2011

Поскольку ни одно из представленных решений не было удовлетворительным, я сел и решил проблему самостоятельно:

Capture :: Tiny :: Extended

person Mithaldu    schedule 20.03.2011

Если ваша программа работает на платформе Linux / Unix, вы можете использовать команду tee . Tee читает стандартный ввод и записывает в стандартный вывод и в указанный файл.

Пример:

myprogram.pl  2>&1 |tee mylog.txt

Единственное предостережение: stdout и stderr будут объединены в одном файле.

Поскольку вы используете платформу Windows, вы можете искать в Google por tee.exe, или вы можете попробовать эту минималистичную версию tee на perl:

$|=1;

if ( !$ARGV[0] ) {
        print "Usage:  some_command  \|  tee.pl [-a]  logfile\n";
        exit(1);
}

# Append mode
my $mode='>';
if ($ARGV[0] eq '-a')
{
        $mode='>>';
        shift;
}
my $LOGFILE=$ARGV[0];

while (<STDIN>) {
        print;
        open( OUT, "$mode $LOGFILE");
        print OUT $_;
        close OUT;

        # Your logic here!
}

Пример:

perl myprogram.pl  2>&1 |perl tee.pl mylog.txt

Я бы действительно попытался избежать изменения исходного кода только для того, чтобы все больше и больше захватывать STDOUT и / или STDERR, если вы собираетесь выполнять системные вызовы.

person Francisco R    schedule 16.03.2011
comment
Я не возражаю против объединения результатов, но из-за ограничений работодателя он должен работать и на Win32. - person Mithaldu; 16.03.2011
comment
Я изменил свой ответ. Надеюсь, поможет. - person Francisco R; 16.03.2011
comment
Да, это вариант, но это скорее крайний случай. Сценарий, который я пишу, должен запускать и захватывать другой сценарий и обертывать вокруг них логику файла блокировки, перехват ошибок, отправку по электронной почте и т. Д. И все из этого должно быть помещено в один файл журнала, что очень хорошо делает Capture :: Tiny. Только не в реальном времени. - person Mithaldu; 16.03.2011
comment
Просьба уточнить. Вам просто нужно записать вывод вашей программы? Тогда тройник - твой друг. Вам нужен процессор журналов в реальном времени? Тогда, возможно, вы можете использовать мой perl tee и изменить его для анализа строк. - person Francisco R; 16.03.2011
comment
Извините, если мне что-то непонятно. У меня есть инструмент, который должен всегда печатать на экране и который ТАКЖЕ должен иметь возможность начать регистрацию всего своего вывода в файл, если логика внутри этого диктует это. Этот вывод может поступать от самого инструмента, который выводит отладочную информацию о таких вещах, как обработка файлов блокировки, а также о том, что происходит из вызовов system (), которые он делает. - person Mithaldu; 16.03.2011

Вы можете использовать IO :: Tee.

  • Сделайте специальную рукоятку-тройник.
  • Отредактируйте вашу программу. Измените все распечатки на стандартный вывод на распечатки для этого дескриптора файла.
  • При необходимости переопределите дескриптор файла tee для печати только в стандартный вывод или для печати в 2 или более файлов.
  • Используйте `` вместо os system () для захвата вывода программ и их печати в специальном дескрипторе файла.

Если вы предпочитаете не использовать какой-либо модуль, создайте свою собственную функцию «myprint». Он может печатать в стандартный вывод и, если включен глобальный флаг, также печатать в файл журнала.

sub myPrint
{
   print @_;
   if ($LOGMODE)
   {
      open(LOGFILE, ">>$logfile");
      print LOGFILE @_;
      close LOGFILE;
   }
}
person Francisco R    schedule 16.03.2011
comment
Это не все решения, но они указали мне рабочий путь. Я добавлю переключатель для переключения типа ведения журнала и использую open(STDOUT, ">>logfile"); или Use Capture::Tiny в зависимости от ситуации; поскольку только они, похоже, могут захватывать system (). - person Mithaldu; 16.03.2011

person    schedule
comment
Вы можете дать описание этого кода? Простая публикация ~ 350 строк кода на самом деле не дает хорошего ответа. Я также заметил, что это точная копия другой ответ. Также убедитесь, что ваши ответы касаются конкретной проблемы, с которой сталкивается пользователь. Спасибо. - person Kev; 11.06.2011
comment
Ctrl + F, = head1 ОПИСАНИЕ - person Yordan Georgiev; 12.06.2011
comment
Вы пропустили ту часть, где я упомянул system (), а ТАКЖЕ ту, где я уже опубликовал правильное решение моей проблемы? - person Mithaldu; 21.06.2011
comment
$ objLogger- ›LogInfoMsg (Запуск $ cmd: \ n $ cmd); $ objLogger- ›LogInfoMsg ($cmd 2>&1); - person Yordan Georgiev; 23.06.2011
comment
Лучший способ получить новый навык - это не получить полный ответ, а найти его самостоятельно. Можно просто погуглить ответ и вставить его, но в следующий раз, когда у вас возникнет новая проблема, вам придется искать ее и снова гуглить ... - person Yordan Georgiev; 23.06.2011