it-swarm.cn

当日志中出现一些文本时,遵循日志并执行命令的最佳方法

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

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

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

56
jonderry

一个简单的方法将是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可能会更优雅一些,也可以代替尾巴。如果使用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");
    }
}
36
penguin359

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

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

...,每当日志文件中出现“ 服务器启动”时,它将运行my_command。对于多种可能性,您可以删除grep,而在case中使用while

大写的-F告诉tail监视日志文件是否要轮换; 如果当前文件被重命名并且另一个具有相同名称的文件被替换,tail将切换到新文件。

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

20
Jander

这个问题似乎已经得到回答,但是我认为有更好的解决方案。

而不是 tail | whatever,我认为您真正想要的是swatch。 Swatch是一个明确设计的程序,用于执行您的要求,查看日志文件并根据日志行执行操作。使用tail|foo将要求您有一个正在运行的终端来执行此操作。另一方面,Swatch作为守护程序运行,它将始终在监视您的日志。 Swatch在所有Linux发行版中都可用,

我鼓励您尝试一下。尽管您可以用螺丝刀的背面敲打指甲,但这并不意味着您应该这样做。

我可以找到的关于样本的最佳30秒教程是 这里

14
bahamat

奇怪的是没有人提到multitail实用程序具有此功能的现成功能。使用示例之一:

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

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

另请参见multitail用法的 另一个示例

11
php-coder

bash 可以自己完成这项工作

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

mylog() {
    echo >>/path/to/myscriptLog "[email protected]"
}

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,但可以保持很快的速度!

但是 bash + sed 是非常有效且有趣的串联

但是对于高负载服务器,并且我喜欢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;
  ...
')
8
F. Hauri

这也是我也开始这样做的方式,但是变得越来越复杂。需要注意的几件事:

  1. 如果日志尾部已经包含“服务器已启动”。
  2. 找到尾巴过程后自动结束。

我使用一些类似的方法:

RELEASE=/tmp/${RANDOM}$$
(
  trap 'false' 1
  trap "rm -f ${RELEASE}" 0
  while ! [ -s ${RELEASE} ]; do sleep 3; done
  # You can put code here if you want to do something
  # once the grep succeeds.
) & wait_pid=$!
tail --pid=${wait_pid} -F /path/to/serverLog \
| sed "1,10d" \
| grep "server is up" > ${RELEASE}

通过将tail保持打开直到${RELEASE}文件包含数据。

grep成功之后:

  1. 将输出写入${RELEASE}将会
  2. 终止${wait_pid}处理到
  3. 退出tail

注意:sed可能更复杂,以实际确定tail在启动时将产生的行数并删除该数目。但通常是10。

6
nix