当日志中出现某些文本时跟踪日志并执行命令的最佳方法

当日志中出现某些文本时跟踪日志并执行命令的最佳方法

我有一个服务器日志,当服务器启动时,它会将特定的文本行输出到其日志文件中。我想在服务器启动后执行命令,因此执行如下操作:

tail -f /path/to/serverLog | grep "server is up" ...(now, e.g., wget on server)?

做这个的最好方式是什么?

答案1

一个简单的方法是 awk。

tail -f /path/to/serverLog | awk '
                    /Printer is on fire!/ { system("shutdown -h now") }
                    /new USB high speed/  { system("echo \"New USB\" | mail admin") }'

是的,这两条都是来自内核日志的真实消息。使用 Perl 可能会更优雅一些,并且还可以取代 tail 的需要。如果使用 perl,它将看起来像这样:

open(my $fd, "<", "/path/to/serverLog") or die "Can't open log";
while(1) {
    if(eof $fd) {
        sleep 1;
        $fd->clearerr;
        next;
    }
    my $line = <$fd>;
    chomp($line);
    if($line =~ /Printer is on fire!/) {
        system("shutdown -h now");
    } elsif($line =~ /new USB high speed/) {
        system("echo \"New USB\" | mail admin");
    }
}

答案2

如果您只想寻找一种可能性并且希望主要留在 shell 中而不是使用awkor perl,您可以执行以下操作:

tail -F /path/to/serverLog | 
grep --line-buffered 'server is up' | 
while read ; do my_command ; done

my_command...每次都会运行“服务器已启动" 出现在日志文件中。对于多种可能性,您可以删除grepcasewhile.

大写-F告诉tail我们要注意要轮换的日志文件;IE如果当前文件被重命名并且另一个同名文件取代了它,tail将切换到新文件。

--line-buffered选项指示grep在每行之后刷新其缓冲区;否则,my_command可能无法及时到达(假设日志具有合理大小的行)。

答案3

奇怪的是,没有人提到具有multitail开箱即用功能的实用程序。使用示例之一:

显示 ping 命令的输出,如果显示超时,则向当前登录的所有用户发送一条消息

multitail -ex timeout "echo timeout | wall" -l "ping 192.168.0.1"

也可以看看另一个例子使用情况multitail

答案4

可以自己做这项工作

让我们看看它是多么简单和可读:

mylog() {
    echo >>/path/to/myscriptLog "$@"
}

while read line;do
    case "$line" in
        *"Printer on fire"* )
            mylog Halting immediately
            shutdown -h now
            ;;
        *DHCPREQUEST* )
            [[ "$line" =~ DHCPREQUEST\ for\ ([^\ ]*)\  ]]
            mylog Incomming or refresh for ${BASH_REMATCH[1]}
            $HOME/SomethingWithNewClient ${BASH_REMATCH[1]}
            ;;
        * )
            mylog "untrapped entry: $line"
            ;;
    esac
  done < <(tail -f /path/to/logfile)

虽然您不使用 bash regex,但这可能会非常快!

+是一个非常高效且有趣的串联

但对于高负载服务器,正如我所喜欢的,sed因为它非常快且可扩展,我经常使用这个:

while read event target lost ; do
    case $event in
        NEW )
            ip2int $target intTarget
            ((count[intTarget]++))
        ...

    esac
done < <(tail -f /path/logfile | sed -une '
  s/^.*New incom.*from ip \([0-9.]\+\) .*$/NEW \1/p;
  s/^.*Auth.*ip \([0-9.]\+\) failed./FAIL \1/p;
  ...
')

相关内容