tail a log util 关键字发现或超时

tail a log util 关键字发现或超时

我正在使用一种特殊的方式,可以让我访问谷歌。现在的页面有很大不同...所以我可以正常编辑问题并评论答案。我删除了更多早期的讨论并进入正题。

当找到脚本执行下一个命令的关键字时,我想停止拖尾并返回 0。如果一分钟后没有找到关键字,整个脚本将停止并返回错误代码。我正在使用,set -euxo pipefail这是必要的。

timeout 1m tail -Fn 0 --pid=$(ps -ef | grep "sed /$keywords" | grep -v grep | awk '{print $2}') $log_file | sed "/$keywords/q"

我之前使用的上面的命令在我测试时接缝正常。但在 Jenkins 中,当找到关键字时,有时它会返回“构建步骤‘执行 shell’将构建标记为失败”。

我手动重启程序后找到了原因。它返回代码141。所以我查了一下代码,发现它与tail -fand pipeline |in有关http://www.pixelbeat.org/programming/sigpipe_handling.html


为了我的目的,我修改了其他问题中的命令。看起来一切都很好,只是“tail -Fn 0 balabala.log”仍然留在后台,几分钟后就消失了。但它距离目标最近。

{ sed /"$keywords"/q; kill -13 $!; } < <(exec timeout 1m tail -Fn 0 $log_file)

这超出了我的理解范围...我查阅了用法但仍然感到不确定。

  1. 我改为kill -s PIPE "$!"缩短kill -13 $!脚本。
  2. 我仍然对 的用法感到困惑{ } < <()。它们对我来说就像陌生的词......
  3. 可以exec删除吗?好像和不写不一样。
  4. tail后台有什么问题吗?如果我同时启动多个程序会有危险吗?

这是詹金斯的日志:

......
+ keywords='cloud-service-notice has been started successfully'
+ log_file=/data/jars/logs/info.cloud-service-notice.log
+ cd /data/jars/cloud-service-notice
+ nohup java -jar /data/jars/cloud-service-notice/cloud-service-notice.jar --spring.profiles.active=test
+ sed '/cloud-service-notice has been started successfully/q'
++ exec timeout 1m tail -Fn 0 /data/jars/logs/info.cloud-service-notice.log
2019-07-02 10:31:12,544 [main] INFO  o.s.c.a.AnnotationConfigApplicationContext.prepareRefresh[588] - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@54a097cc: startup date [Tue Jul 02 10:31:12 CST 2019]; root of context hierarchy
......
2019-07-02 10:31:33,860 [main] INFO  c.enneagon.service.notice.NoticeApp.main[24] - cloud-service-notice has been started successfully
+ kill -13 20021
+ ssh web01 'cd /data/releases/cloud-service-notice/20190702-104108/.. &&' 'ls -1 | sort -r | awk '\''FNR > 20  {printf("rm -rf %s\n", $0);}'\'' | bash'
Finished: SUCCESS

进程 20021 是timeout 1m tail -Fn 0 balabala.log。脚本完成后,进程20023tail -Fn 0 balabala.log仍然存在,几分钟后就消失了。

[root@web01 scripts]# ps -ef | grep notice
root     20020     1 27 10:41 ?        00:01:07 java -jar /data/jars/cloud-service-notice/cloud-service-notice.jar --spring.profiles.active=test
root     20023     1  0 10:41 ?        00:00:00 tail -Fn 0 /data/jars/logs/info.cloud-service-notice.log
root     20461 18966  0 10:45 pts/1    00:00:00 grep --color=auto notice

我将用这个命令回答我的问题,但我不确定。我在本地机器上测试了它,并将其放在我们的生产环境中进行进一步测试。


经过多次测试,我最终将命令改为:

{ sed /"$keywords"/q; kill $!; } < <(exec timeout 1m tail -Fn 0 $log_file)

-13只是被删除。这就是留下来的原因tail -Fn 0 balabala.log。我可以大致回答上面四个问题:

  1. kill -15更好,因为我添加了timeout这个命令。$!是 的 pid timeouttail -Fn 0 balabala.log这里是一个子进程,使用默认数字 15 可以杀死它。
  2. 它只是一个进程替换和多个进程使用{...}。我什至可以忽略,kill因为 1 分钟后timeout就会在后台自杀。所以这个命令不带kill仍然可以接受:sed /"$keywords"/q < <(exec timeout 1m tail -Fn 0 $log_file)。在这种情况下,它将始终返回 0。
  3. 最好不要。执行命令时会显示两个上层进程。不过做完之后就没事了。
  4. 原因就在上面的“1”中。timeout被杀了,却被tail留下了。

答案1

你可以这样做:

sh -c 'echo "$$"; exec tail -f file' | (
  IFS= read -r pid
  timeout 60 sed "/$keyword/q"
  kill -s PIPE "$pid"
)

除非您启用了该pipefail选项,否则它将退出,退出状态kill应为 0,除非tail它自己退出(这在实践中不应发生)。

使用 时pipefail,它将以由 SIGPIPE 杀死的退出状态退出tail(大多数 shell 用值 141 表示)。您始终可以附加 a|| true来强制成功退出状态。

也可以看看:

答案2

我认为这里发生的是竞争条件。tail --pid=...依赖于tail检查并认识到跟踪的 PID 在收到 SIGPIPE(通常为 13 号信号,对应于您获得的 128+13=141 退出状态)之前因尝试写入因sed终止而损坏的管道而已死亡。这手动的只是说“该进程终止后不久,tail也会终止”,因此检查可能不会频繁。

不管怎样,如果tail确实被 SIGPIPE 杀死,这意味着(通常)sed已经得到了你想要的线路并且已经退出,所以应该成为您成功的条件。我建议将其视为完全一样,使用if块来防止set -e,并显式检查退出状态:

if timeout tail ... | sed ...; ret=$?; then
    : # do nothing, success
elif [ "$ret" != 141 ]  # not sigpipe, sed didn't quit, so failure
    exit "$ret"
fi

旁白:你说脚本使用#/bin/bash.那应该#!带有感叹号,而不仅仅是#。如果没有这个脚本将使用 sh 运行,这可能就是您尝试使用进程替换的原因(<(...)过程,不是命令,而是替换)是语法错误。仔细检查一下。

我知道您说过您想要一个单衬管,但就可维护性而言,复杂的单衬管并不总是最佳解决方案。如果使用多行可以更轻松地记录您正在做的事情,则可以使用多行。

答案3

我找到了一个命令。详细信息在问题中。

{ sed /"$keywords"/q; kill $!; } < <(exec timeout 1m tail -Fn 0 $log_file)

#!/bin/bashset -euxo pipefail如果在脚本中则需要和,该脚本必须由 执行bash,而不是,尽管在 CentOS 中sh链接到。bash

相关内容