arraysgroovyjenkins-groovybytebufferbytearrayoutputstream

Writing to output stream in chunks in Groovy


I'm getting Jenkins console logs and writing them into an output stream like this:

    ByteArrayOutputStream stream = new ByteArrayOutputStream()
    currentBuild.rawBuild.getLogText().writeLogTo(0, stream)

However, the downside of this approach is that writeLogTo() method is limited to 10000 lines: https://github.com/jenkinsci/stapler/blob/master/core/src/main/java/org/kohsuke/stapler/framework/io/LargeText.java#L572

In this case, if Jenkins console log is more than a 10000 lines then the data from line 10000 and up is lost and not written into a buffer.

I'm trying to re-write the above approach in the most easiest way to account for cases when the log has more than 10000 lines.

I feel like my attempt is very complicated and error-prone. Is there an easier way to introduce a new logic?

Please note that the code below is not tested, this is just a draft of how I'm planning to implement it:

ByteArrayOutputStream stream = new ByteArrayOutputStream()
def log = currentBuild.rawBuild.getLogText()

def offset = 0
def maxNumOfLines = 10000

# get total number of lines in the log
# def totalLines = (still trying to figure out how to get it)
if (totalLines > maxNumOfLines) {
    def numOfExecutions = round(totalLines / maxNumOfLines)
}

for (int i=0; i<numOfExecutions; i++) {
    log.writeLogTo(offset, stream)
    offset += maxNumOfLines
}

Solution

  • writeLogTo(long start, OutputStream out)
    

    According to comments this method returns the offset to start the next write operation.

    Seems code could be like this

    def logFile = currentBuild.rawBuild.getLogText()
    def start=0
    while(logFile.length()>start)
        start=logFile.writeLogTo(start, stream)
    

    stream could be a FileOutputStream to avoid reading whole log into memory.

    There is another method readAll()

    So, the code could be simple as this to read whole log as text:

    def logText=currentBuild.rawBuild.getLogText().readAll().getText()
    

    Or if you want to transfer it to a local file:

    new File('path/to/file.log').withWriter('UTF-8'){ w->
        w << currentBuild.rawBuild.getLogText().readAll()
    }