48

詹金斯很新,我有一个简单但烦人的问题。当我在 Jenkins 上运行作业(构建)时,我触发了 ruby​​ 命令来执行我的测试脚本。

问题是 Jenkins 没有从控制台实时显示输出。这是触发日志。

Building in workspace /var/lib/jenkins/workspace/foo_bar
No emails were triggered.
[foo_bar] $ /bin/sh -xe /tmp/hudson4042436272524123595.sh
+ ruby /var/lib/jenkins/test-script.rb

基本上它会挂在这个输出上,直到构建完成,而不是只显示完整的输出。有趣的是,这不是一致的行为,有时它可以正常工作。但大多数时候没有实时控制台输出。

詹金斯版本:1.461

4

9 回答 9

70

澄清一些答案。

  • rubyorpython或任何合理的脚本语言将缓冲输出;这是为了最小化IO;写入磁盘很慢,写入控制台很慢......
  • 通常,flush()在缓冲区中有足够的数据并对换行符进行特殊处理后,数据会自动获取。例如,在没有换行符的情况下编写字符串,然后sleep()在完成之前不会写入任何内容sleep()(我仅用sleep作示例,请随意替换任何其他昂贵的系统调用)。

例如,这将等待 8 秒,打印一行,再等 5 秒,打印第二行。

from time import sleep

def test():
    print "ok",
    time.sleep(3)
    print "now",
    time.sleep(5)
    print "done"
    time.sleep(5)
    print "again"

test()
  • 对于ruby, STDOUT.sync = true, 开启autoflush;所有的写入STDOUT都跟在flush(). 这将解决您的问题,但会导致更多的 IO。

    STDOUT.sync = true
    
  • 对于python, 可以使用python -uor 环境变量PYTHONUNBUFFERED来做stdin/stdout/stout不缓冲,但是还有其他的解决方案不改stdin或者stderr

    export PYTHONUNBUFFERED=1
    
  • 因为perl,你有autoflush

    autoflush STDOUT 1;
    
于 2014-01-21T19:44:55.200 回答
13

确保您的脚本正在刷新其标准输出和标准错误。就我而言,我遇到了与您描述的类似的缓冲问题,但我使用的是 python。以下python代码为我修复了它:

import sys
sys.stdout.flush()

我不是 Ruby 编码员,但 Google 揭示了以下内容:

$stdout.flush
于 2012-10-19T11:43:16.700 回答
8

在我看来,这python -u也有效。

例如在批处理命令中

python -u foo.py
于 2014-01-21T00:22:08.040 回答
4

这里最简单的解决方案是打开同步缓冲区到输出。@Craig 在他的回答中写了一些东西,但是一个解决方案将涵盖整个脚本,并且不需要您多次刷新缓冲区。

写吧

STDOUT.sync = true

后面的逻辑很简单,避免多次使用 IO 操作输出缓冲。要禁用此使用

STDOUT.sync = false

这是 Ruby 解决方案 ofc。

于 2012-10-19T12:10:49.353 回答
3

其他每个答案都特定于一个程序或另一个,但我在这里找到了一个更通用的解决方案:

https://unix.stackexchange.com/a/25378

您可以使用它stdbuf来改变任何程序的缓冲行为。

tee在我的例子中,我将 shell 脚本的输出通过管道grep传输到控制台或基于内容的文件中。如 OP 所述,控制台已挂起。这解决了它:

./slowly_parse.py login.csv |tee >(grep -v LOG: > out.csv) | stdbuf -oL -eL grep LOG:

最终我发现我可以传递--line-buffered给 grep 以获得相同的结果:

./slowly_parse.py login.csv |tee >(grep -v LOG: > out.csv) | grep --line-buffered LOG:
于 2014-10-11T02:39:05.717 回答
3

其他答案是正确的,您需要确保标准输出不被缓冲。

要注意的另一件事是 Jenkins 本身会逐行缓冲。如果您有一个运行缓慢的进程发出单个字符(例如,一个 nunit 测试套件摘要,它打印一个.成功测试和E一个错误),您将在行尾之前看不到任何内容。

[适用于我在 Windows 机器上运行的 Jenkins 1.572。]

于 2015-07-08T08:36:27.170 回答
1

对于某些命令,包括tee取消缓冲的最佳选择是unbufferexpect包中调用的程序。

使用示例:

代替

somecommand | tee /some/path

somecommand | unbuffer -p tee /some/path

来源和更多信息:

于 2018-10-09T18:30:50.027 回答
0

操作系统本质上是缓冲输出数据以节省 CPU,Jenkins 也是如此。

看起来您正在使用 shell 命令运行 Ruby 脚本 -
我建议直接通过专用插件运行 Ruby 脚本:

詹金斯红宝石插件

(可能需要安装)

于 2012-07-24T20:41:27.213 回答
0

Python 缓冲其输出跟踪并在脚本末尾打印它,以尽量减少控制台上的写入,因为写入控制台很慢。

您可以在跟踪后使用以下命令。它会将所有跟踪刷新到控制台,这些跟踪在该命令之前排队。

sys.stdout.flush()

于 2019-04-23T14:06:38.150 回答