Continuous integration Jenkins控制台输出不实时

Continuous integration Jenkins控制台输出不实时,continuous-integration,jenkins,Continuous Integration,Jenkins,詹金斯是个新手,我有一个简单但烦人的问题。当我在Jenkins上运行job(Build)时,我触发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/l

詹金斯是个新手,我有一个简单但烦人的问题。当我在Jenkins上运行job(Build)时,我触发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

操作系统本质上是在缓冲输出数据,以节省CPU,詹金斯也是如此

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


(可能需要安装)

确保脚本正在刷新其标准输出和标准输出。 在我的例子中,我遇到了一个与您描述的类似的缓冲问题,但我使用的是python。 下面的python代码为我修复了它:

导入系统 sys.stdout.flush() 我不是Ruby程序员,但Google透露了以下信息:

$stdout.flush

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

只要写

STDOUT.sync = true
后面的逻辑很简单,以避免在缓冲输出时多次使用IO操作。要禁用此功能,请执行以下操作:

STDOUT.sync = false

这是C的Ruby解决方案。

在我看来,
python-u
也可以工作

例如,批处理命令

python -u foo.py

澄清一些答案

  • ruby
    python
    或任何合理的脚本语言将缓冲输出;这是为了最小化IO;写入磁盘很慢,写入控制台很慢
  • 通常,在缓冲区中有足够的数据并对换行进行特殊处理后,数据会自动进行
    flush()
    。e、 g.在
    sleep()
    完成之前,如果不使用换行符编写字符串,那么
    sleep()
    将不会写入任何内容(我仅使用
    sleep
    作为示例,请随意使用任何其他昂贵的系统调用进行替换)
e、 g.这将等待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
    ,打开
    autoflush
    ;所有写入
    STDOUT
    的操作后面都是
    flush()
    。这将解决您的问题,但会导致更多IO

    STDOUT.sync = true
    
  • 对于
    python
    ,可以使用
    python-u
    或环境变量
    PYTHONUNBUFFERED
    使
    stdin/stdout/stout
    不被缓冲,但不会改变
    stdin
    stderr

    export PYTHONUNBUFFERED=1
    
  • 对于
    perl
    ,您有


其他答案中的每一个都是针对某个项目的,但我在这里找到了一个更通用的解决方案:

您可以使用
stdbuf
更改任何程序的缓冲行为

在我的例子中,我通过
tee
grep
将shell脚本的输出管道化,以便根据内容将行拆分为控制台或文件。控制台如OP所述悬挂。这解决了问题:

./slowly_parse.py login.csv |tee >(grep -v LOG: > out.csv) | stdbuf -oL -eL grep LOG:
最终我发现我可以将
--行缓冲
传递给grep,得到相同的结果:

./slowly_parse.py login.csv |tee >(grep -v LOG: > out.csv) | grep --line-buffered LOG:

其他答案是正确的,您需要确保标准输出没有缓冲

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


[适用于运行在Windows设备上的my Jenkins 1.572。]

对于某些命令,包括
tee
a,解除缓冲的最佳选择是从程序包调用的程序

用法示例:

而不是

somecommand | tee/some/path

somecommand | unbuffer-p tee/some/path

来源和更多信息:


Python缓冲了它的输出跟踪,并在脚本末尾打印它,以最大限度地减少控制台上的写入,因为写入控制台的速度很慢

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

sys.stdout.flush()


您正在运行的服务器功能有多强大?执行此脚本需要多长时间?对我来说,这听起来像是由于服务器过载造成的延迟。当我的詹金斯大师满负荷运转时,我也看到过类似的症状。谢谢你们的关注,这是有道理的。在本例中,我们讨论的是EC2实例
small
,但它只是在运行进程。您可能需要更多吗?这取决于正在运行的作业数量,但是是的,如果您在一个小实例上同时运行的作业数量超过几个,我希望看到延迟。我有一个类似的问题,但是,该机器的规格过高,使用不足。在jenkins之外运行python脚本也可以像预期的那样实时工作。该作业调用一个python脚本,该脚本跟踪另一个进程的日志文件。日志文件实时更新,jenkins输出被分块转储,就好像它在等待填充缓冲区一样。嗨Craig,你是对的,缓冲输出是个问题。使用
STDOUT.sync=true
解决了这个问题。我会尝试一下,这需要一些时间。谢谢。您好,这不起作用:(尝试了相同的结果。另外,由于ruby代码保存在Jenkins作业中,所以解决方案不太实用,因此版本升级更难。我同意该解决方案的“非源代码控制”性质——最好管理Jenkins之外的任何脚本
./slowly_parse.py login.csv |tee >(grep -v LOG: > out.csv) | grep --line-buffered LOG: