multithreading - 如何使用 Log4perl 在多线程 Perl 应用程序中轮换日志文件

标签 multithreading perl log4perl

下面是我尝试使用 log4perl 在多线程应用程序中旋转日志文件的示例代码。但除非它是多线程应用程序,否则它工作正常。日志不会旋转并且日志文件的大小会增加。谁能指导我哪里出错了?

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]);
    }
}

最佳答案

好吧,从根本上来说,你的问题是这样的 - 你的“记录器”是在线程启动之前创建的。这意味着所有线程都将具有相同的文件句柄。

这本质上会给您带来问题,除非您有某种文件 IO 仲裁机制。将您的线程视为单独的程序,所有线程都尝试打开并写入同一个文件 - 您可以看到它可能会变得多么困惑。

我建议您需要做的是为记录器创建另一个线程,并通过诸如Thread::Queue之类的东西发送IO

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很乱,所以最好尽量避免。

关于multithreading - 如何使用 Log4perl 在多线程 Perl 应用程序中轮换日志文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27252437/

相关文章:

Android:启动画面和网页 View

c++ - 测试等待队列中 condition_variables 的多个线程

python - R 中的预测时间分析(数据挖掘算法)

perl - 带有共享符号的安全隔间会导致 Perl 调试器发出嘶嘶声

perl - 如何在 Log::Log4perl 中设置两个具有不同日志级别的附加程序?

perl - 如何在 Log4perl 中登录到两个不同的文件?

c# - Thread.Join() 需要帮助

java - 组合多个接收源

perl - 如何使用 Mechanize 在 html 文档中搜索文本?