Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-75081

The /logText/progressiveText API exhaust heap memory on large logs of completed builds

XMLWordPrintable

    • 2.509

      Hitting the /logText/progressiveText API of a completed build with very large log file ( XXX MB or X GB or more) exhaust the heap memory.

      The Jetty thread handling it looks like this:

      "Handling GET /job/testLog/5//logText/progressiveText from 127.0.0.1 : Jetty (winstone)-19" id=19 state=RUNNABLE
          at java.base@17.0.8/java.util.zip.Deflater.deflateBufferBytes(Native Method)
          at java.base@17.0.8/java.util.zip.Deflater.deflate(Deflater.java:751)
          at Jenkins Main ClassLoader//org.eclipse.jetty.server.handler.gzip.GzipResponseAndCallback$GzipBufferCB.compressing(GzipResponseAndCallback.java:410)
          at Jenkins Main ClassLoader//org.eclipse.jetty.server.handler.gzip.GzipResponseAndCallback$GzipBufferCB.process(GzipResponseAndCallback.java:370)
          at Jenkins Main ClassLoader//org.eclipse.jetty.util.IteratingCallback.processing(IteratingCallback.java:262)
          at Jenkins Main ClassLoader//org.eclipse.jetty.util.IteratingCallback.iterate(IteratingCallback.java:243)
          at Jenkins Main ClassLoader//org.eclipse.jetty.server.handler.gzip.GzipResponseAndCallback.gzip(GzipResponseAndCallback.java:157)
          at Jenkins Main ClassLoader//org.eclipse.jetty.server.handler.gzip.GzipResponseAndCallback.write(GzipResponseAndCallback.java:135)
          at Jenkins Main ClassLoader//org.eclipse.jetty.server.Response$Wrapper.write(Response.java:768)
          at Jenkins Main ClassLoader//org.eclipse.jetty.server.handler.ContextResponse.write(ContextResponse.java:56)
          at Jenkins Main ClassLoader//org.eclipse.jetty.ee9.nested.HttpChannel.send(HttpChannel.java:1044)
          at Jenkins Main ClassLoader//org.eclipse.jetty.ee9.nested.HttpChannel.sendResponse(HttpChannel.java:1028)
          at Jenkins Main ClassLoader//org.eclipse.jetty.ee9.nested.HttpChannel.write(HttpChannel.java:1110)
          at Jenkins Main ClassLoader//org.eclipse.jetty.ee9.nested.HttpOutput.channelWrite(HttpOutput.java:277)
          at Jenkins Main ClassLoader//org.eclipse.jetty.ee9.nested.HttpOutput.channelWrite(HttpOutput.java:261)
          at Jenkins Main ClassLoader//org.eclipse.jetty.ee9.nested.HttpOutput.write(HttpOutput.java:876)
          at java.base@17.0.8/java.io.ByteArrayOutputStream.writeTo(ByteArrayOutputStream.java:161)
            - locked org.eclipse.jetty.util.ByteArrayOutputStream2@5ff96858
          at Jenkins Main ClassLoader//org.eclipse.jetty.io.WriteThroughWriter$Utf8Writer.append(WriteThroughWriter.java:335)
          at Jenkins Main ClassLoader//org.eclipse.jetty.io.WriteThroughWriter.write(WriteThroughWriter.java:138)
          at Jenkins Main ClassLoader//org.eclipse.jetty.ee9.nested.ResponseWriter.write(ResponseWriter.java:209)
            - locked org.eclipse.jetty.io.WriteThroughWriter$Utf8Writer@4cb1d7cd
          at org.springframework.security.web.util.OnCommittedResponseWrapper$SaveContextPrintWriter.write(OnCommittedResponseWrapper.java:314)
          at java.base@17.0.8/java.io.FilterWriter.write(FilterWriter.java:83)
          at org.kohsuke.stapler.framework.io.LineEndNormalizingWriter.write(LineEndNormalizingWriter.java:78)
          at org.kohsuke.stapler.framework.io.LineEndNormalizingWriter.write(LineEndNormalizingWriter.java:51)
          at org.kohsuke.stapler.framework.io.CharSpool.writeTo(CharSpool.java:86)
          at org.kohsuke.stapler.framework.io.LargeText.doProgressTextImpl(LargeText.java:319)
          at org.kohsuke.stapler.framework.io.LargeText.doProgressText(LargeText.java:274)
          at hudson.console.AnnotatedLargeText.doProgressiveText(AnnotatedLargeText.java:128)
          at java.base@17.0.8/java.lang.invoke.LambdaForm$DMH/0x000000013e120400.invokeVirtual(LambdaForm$DMH)
          at java.base@17.0.8/java.lang.invoke.LambdaForm$MH/0x000000013ece2800.invoke(LambdaForm$MH)
          at java.base@17.0.8/java.lang.invoke.LambdaForm$MH/0x000000013ec9dc00.invoke(LambdaForm$MH)
          at java.base@17.0.8/java.lang.invoke.LambdaForm$MH/0x000000013ec9c000.invokeExact_MT(LambdaForm$MH)
          at java.base@17.0.8/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
          at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:484)
          at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:497)
          at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:218)
          at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:140)
          at org.kohsuke.stapler.MetaClass$12.doDispatch(MetaClass.java:686)
          at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:61)
          at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:800)
          at org.kohsuke.stapler.Stapler.invoke(Stapler.java:938)
          at org.kohsuke.stapler.MetaClass$2.doDispatch(MetaClass.java:244)
          at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:61)
          at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:800)
          at org.kohsuke.stapler.Stapler.invoke(Stapler.java:938)
          at org.kohsuke.stapler.MetaClass$10.dispatch(MetaClass.java:590)
          at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:800)
          at org.kohsuke.stapler.Stapler.invoke(Stapler.java:938)
          at org.kohsuke.stapler.MetaClass$5.doDispatch(MetaClass.java:369)
          at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:61)
          at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:800)
          at org.kohsuke.stapler.Stapler.invoke(Stapler.java:938)
          at org.kohsuke.stapler.Stapler.invoke(Stapler.java:721)
          at org.kohsuke.stapler.Stapler.service(Stapler.java:253)
          at Jenkins Main ClassLoader//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:587)
          at Jenkins Main ClassLoader//org.eclipse.jetty.ee9.servlet.ServletHolder.handle(ServletHolder.java:765)
      

      On the other hand, the console output is not impacted by this and efficiently stream the logs.

      The API documentation is not clear about how to stream the data should a REST Client want to do something similar:

      Or if it is even possible.

      How to Reproduce

      • Spin a controller
      • Create a pipeline that generates a lot of logs, for example:
      node {
          sh """
      head -c 10073741824 /dev/urandom | base64 --break=1000
      """
      }
      
      • Build it
      • Once completed, go to $JOB_URL/logText/progressiveText
      • Generate a heapdump and observe that the Jetty thread holds everything in memory

      cc @jglick who helped confirm this bug.

            jglick Jesse Glick
            allan_burdajewicz Allan BURDAJEWICZ
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: