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


54

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

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

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


3
一定要使用tail -F处理日志旋转-即my.log满,并移动到my.log.1和你的进程创建一个新的my.log
SG

Answers:


34

一个简单的方法将是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");
    }
}

我喜欢awk短而易行的解决方案。但是,如果我要运行的命令带有引号,则可能有点麻烦,是否有替代方法,可能使用管道和复合命令,它们也允许使用简短的单线解决方案,但不需要传递结果命令作为字符串?
jonderry 2011年

1
@jon您可以将awk编写为脚本。使用“#!/ usr / bin awk -f”作为脚本的第一行。这将消除我的示例中对外部单引号的需求,并释放它们以在system()命令内部使用。
penguin359 2011年

@ penguin359,是的,但是从命令行执行它仍然很有趣。就我而言,我想做很多不同的事情,包括很多我无法预料的事情,因此能够方便地启动服务器并在一站式完成这一切很方便。
jonderry

我找到了一个替代方案,尽管我不知道它的坚固程度:tail -f /path/to/serverLog | grep "server is up" | head -1 && do_some_command
jonderry

@jon那样使用head似乎有点脆弱。更重要的是,它不能像我的示例那样重复。如果“服务器启动”在日志的最后十行中,它将触发命令并立即退出。如果重新启动它,除非在日志中添加了十行不包含“ server is up”的行,否则很有可能再次触发并退出。可能会更好的修改是,tail -n 0 -f /path/to/serverLog 它将读取文件的最后0行,然后等待更多行打印。
penguin359

16

如果您只是在寻找一种可能性,并且希望将大部分时间留在shell中而不是使用awkperl,则可以执行以下操作:

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

...该文件将在my_command每次“ 服务器启动 ” 时运行。对于多种可能性,也许你可以删除grep,而使用一个casewhile

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

--line-buffered选项告诉grep每行之后刷新其缓冲区;否则,my_command可能无法及时到达(假设原木具有合理尺寸的线)。


2
我真的很喜欢这个答案,但起初对我没有用。我认为您需要向中添加该--line-buffered选项grep,否则请确保该选项刷新行之间的输出:否则,它只会挂起,并且my_command永远不会到达。如果愿意ack,它带有一个--flush标志;如果愿意ag,可以尝试用stdbufstackoverflow.com/questions/28982518/…–
记载

我尝试使用do exit ;。看起来工作正常,但是拖尾从未完成,我们的脚本也从未移至下一行。有没有办法阻止该do节的尾巴?
Machtyn

14

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

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

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

我可以在这里找到有关样本的30秒最佳教程:http : //www.campin.net/newlogcheck.html


1
该教程现在是404:/
从这里开始


10

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

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

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

又见另一个实例multitail使用。


+1,我不知道`multitail拥有那些忍者技能。感谢您指出了这一点。
Caleb

8

可以自己完成这项工作

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

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;
  ...
')

6

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

  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。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.