简体   繁体   English

使用copytruncate时如何在perl中尾文件

[英]How to tail file in perl when copytruncate is used

Problem 问题

I have created a simple perl script to read log files and process the data asynchronously. 我创建了一个简单的perl脚本来读取日志文件并异步处理数据。
The reading sub also checks for changes in inode number so a new filehandle is created when the logs rotate. reading子节点还检查inode编号的变化,以便在日志旋转时创建新的文件句柄。

The problem i am facing is that when copytruncate is used in logrotation then then inode does not change when the file is rotated. 我面临的问题是,在logrotation中使用copytruncate时,旋转文件时inode不会改变。
This shouldn't be an issue as the script should just continue reading the file but for some reason that i cannot immediately see, as soon as the logs rotate no new lines are ever read. 这不应该是一个问题,因为脚本应该继续读取文件,但是由于某些我无法立即看到的原因,一旦日志轮转,就不会再读取新行了。


Question

How can i modify the below script (or completely scrap and start again) to continously tail a file which is logrotated using copytruncate using perl ? 我如何修改以下脚本(或完全废弃并重新启动),以连续copytruncate使用perl使用copytruncate进行logrotated的文件?


Code

use strict;
use warnings;

use threads;
use Thread::Queue;
use threads::shared;

my $logq = Thread::Queue->new();
my %Servers :shared;
my %servername :shared;

#########
#This sub just reads the data off the queue and processes it, i have
#reduced it to a simple print statement for simplicity.
#The sleep is to prevent it from eating cpu.
########

sub process_data
{
        while(sleep(5)){
                if ($logq->pending())
                {
                        while($logq->pending() > 0){
                                my $data = $logq->dequeue();
                                print "Data:$data\n";
                        }
                }
        }
}

sub read_file
{
        my $myFile=$_[0];
        #Get the argument and assign to var.

        open(my $logfile,'<',$myFile) || die "error";
        #open file

        my $Inode=(stat($logfile))[1];
        #Get the current inode

        seek $logfile, 0, 2;
        #Go to the end of the file

        for (;;) {
                while (<$logfile>) {
                        chomp( $_ );
                        $logq->enqueue( $_ );
                        #Add lines to queue for processing

                }
                sleep 5;
                if($Inode != (stat($myFile))[1]){
                        close($logfile);
                        while (! -e $myFile){
                                sleep 2;
                        }
                        open($logfile,'<',$myFile) || die "error";
                        $Inode=(stat($logfile))[1];
                }
                #Above checks if the inode has changed and the file exists still

                seek $logfile, 0, 1;
                #Remove eof

        }

}


my $thr1 = threads->create(\&read_file,"test");
my $thr4 = threads->create(\&process_data);
$thr1->join();
$thr4->join();
#Creating the threads, can add more log files for processing or multiple processing sections.

Possibly relevant info 可能相关的信息

Log config for logrotate contains logrotate的日志配置包含

compress
compresscmd /usr/bin/bzip2
uncompresscmd /usr/bin/bunzip2
daily
rotate 5
notifempty
missingok
copytruncate

for this file. 该文件。

Specs 眼镜

GNU bash, version 3.2.57(1)-release (s390x-ibm-linux-gnu)
perl, v5.10.0
(if logrotate has version and someone knows how to check then i will also add that)

Any more info needed just ask. 需要更多信息只是问。

So the reason that this was failing is pretty obvious when you look at copytruncate , it copies the original file and then truncates the current one. 因此,当您查看copytruncate ,失败的原因非常明显,它会复制原始文件,然后截断当前文件。
Whilst this ensure that the inode is kept, it created another problem. 尽管这确保保留了索引节点,但它又产生了另一个问题。

As the current way i tail the file is by simply staying at the end and removing the eof flag this means that when the file is truncated, the pointer stays at the position of the last line before truncation, which in turn means that no more lines would be read until it reached that pointer again. 按照我当前尾部处理文件的方式,只需停留在末尾并删除eof标志,这意味着当文件被截断时,指针停留在截断前的最后一行的位置,这又意味着不再有行将被读取,直到再次到达该指针。

The obvious solution then is to simply check the size of the file and reset the pointer if it is ever pointing past the end of the file. 显而易见的解决方案是简单地检查文件的大小,并在指针指向文件末尾时重置指针。

I found it easier to just check that file size never got smaller though, using the two lines below. 我发现使用下面的两行代码来检查文件大小是否变得更容易。

my $fileSize=(stat($logfile))[7];
#Added after the inode is assigned

and changing 和改变

if($Inode != (stat($myFile))[1]){

to

if($Inode != (stat($myFile))[1] || (stat($myFile))[7] < $fileSize){

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM