【问题标题】:Output the console text of a Jenkins job that my Job is running输出我的作业正在运行的 Jenkins 作业的控制台文本
【发布时间】:2015-10-09 20:14:21
【问题描述】:

我尝试查看 hereherehere

我正在使用 dsl 流程。而且我希望能够在我正在运行的作业中看到我正在构建的作业中打印出来的控制台日志。我试着四处寻找例子,但似乎找不到我要找的东西。如果这个问题没有使用正确的术语或以不同的方式提出,我深表歉意。我只想找到如何做到这一点的答案。

A = build("Main Suites", SUITE: "qa_smoketests", OS: "mac")

下面我尝试这样做,但它似乎没有工作

OUTPUT = A.build.doConsoleText()
out.println(OUTPUT)

更新:

我尝试了第二种方法来即时更新它,但我一直遇到 url 的问题?奇怪的是,如果我单击错误中的 url 链接,它会将我带到相应的页面。我确实必须修改工作名称中包含空格的内容。我还为这篇文章编辑了我的错误日志,说 MYHOSTURL 而不是我实际的 Jenkins 主机 url。

ERROR: Failed to run DSL Script
java.util.concurrent.ExecutionException: org.codehaus.groovy.runtime.InvokerInvocationException: java.io.IOException: Server returned HTTP response code: 401 for URL: http://MYHOSTURL/job/Main%20Suites/159/consoleText
    at java.util.concurrent.FutureTask.report(FutureTask.java:122)
    at java.util.concurrent.FutureTask.get(FutureTask.java:188)
    at java_util_concurrent_Future$get$7.call(Unknown Source)
    at com.cloudbees.plugins.flow.FlowDelegate$_parallel_closure6.doCall(FlowDSL.groovy:440)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
    at groovy.lang.Closure.call(Closure.java:415)
    at groovy.lang.Closure.call(Closure.java:428)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1379)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1351)
    at org.codehaus.groovy.runtime.dgm$170.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:271)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at com.cloudbees.plugins.flow.FlowDelegate.parallel(FlowDSL.groovy:438)
    at sun.reflect.GeneratedMethodAccessor10240.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1079)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:723)
    at com.cloudbees.plugins.flow.FlowDelegate.invokeMethod(FlowDSL.groovy)
    at hudson.util.spring.ClosureScript.invokeMethod(ClosureScript.java:83)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:72)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
    at Script1.run(Script1.groovy:12)
    at Script1$run.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
    at Script1$run.call(Unknown Source)
    at com.cloudbees.plugins.flow.FlowDSL.executeFlowScript(FlowDSL.groovy:84)
    at com.cloudbees.plugins.flow.FlowRun$FlyweightTaskRunnerImpl.run(FlowRun.java:219)
    at hudson.model.Run.execute(Run.java:1759)
    at com.cloudbees.plugins.flow.FlowRun.run(FlowRun.java:155)
    at hudson.model.ResourceController.execute(ResourceController.java:89)
    at hudson.model.Executor.run(Executor.java:240)
    at hudson.model.OneOffExecutor.run(OneOffExecutor.java:43)
Caused by: org.codehaus.groovy.runtime.InvokerInvocationException: java.io.IOException: Server returned HTTP response code: 401 for URL: http://MYHOSTURL/job/Main%20Suites/159/consoleText
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:97)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
    at groovy.lang.Closure.call(Closure.java:415)
    at groovy.lang.Closure.call(Closure.java:409)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: Server returned HTTP response code: 401 for URL: http://MYHOSTURL/job/Main%20Suites/159/consoleText
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1627)
    at sun.net.www.protocol.http.HttpURLConnection$getInputStream.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
    at Script1.responseFrom(Script1.groovy:82)
    at Script1$responseFrom.callCurrent(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at Script1.printConsoleOutputTextChunksFrom(Script1.groovy:62)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:361)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149)
    at Script1$_run_closure2.doCall(Script1.groovy:20)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at Script1$_run_closure2.doCall(Script1.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:39)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:54)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
    at com.cloudbees.plugins.flow.FlowDelegate$_parallel_closure5_closure7.doCall(FlowDSL.groovy:427)
    at sun.reflect.GeneratedMethodAccessor8673.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:903)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at com.cloudbees.plugins.flow.FlowDelegate$_parallel_closure5_closure7.doCall(FlowDSL.groovy)
    at sun.reflect.GeneratedMethodAccessor8672.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    ... 9 more
}
Finished: FAILURE

更新 2:

所以我能够通过修改 responseFrom 函数来处理需要身份验证的页面,从而使第一个方法工作。

InputStream responseFrom(String url)
  {
  // See Using java.net.URLConnection to fire and handle HTTP requests 
  //     https://stackoverflow.com/a/2793153/1744774
  URL myURL = new URL(url);
  HttpURLConnection connection = (HttpURLConnection)myURL.openConnection();
  String userCredentials = "username:password";
  String encoding = new sun.misc.BASE64Encoder().encode(userCredentials.getBytes());
  String basicAuth = "Basic " + encoding;
  connection.setRequestProperty("Authorization", basicAuth);
  connection.setRequestProperty("Accept-Charset", StandardCharsets.UTF_8.name());
  return connection.getInputStream();  
  }

但是,我仍然无法让第二种方法发挥作用。我想这是用于从下游作业获取内部版本号的功能。

java.util.concurrent.ExecutionException: org.codehaus.groovy.runtime.InvokerInvocationException: groovy.lang.MissingMethodException:没有方法签名:静态 java.lang.Integer.parseUnsignedInt() 适用于参数类型: (java.lang.String) 值:[164]

【问题讨论】:

  • Re "没有方法签名:静态 java.lang.Integer.parseUnsignedInt() 适用于参数类型:(java.lang.String)"。 Integer.parseUnsignedInt()声明 “自:1.8”。 如果您使用的是 1.8 之前的版本,请尝试 Integer.parseInt()

标签: groovy jenkins console output


【解决方案1】:

有趣的问题。我无法理解反对票。

  • 您的第一个链接描述了您应该如何做到这一点:通过“重复的 GET 请求”
  • 第二个是关于根据下游作业的控制台输出的内容设置上游作业的结果。除了解析控制台输出之外,这可以通过其他方式更轻松地实现。
  • 第三个方向正好相反:将输出从上游作业传递到下游作业。

我将尝试第一个,然后会相应地更新此答案。

更新 1

下游构建完成后,以下内容会更新上游的日志。

// From: Output the console text of a Jenkins job that my Job is running
//       http://stackoverflow.com/a/31573477/1744774
final String JENKINS_HOST = 'http://<your Jenkins host>'
final String DOWNSTREAM_NAME = '<your downstream job's name>'

final String SEPARATOR = new String(new char[8]).replace('\0', '-')
final int DOWNSTREAM_BUILD_NO = build(DOWNSTREAM_NAME).getBuild().getNumber()

println("${SEPARATOR} Begin console HTML output of ${DOWNSTREAM_NAME} #${DOWNSTREAM_BUILD_NO} ${SEPARATOR}")
printConsoleOutputHtmlFrom(
    "${JENKINS_HOST}/job/${DOWNSTREAM_NAME}/${DOWNSTREAM_BUILD_NO}/console")

println("${SEPARATOR} Begin console text output of ${DOWNSTREAM_NAME} #${DOWNSTREAM_BUILD_NO} ${SEPARATOR}")
printConsoleOutputTextFrom(
    "${JENKINS_HOST}/job/${DOWNSTREAM_NAME}/${DOWNSTREAM_BUILD_NO}/consoleText")

println("${SEPARATOR} End console output of ${DOWNSTREAM_NAME} ${SEPARATOR}")

import org.xml.sax.InputSource

void printConsoleOutputHtmlFrom(String consoleUrl)
  {
  println(xPathExpression('//pre[contains(@class, "console-output")]')
              .evaluate(new InputSource(responseFrom(consoleUrl))))
  }

import java.nio.charset.StandardCharsets

void printConsoleOutputTextFrom(String consoleTextUrl)
  {
  BufferedReader log = new BufferedReader(
      new InputStreamReader(responseFrom(consoleTextUrl), StandardCharsets.UTF_8.name()));
  while ((line = log.readLine()) != null)
    {
    println(line)
    }
  }

InputStream responseFrom(String url)
  {
  // See Using java.net.URLConnection to fire and handle HTTP requests 
  //     http://stackoverflow.com/a/2793153/1744774
  URLConnection connection = new URL(url).openConnection();
  connection.setRequestProperty("Accept-Charset", StandardCharsets.UTF_8.name());
  return connection.getInputStream();  
  }

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

XPathExpression xPathExpression(String expression)
  {
  // See How to read XML using XPath in Java
  //     http://stackoverflow.com/a/2811101/1744774
  XPathFactory xPathFactory = XPathFactory.newInstance();
  XPath xPath = xPathFactory.newXPath();
  return xPath.compile(expression);
  }

参考资料:

更新 2

以下内容会即时更新上游的日志。

// From: Output the console text of a Jenkins job that my Job is running
//       http://stackoverflow.com/a/31573477/1744774
final String JENKINS_HOST = 'http://<your Jenkins host>'
final String DOWNSTREAM_NAME = '<your downstream job's name>'

