简体   繁体   English

如何在读取事件时捕获File :: Tail异常

[英]How to catch File::Tail exception on read event

I'm trying to write a small process that keeps scanning a log path. 我正在尝试编写一个不断扫描日志路径的小进程。 All the rotated files are ".csv", while the current one which is still being written has ".csv.cur" as its extension. 所有旋转的文件均为“ .csv”,而当前仍在写入的文件的扩展名为“ .csv.cur”。 The process should keep looking in "almost" real time for ".csv.cur" files and perform operations on their content. 该过程应保持“几乎”实时地查找“ .csv.cur”文件并对其内容执行操作。 To make it short, it should work like a "tail -f | replace something". 简而言之,它应该像“ tail -f | replace something”一样工作。

So this is the main code: 因此,这是主要代码:

for (;;) {

    opendir(my $cdrs, $path) || die $!;
    my @current = grep { /^$host.+\.cur$/ && -f "$path/$_" } readdir($cdrs); 
    closedir($cdrs);

    if (! $current[0]) {
        &debug(DEBUG_MODE, "[PARENT] No CURRENT file found in: $path/. Retrying in $current_lookup_retry second(s)...\n");
        sleep $current_lookup_retry;
        next;
    }

    if ((! $last_file) || ($last_file ne $current[0])) {
        $last_file = $current[0];
        my $c_pid = &spawn_guardian("$path/$current[0]");
        &debug(DEBUG_MODE, "[PARENT] Guardian spawned (Child PID $c_pid)\n");
        &debug(DEBUG_MODE, "[PARENT] CURRENT set to: $current[0]\n");
    }

    select(undef, undef, undef, $ms);
}

And the sub spawn_guardian: 和子spawn_guardian:

sub spawn_guardian() {
    $SIG{CHLD} = "IGNORE"; # prevent defunct processes
    my $child_pid = fork();    

    if (!defined $child_pid) {
        die "[CHILD] Cannot fork: $!";
    } elsif ($child_pid == 0) {
        # no need to verify if the parent dies

        &debug(DEBUG_MODE, "[CHILD][$$] Spawning guardian for $_[0]...\n");
        my $file = File::Tail->new(name          => $_[0],
                                   #name_changes => \&lcount($line_count),
                                   interval      => 1, 
                                   maxinterval   => 5,
                                   adjustafter   => 1,
                                   #errmode      => 'die',
                                   resetafter    => 15,
                                   debug         => DEBUG_MODE);

        while (defined(my $line = $file->read)) {
            if ($line) { # Try to evaluate the content of $line 
                print "[CHILD][$$] $line";
            } else {  # Try to gracefully exit from this Child process  
                &grace($$, $_[0]);
            }
        }

        &debug(DEBUG_MODE, "[CHILD][$$] Exiting guardian for $_[0]...\n"); # this should never be executed anyway
        exit 0; # same as previous line
    }
    return $child_pid; # return PID to Parent process
} 

This is the output I get from this code: 这是我从以下代码获得的输出:

[DEBUG][PARENT] No CURRENT file found in: /root/OLOShaper/. Retrying in 2 second(s)...
[DEBUG][PARENT] No CURRENT file found in: /root/OLOShaper/. Retrying in 2 second(s)...
[DEBUG][CHILD][8346] Spawning guardian for /root/OLOShaper/mcitti21-KCZsOUrfmlFNRDXk.csv.cur...
[DEBUG][PARENT] Guardian spawned (Child PID 8346)
[DEBUG][PARENT] CURRENT set to: mcitti21-KCZsOUrfmlFNRDXk.csv.cur
[CHILD][8346] <omitted content of the .csv.cur>
[CHILD][8346] <omitted content of the .csv.cur>
[CHILD][8346] <omitted content of the .csv.cur>
[DEBUG][PARENT] No CURRENT file found in: /root/OLOShaper/. Retrying in 2 second(s)...
Error opening /root/OLOShaper/mcitti21-KCZsOUrfmlFNRDXk.csv.cur: No such file or directory at ./OLOShaper line 91
[DEBUG][PARENT] No CURRENT file found in: /root/OLOShaper/. Retrying in 2 second(s)...
[DEBUG]Ctrl-C detected!
Graceful shutdown in progress for PID 8344...
[DEBUG]Resetting PID file...
[DEBUG]Removing PID file...
Service ./OLOShaper has been halted.

So as you can see I get this error: 如您所见,我收到此错误:

Error opening /root/OLOShaper/mcitti21-KCZsOUrfmlFNRDXk.csv.cur: No such file or directory at ./OLOShaper line 91

What I do in oder to generate it, it's to delete the .csv.cur file while the process is scanning it. 为了生成该文件,我要做的是在扫描过程中删除.csv.cur文件。 Of course, I'm doing such idiotic thing in order to test the code, but I really can't come up with a solution to handle this error. 当然,为了测试代码,我正在做这种愚蠢的事情,但是我真的无法提出解决此错误的解决方案。

Let me know if you need more information. 如果您需要更多信息,请与我们联系。

As far as I can tell, the error is working as you'd probably desire. 据我所知,该错误正在按您的期望进行。 The child is no longer able to process its assigned file, so it naturally dies and is cleaned up while parent continues to look for new files. 孩子不再能够处理分配给它的文件,所以它自然dies和被清除了,而家长继续寻找新的文件。

If you'd like to more gracefully handle these types of error conditions, you could wrap your File::Tail code in an eval , and do some cleanup and more detailed logging when an error occurs. 如果您想更优雅地处理这些类型的错误情况,可以将File::Tail代码包装在eval ,并在发生错误时进行一些清理和更详细的日志记录。 You could use use a module like Try::Tiny for a slightly more semantic way of catching errors. 您可以使用类似Try::Tiny的模块来获取捕获错误的更多语义方法。

eval {
    my $file = File::Tail->new(...);

    while (defined(my $line = $file->read)) {
       ...
    }
};
if ($@) {
    warn "Error processing $filename: $@";
    # Any additional cleanup here
}

Either way, it looks like your code is going to work fine as it is, but certainly more full error handling can be nice. 无论哪种方式,看起来您的代码都可以正常工作,但是更全面的错误处理当然可以。

side note 边注

Your spawn_guardian is passed a single parameter file name. 您的spawn_guardian传递了一个参数文件名。 Go ahead and put that in a descriptive variable: my ($filename) = @_; 继续并将其放在一个描述性变量中: my ($filename) = @_; That way your code is more self-documenting instead of having random $_[0] 's floating around. 这样,您的代码将更具有自我说明性,而不会产生随机的$_[0]浮动。

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

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