Jenkins Pipeline - how to get logs from parallel builds

I needed to access logs from within the pipeline code
so I implemented the algorithm proposed by キキジキ (really helpful) with a few adjustments (to add branchName prefix on each line to be able to get the whole log and still figure out which branch corresponds to each line ; and to support nested branches, which I needed) in https://github.com/gdemengin/pipeline-logparser :

  • to get logs programmatically

    • to get the full logs with branch prefix (similar to what currentBuild.rawBuild.log returned before version 2.2.5 of workflow-job plugin. but in version 2.26 they got rid of the branch information and I could not find any built-in function with the same information)
      String logs = logparser.getLogsWithBranchInfo()

      [Pipeline] Start of Pipeline
      [Pipeline] parallel
      [Pipeline] { (Branch: branch1)
      [Pipeline] { (Branch: branch2)
      [Pipeline] }
      [Pipeline] echo
      [branch1] in branch1
      [Pipeline] sleep
      [branch1] Sleeping for 1 sec
      [Pipeline] echo
      [branch2] in branch2
      [Pipeline] sleep
      [branch2] Sleeping for 1 sec

    • get the logs from 'branch2' only
      String logsBranch2 = logparser.getLogsWithBranchInfo(filter: ['branch2'])

      [branch2] in branch2
      [branch2] Sleeping for 1 sec

  • to archive logs (in as $JOB_URL/<runId>/artifacts) to have them available as a link for later use

    • to archive the full logs (with branch prefix)
      logparser.archiveLogsWithBranchInfo('consoleText.txt')

    • to archive the logs from branch2 only
      logparser.archiveLogsWithBranchInfo('logsBranch2.txt', [filter: ['branch2']])


I found a way to achieve that, but you need to access the build folder directly (for example using currentBuild.rawBuild.getLogFile().getParent()).

  • Parse the xml files (or the single flowNodeStore.xml file) inside the workflow directory:
    • Build a hierarchy of nodes using the <id> and <parentIds> values.
    • If <branchName> is defined associate it to the current node and recursively to all nodes that have this node as parent. If a node has multiple parents assign no branch value to it.
  • Read the log file as byte[].
  • Read each line of log-index to find log ranges to assign to each node. The format of a line can be one of the following:
    • offset nodeId -> start of new node range, end of the previous (if present).
    • offset: end of current node range.
  • Convert the byte range back to a utf8 string (new String(range, "UTF-8")).
    • You might want to strip away all embedded codes with something like replaceAll("\u001B.*?\u001B\\[0m", "")