final String SEPARATOR = new String(new char[8]).replace('\0', '-')

import java.util.concurrent.TimeUnit

parallel(
  { build(DOWNSTREAM_NAME) },
  {
  final String THIS_BUILD_NAME = build.getProject().getName()
  final int THIS_BUILD_NO = build.getNumber()
  final int DOWNSTREAM_BUILD_NO = downstreamBuildNoFrom(
      "${JENKINS_HOST}/job/${THIS_BUILD_NAME}/${THIS_BUILD_NO}/consoleText") 
    
  println("${SEPARATOR} Begin console output of ${DOWNSTREAM_NAME} #${DOWNSTREAM_BUILD_NO} ${SEPARATOR}")
  
  printConsoleOutputTextChunksFrom(
      "${JENKINS_HOST}/job/${DOWNSTREAM_NAME}/${DOWNSTREAM_BUILD_NO}/consoleText", 3L, TimeUnit.SECONDS)
  
  println("${SEPARATOR} End console output of ${DOWNSTREAM_NAME} #${DOWNSTREAM_BUILD_NO} ${SEPARATOR}")
  })

int downstreamBuildNoFrom(String thisBuildConsoleTextUrl)
  {
  int downstreamBuildNo = -1
  while (downstreamBuildNo <= 0)
    {
    TimeUnit.SECONDS.sleep(1L)
    BufferedReader log = new BufferedReader(
        new InputStreamReader(responseFrom(thisBuildConsoleTextUrl), StandardCharsets.UTF_8.name()));
    while ((line = log.readLine()) != null)
      {
      if (line.matches('.* Build .* started'))
        {
        final int buildNoIdx = line.indexOf('#') + 1
        downstreamBuildNo = Integer.parseUnsignedInt(
            line.substring(buildNoIdx, line.indexOf(' ', buildNoIdx)))
        break
        }
      /*if (log.lines().anyMatch(t -> t.matches(".* Build .* started")))
        {
        // in case of Java >=8
        }*/
      }
    }
  return downstreamBuildNo
  } // downstreamBuildNoFrom()

import java.nio.charset.StandardCharsets

void printConsoleOutputTextChunksFrom(String consoleTextUrl, long updateInterval, TimeUnit updateIntervalUnit)
  {
  final int LINE_BREAK_LENGTH = System.getProperty("line.separator").length()
  int charsPrintedSoFar = 0
  while (true) // effectively a do { ... }
    {
    int charsPrintedThisTime = 0
    BufferedReader chunk = new BufferedReader(
        new InputStreamReader(responseFrom(consoleTextUrl), StandardCharsets.UTF_8.name()))
    chunk.skip(charsPrintedSoFar)
    while ((line = chunk.readLine()) != null)
      {
      println(line)
      charsPrintedThisTime = line.length() + LINE_BREAK_LENGTH
      charsPrintedSoFar += charsPrintedThisTime
      }
    updateIntervalUnit.sleep(updateInterval)
    if (charsPrintedThisTime == 0)
      break
    } 
  } // printConsoleOutputTextChunksFrom()

InputStream responseFrom(String url)
  {
  // See Using java.net.URLConnection to fire and handle HTTP requests 
  //     http://stackoverflow.com/a/2793153/1744774
  URLConnection connection = new URL(url).openConnection();
  connection.setRequestProperty("Accept-Charset", StandardCharsets.UTF_8.name());
  return connection.getInputStream();  
  }

【讨论】:

  • 感谢您的善意和努力。我想我可能会被否决,因为最初我只是说我查看了示例但我没有链接它们。我对詹金斯还是很陌生。我想也许我可以使用下面的方法打印出链接的内容。 buildnumber = A.build.number OUTPUT = "myurl" + buildnumber + "/logText/progressiveHtml" 不知道那个链接的内容怎么显示?精确模拟控制台输出在下游作业中的外观是理想的。实时更新。
  • @BarretV 我的答案更新中的实现是否适合您的需求?
  • 好吧,我不确定是否是我的控制台输出导致了问题。我正在输出一套量角器测试的结果,有几次它会输出结果,而其他时候它会在 xml 解析中遇到错误。我猜有些字符是不允许的。
  • @BarretV 它总是发生在同一个工作还是随机工作?错误发生在哪一行,具体是哪一行?你能提供失败的工作的日志吗?你的意思是量角器,还是别的什么,不为predefined entities写字符引用,而是为字符本身写?
  • 是的,我正在使用量角器。不幸的是,我们只保留了我们测试的最后 20 次运行,所以我得到的错误不再出现。我还在使用 jasmine-spec-reporter 作为控制台输出。这是您可能会看到的输出示例gist.github.com/bvasilchik/38ff064f89df307534a8
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多