2014-12-02 2 views
3

Ниже приведен пример кода, который я попытался повернуть файл журнала в многопоточном приложении с помощью log4perl. Но он отлично работает, если это не многопоточное приложение. Журналы не меняются, а файл журнала увеличивается. Может ли кто-нибудь направить меня туда, где я ошибаюсь?Как использовать Log4perl для поворота файлов журнала в многопоточном приложении perl

use strict; 
use warnings; 
use Log::Log4perl; 
use POSIX; 
use threads; 
use threads::shared; 

my @InputFiles; 

my $InputDirectory=$ARGV[0]; 
my $LogName=$ARGV[1]; 
opendir(DIR,$InputDirectory) or die "could not open the input directory"; 
@InputFiles=readdir(DIR); 
close(DIR); 
my $file; 

    #logger_configuration 
my $log_conf =" 
    log4perl.rootLogger    = DEBUG, LOG1 

    log4perl.appender.LOG1   = Log::Dispatch::FileRotate 
    log4perl.appender.LOG1.filename = $LogName 
    log4perl.appender.LOG1.mode  = append 
    log4perl.appender.LOG1.autoflush = 1 
    log4perl.appender.LOG1.size  = 10000 
    log4perl.appender.LOG1.max  = 20 
    log4perl.appender.LOG1.layout = Log::Log4perl::Layout::PatternLayout 
    log4perl.appender.LOG1.layout.ConversionPattern = \%d{yyyy-MM-dd HH:mm:ss}|\%P|\%m|\%n 
"; 

#loading the configuration file 
Log::Log4perl::init(\$log_conf); 

#creating logger instance 
my $logger = Log::Log4perl->get_logger(); 

my $thread_count=5; 
my $file_total= scalar @InputFiles; 
#print STDERR "$file_total\n"; 

#dividing total files among the no of given threads 
my $div = $file_total/$thread_count; 
$div = ceil($div); 
my $start = 0; 
my $end = $div; 
my @threads; 
for (my $count = 1; $count <=$thread_count ; $count++) 
{ 
    my $thread = threads->new(\&process,$start,$end); 
    push(@threads,$thread);   
    $start = $end; 
    $end = $end + $div; 
    if ($end > $file_total) 
    { 
     $end = $file_total; 
    } 
} 

foreach (@threads) 
{ 
    $_->join; 
} 

sub process 
{ 
    my $lstart = shift; 
    my $lend = shift; 
    my $id = threads->tid(); 
    for (my $index = $lstart; $index < $lend; ++$index) 
    { 
     $logger->info($InputFiles[$index]); 
    } 
} 

ответ

2

ОК, довольно принципиально ваша проблема в этом - ваш «регистратор» создается до начала ваших потоков. Это означает, что все ваши потоки будут иметь одинаковые дескрипторы файлов.

Это по своей сути вызовет у вас проблемы, если у вас нет своего рода арбитражного механизма для файла IO. Подумайте о ваших потоках как о отдельных программах, все пытаются открыть и записать в один файл - и вы можете увидеть, как это может быть беспорядочно.

Я хотел бы предложить вместо того, что вам нужно сделать, это создать другой нить для регистратора, и отправить IO через что-то вроде Thread::Queue

use Thread::Queue; 
my $log_q = Thread::Queue -> new(); 

sub logger_thread { 
    #init logger here 

    while (my $log_item = $log_q -> dequeue()) { 
     $logger -> info ($log_item); 
    } 
} 

my $log_thread = threads -> create (\&logger_thread); 

А потом заменить $logger -> info (....) с:

$log_q -> enqueue($message_to_log); 

Затем, как только вы присоединились ко всем своим «технологическим» потокам (например, как вы сейчас), закройте нить журнала:

$log_q -> end(); 
$log_thread -> join(); 

Это приведет к тому, что каждый из потоков будет помещать в очередь сообщения журнала, и как только они будут завершены (и объединены), вы закроете очередь, чтобы регистратор знал, что это «сделано» - и так выйдет, как только очередь будет пустой, могут быть объединены.

Многопоточный файл IO грязный, поэтому лучше избегать как можно большего.

+0

Hi Sobrique, он работает нормально, но когда я использую $ log_q -> end(), он дает мне ошибку «не могу найти конец объекта через пакет Thread-> Queue() – Doe

+0

Спасибо Sobrique.I не обновил тему :: Очередь в ppm.Now это работает отлично. Спасибо много .... – Doe

Смежные вопросы