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

jon*_*rry 60 logs shell-script tail text-processing

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

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

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

pen*_*359 38

一个简单的方法是 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") }'
Run Code Online (Sandbox Code Playgroud)

是的,这两个都是来自内核日志的真实消息。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");
    }
}
Run Code Online (Sandbox Code Playgroud)


Jan*_*der 27

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

tail -F /path/to/serverLog | 
grep --line-buffered 'server is up' | 
while read ; do my_command ; done
Run Code Online (Sandbox Code Playgroud)

...my_command每次“ server is up ”出现在日志文件中时都会运行。对于多种可能性,您可以删除grep,而是casewhile.

资本-F告诉tail观察要轮换的日志文件;即,如果当前文件被重命名并且另一个同名文件取而代之,tail则将切换到新文件。

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

  • 我真的很喜欢这个答案,但一开始对我不起作用。我认为您需要将 `--line-buffered` 选项添加到 `grep`,或者确保它在行之间刷新其输出:否则,它只是挂起,并且永远不会到达 `my_command`。如果你更喜欢 `ack`,它有一个 `--flush` 标志;如果您更喜欢 `ag`,请尝试使用 `stdbuf` 包装。http://stackoverflow.com/questions/28982518/what-is-ags-silver-searcher-analogous-option-to-greps-line-buffered (3认同)

bah*_*mat 14

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

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

我鼓励你尝试一下。虽然您可以用螺丝刀的背面敲击钉子,但这并不意味着您应该这样做。

我能找到的最好的 30 秒色板教程在这里


Sla*_*hin 11

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

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

multitail -ex timeout "echo timeout | wall" -l "ping 192.168.0.1"
Run Code Online (Sandbox Code Playgroud)

又见另一个实例multitail使用。


F. *_*uri 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)
Run Code Online (Sandbox Code Playgroud)

虽然您不使用 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;
  ...
')
Run Code Online (Sandbox Code Playgroud)


nix*_*nix 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}
Run Code Online (Sandbox Code Playgroud)

它的工作原理是保持tail打开直到${RELEASE}文件包含数据。

一旦grep成功:

  1. 的输出写入到${RELEASE}这将
  2. 终止${wait_pid}进程
  3. 退出 tail

注意:sed实际确定tail启动时将产生的行数并删除该数字可能会更复杂。但一般情况下,它是 10。