Протоколирование стандартного вывода и stderr для нескольких команд в обратных ссылках

#perl

#perl

Вопрос:

Мне нужно протоколировать stdout и stderr для нескольких команд в обратных ссылках.

 my $logger = Log::Log4perl->get_logger("test_app");
...
my $log;
$log = `service someservice restart`;

$logger->info("someservice: $log");

$log = `~/scripts/test.pl param1`;
$logger->info("test.pl: $log");

$log = `~/scripts/script.pl param2`;
$logger->info("script.pl: $log");

$log = `~/scripts/env.pl param3`;
$logger->info("env.pl: $log");

$log = `~/scripts/monitor.pl param4`;
$logger->info("monitor.pl: $log");
  

В этом случае будет протоколироваться только стандартный вывод. Как я могу также протоколировать stderr?

Этот код выглядит уродливо. Есть ли способ написать это более изящно?

Комментарии:

1. Вы можете использовать 2>amp;1 для перенаправления stderr в стандартный вывод. Например: $log = `service someservice restart 2>amp;1`

2. Я предлагаю пойти в другом направлении. Вместо использования обратных ссылок я бы использовал IPC::Open3 , чтобы вы могли записывать stdout и stderr в отдельные переменные. Стандартный вывод регистрируется как info, а stderr — как предупреждение или ошибка.

3. Другим предложением было бы перенести выполнение и протоколирование в подраздел. Создайте хэш элементов, которые должны быть выполнены, и передайте определенный элемент хэша (ключ / значение) вспомогательному модулю, чтобы он выполнялся и регистрировал результаты.

4. Спасибо! Я новичок в Perl. Возможно ли показать небольшой пример?

5. Попробуйте perldoc IPC::Open3 получить подробные объяснения и примеры.

Ответ №1:

Следуя предложению Рона Бергина, вот пример использования IPC::Open3

/tmp/log4perl.conf

 log4perl.logger.test_app               = INFO, FileAppndr1
log4perl.appender.FileAppndr1          = Log::Log4perl::Appender::File
log4perl.appender.FileAppndr1.filename = /tmp/test_app.log
log4perl.appender.FileAppndr1.layout   = Log::Log4perl::Layout::SimpleLayout
  

test.pl

 #!/usr/bin/env perl

use warnings;
use strict;

use IPC::Open3;
use Log::Log4perl;
use Symbol 'gensym'; # Create anonymous glob (filehandle)

Log::Log4perl::init("/tmp/log4perl.conf");
my $logger = Log::Log4perl->get_logger("test_app");
$logger->info('-'x40); # New run

my @tasks = (
    [ 'ls', '-lt', '/tmp/test_app.log' ], # ok
    [ 'df', '-h'                       ], # ok
    [ 'grep', 'foo', '/var/log/foo'    ], # error
);

for my $task (@tasks) {
    run_command($task);
}

sub run_command {
    my ($command_with_args) = @_;
    my ($writer, $reader, $error);
    $error = gensym;
    my $pid = open3($writer, $reader, $error, @$command_with_args);

    waitpid( $pid, 0 );
    my $child_exit_status = $? >> 8;

    $logger->info("Running [ " . join(' ', @$command_with_args) . " ]");

    {
        local $/; # Read all of $reader/$error at one go, but do not affect rest of program
        if ($child_exit_status) {
            $logger->error("ERROR: Got status code [ $child_exit_status ]");
            $logger->error("Error Message:n" . <$error>);
        } else {
            $logger->info("SUCCESS");
            $logger->info("Output:n" . <$reader>);
        }
    }
}
  

Вывод — /tmp/test_app.log

 INFO - ----------------------------------------
INFO - Running [ ls -lt /tmp/test_app.log ]
INFO - SUCCESS
INFO - Output:
-rw-rw-r-- 1 felix felix 29129 Oct 24 00:06 /tmp/test_app.log

INFO - Running [ df -h ]
INFO - SUCCESS
INFO - Output:
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda2       30G   13G   18G  41% /
devtmpfs        3.6G     0  3.6G   0% /dev
/dev/xvdh       100G   25G   76G  25% /data/home

INFO - Running [ grep foo /var/log/foo ]
ERROR - ERROR: Got status code [ 2 ]
ERROR - Error Message:
grep: /var/log/foo: No such file or directory