When a flow involves many steps, long logs, and/or many branches, it can be hard for a developer receiving a failure email (for example) to quickly see what part of the build actually failed and why. I think it would be useful for the catchError step to do a DFS search on the Throwable and its cause chain through the FlowNode graph starting at the end of the catch step, looking for ErrorAction, and setting/appending an environment variable with the URL of the LogAction. Or provide a new step to do the same. Thus you could write

      def runStuff(param) {
        ...
      }
      try {
        parallel a: {runStuff 'a'}, b: {runStuff 'b'}
      } catch (e) {
        mail to: '...', subject: 'Failure!', body: "Build failed: ${errorUrl(e)}"
      }
      

      and get a link to http://jenkins/job/myflow/123/flowGraph/77/console or the like, according to the actual step in one of the branches that threw the error.

          [JENKINS-28119] Link to log of failed step

          Jesse Glick added a comment -

          Should also be able to get a tail of the log.

          Jesse Glick added a comment - Should also be able to get a tail of the log.

          Michael Neale added a comment -

          In a freestyle job the config is still simpler than the proposed above, having a global "catch all" that sends failure (with pertinent details) would be nice to bring it up to parity.

          Michael Neale added a comment - In a freestyle job the config is still simpler than the proposed above, having a global "catch all" that sends failure (with pertinent details) would be nice to bring it up to parity.

          Michael Neale added a comment -

          Given a common use for this will be to slap a try/catch around everything to get failure messages, would it be possible to have a:

          onFailure DSL that effectively does the same thing? (not sure if this is possible in the current form of things). Ideally this could be scoped to stage, but that may be just too much to ask. The ideal is to make it not too much more work than what people experience now with freestyle, in WF terms.

          Michael Neale added a comment - Given a common use for this will be to slap a try/catch around everything to get failure messages, would it be possible to have a: onFailure DSL that effectively does the same thing? (not sure if this is possible in the current form of things). Ideally this could be scoped to stage, but that may be just too much to ask. The ideal is to make it not too much more work than what people experience now with freestyle, in WF terms.

          This is going to be a primary blocker to my users not adopting pipeline DSL over say, Job DSL (perhaps with some pipeline in it). It's way too cumbersome to require all that raw Groovy code just to send an email on failure.

          The mail post-build step wrapper doesn't actually execute right now because the pipeline DSL aborts the run before it finishes.

          I can of course, create a global wrapper for "node" that embeds a default mail handler and exception trap, but inside that global method I lose access to global variables, like JOB_NAME and other things that make sending the mail more intuitive.

          Maxfield Stewart added a comment - This is going to be a primary blocker to my users not adopting pipeline DSL over say, Job DSL (perhaps with some pipeline in it). It's way too cumbersome to require all that raw Groovy code just to send an email on failure. The mail post-build step wrapper doesn't actually execute right now because the pipeline DSL aborts the run before it finishes. I can of course, create a global wrapper for "node" that embeds a default mail handler and exception trap, but inside that global method I lose access to global variables, like JOB_NAME and other things that make sending the mail more intuitive.

          Michael Neale added a comment -

          maxfields2000 yes agree. I made https://wiki.jenkins-ci.org/display/JENKINS/Simple+Build+For+Pipeline+Plugin to show how this could be made simpler.

          Michael Neale added a comment - maxfields2000 yes agree. I made https://wiki.jenkins-ci.org/display/JENKINS/Simple+Build+For+Pipeline+Plugin to show how this could be made simpler.

          Peter Marcoen added a comment -

          I agree with Michael and Maxfield. It feels like I'm taking a step back when using Pipeline. It used to be as simple as providing the emailaddress to send a mail to when the build failed. Now I have to start coding it in with try-catches.

          I too would prefer a onFailure DSL to avoid all that complexity.

          Peter Marcoen added a comment - I agree with Michael and Maxfield. It feels like I'm taking a step back when using Pipeline. It used to be as simple as providing the emailaddress to send a mail to when the build failed. Now I have to start coding it in with try-catches. I too would prefer a onFailure DSL to avoid all that complexity.

          It might reduce the volume of code if you push everything down, and try-catch only once at the top:

          main()
          def main() {
              try {
                  core()
              } catch (Exception e) {
                  mail to: 'dest@domain', subject: "Failure of Jenkins", body: e.getMessage()+"\nTry harder the next time."
                  error(e.getMessage())
              }
          }
          
          def core() {
              node {
                  sh "exit 1"
              }
          }
          

          Hope this helps.

          Martin d'Anjou added a comment - It might reduce the volume of code if you push everything down, and try-catch only once at the top: main() def main() { try { core() } catch (Exception e) { mail to: 'dest@domain' , subject: "Failure of Jenkins" , body: e.getMessage()+ "\nTry harder the next time." error(e.getMessage()) } } def core() { node { sh "exit 1" } } Hope this helps.

          Jesse Glick added a comment -

          inside that global method I lose access to global variables, like JOB_NAME

          Not true, these are still accessible.

          Jesse Glick added a comment - inside that global method I lose access to global variables, like JOB_NAME Not true, these are still accessible.

          Jesse Glick added a comment -

          Should rather return a Serializable struct with @Whitelisted properties that can be used to customize error handling:

          • original exception (e.g., for calling .message)
          • full stack trace of exception (as a convenience)
          • URL of LogAction
          • tail of log file leading up to error
          • label associated with failing step (using FlowNodeSerialWalker from JENKINS-26132, and especially useful in conjunction with JENKINS-26107)

          Jesse Glick added a comment - Should rather return a Serializable struct with @Whitelisted properties that can be used to customize error handling: original exception (e.g., for calling .message ) full stack trace of exception (as a convenience) URL of LogAction tail of log file leading up to error label associated with failing step (using FlowNodeSerialWalker from JENKINS-26132 , and especially useful in conjunction with JENKINS-26107 )

          Jesse Glick added a comment -

          As per JENKINS-32059, we lack API-level metadata about source line location.

          Jesse Glick added a comment - As per JENKINS-32059 , we lack API-level metadata about source line location.

          Leah Klearman added a comment -

          I'm interested in ensuring that the solution works with a parallel() that has a large number of sub-jobs...that all of the jobs get completed and multiple failures can be identified.

          Leah Klearman added a comment - I'm interested in ensuring that the solution works with a parallel() that has a large number of sub-jobs...that all of the jobs get completed and multiple failures can be identified.

          James Dumay added a comment -

          jglick is this this still relevant with the advent of Blue Ocean?

          James Dumay added a comment - jglick is this this still relevant with the advent of Blue Ocean?

          Viacheslav Dubrovskyi added a comment - - edited

          My workaround for this.

          // Add specific string used for detect id of log. Should be uniq for every step.
          sh 'echo "Run SPECIFIC_TOKEN"'
          
          // At the end detect log id and generate URL to step
          exec = """ set +x; echo "${BUILD_URL}execution/node/\$(grep -l "Run SPECIFIC_TOKEN" "$JENKINS_HOME/jobs/\$(echo "$JOB_NAME" | sed 's|/|/branches/|g')/builds/$BUILD_ID/"*.log 2>/dev/null | head -n1 | xargs basename | sed 's/\\.log//')/log/" """
          stepURL=sh ( script: exec, returnStdout: true).trim()
          

          It's ugly, but works in my case.

          Viacheslav Dubrovskyi added a comment - - edited My workaround for this. // Add specific string used for detect id of log. Should be uniq for every step. sh 'echo "Run SPECIFIC_TOKEN" ' // At the end detect log id and generate URL to step exec = """ set +x; echo " ${BUILD_URL}execution/node/\$(grep -l "Run SPECIFIC_TOKEN" "$JENKINS_HOME/jobs/\$(echo " $JOB_NAME " | sed 's|/|/branches/|g' )/builds/$BUILD_ID/" *.log 2>/dev/ null | head -n1 | xargs basename | sed 's/\\.log //' )/log/ " " "" stepURL=sh ( script: exec, returnStdout: true ).trim() It's ugly, but works in my case.

          Sorin Sbarnea added a comment -

          Is ugly and would break in too many possible ways. We need a generic solution that we can use even when Blue Ocean is not enabled. 

          We need a link that points to the first error of the current build. This looks like something where we need to use HTML bookmarks (url#bookmark) to achieve it in a reliable way. At this this approach should downgrade gracefully.  

          Sorin Sbarnea added a comment - Is ugly and would break in too many possible ways. We need a generic solution that we can use even when Blue Ocean is not enabled.  We need a link that points to the first error of the current build. This looks like something where we need to use HTML bookmarks (url#bookmark) to achieve it in a reliable way. At this this approach should downgrade gracefully.  

          Jesse Glick added a comment -

          jamesdumay yes. Could be integrated with display-url-provider but otherwise unaffected.

          Jesse Glick added a comment - jamesdumay yes. Could be integrated with display-url-provider but otherwise unaffected.

          Hi. Is this still being worked on?

          Thanks

          Juan Pablo Bottinelli added a comment - Hi. Is this still being worked on? Thanks

          You can use the rest api that comes with the stage view plugin:

          https://github.com/jenkinsci/pipeline-stage-view-plugin/tree/master/rest-api

           

          to obtain a stage-seperated log

          roel postelmans added a comment - You can use the rest api that comes with the stage view plugin: https://github.com/jenkinsci/pipeline-stage-view-plugin/tree/master/rest-api   to obtain a stage-seperated log

          I'll take a look at that. Thanks roel0

          Juan Pablo Bottinelli added a comment - I'll take a look at that. Thanks roel0

          Hans Ecke added a comment -

          FWIW, I'm looking at the exact same usecase. Currently I email currentBuild.rawBuild.getLog(1000) to the stakeholders of the run, but it contains much unrelated chaff.

          Hans Ecke added a comment - FWIW, I'm looking at the exact same usecase. Currently I email  currentBuild.rawBuild.getLog(1000) to the stakeholders of the run, but it contains much unrelated chaff.

          Craig Ringer added a comment -

          This becomes even more relevant when working with Blue Ocean etc. The URLs are something like `jobname/6/pipeline/79` where the /79 is a node in the graph of steps and parallel tasks. It doesn't seem to be predictable, so it's not clear how you can generate a URL that points to exactly one parallel step, for example.

          Craig Ringer added a comment - This becomes even more relevant when working with Blue Ocean etc. The URLs are something like `jobname/6/pipeline/79` where the /79 is a node in the graph of steps and parallel tasks. It doesn't seem to be predictable, so it's not clear how you can generate a URL that points to exactly one parallel step, for example.

          hardi249 added a comment -

          Is this still in progress?

          hardi249 added a comment - Is this still in progress?

          Jesse Glick added a comment -

          Not really. I suppose I could revisit this, given the high vote count.

          Jesse Glick added a comment - Not really. I suppose I could revisit this, given the high vote count.

          David Riemens added a comment -

          just up-voted;
          Me too, I have similar usecase. In our testenvironment, we run many tools, each generating a separate logfile. We have one generic log shown in the console.
          If one test fails, we can see that it failed, and typically have an exception message shown in the console, but the actual (detailed) reason is hidden in one of
          the  detailed logs. For that reason we want to include a link to the workspace directory on the exception text, such that all the log-files are just one click away.
          For the pipeline jobs that link is not easy to derive; it is hidden in one of the pipeline steps. as also indicated by ringerc
          My feeling says that making sure that link, or the ID is available at runtime should be possible ... right ?

          David Riemens added a comment - just up-voted; Me too, I have similar usecase. In our testenvironment, we run many tools, each generating a separate logfile. We have one generic log shown in the console. If one test fails, we can see that it failed, and typically have an exception message shown in the console, but the actual (detailed) reason is hidden in one of the  detailed logs. For that reason we want to include a link to the workspace directory on the exception text, such that all the log-files are just one click away. For the pipeline jobs that link is not easy to derive; it is hidden in one of the pipeline steps. as also indicated by ringerc My feeling says that making sure that link, or the ID is available at runtime should be possible ... right ?

          Jan Heylen added a comment - - edited

          Is there already any way to get the link to 'blue/rest/organizations/jenkins/pipelines/<jobname>/runs/<build-id>/nodes/<PipelineNodeImpl-id>/log/ from within a pipeline parallel node?

          Jan Heylen added a comment - - edited Is there already any way to get the link to 'blue/rest/organizations/jenkins/pipelines/<jobname>/runs/<build-id>/nodes/<PipelineNodeImpl-id>/log/ from within a pipeline parallel node?

          Erik van Velzen added a comment - - edited

          Gonna be  harsh here, but rightfully so. I feel burned, I worked many days to set up docker containers, scripts and even fixing and compiling plugins, and I now find out that it's for naught.

          "run a command and produce a URL to the output" is basic functionality of a CI tool.

          There's no point in using Jenkins without it (for me).

          Erik van Velzen added a comment - - edited Gonna be  harsh here, but rightfully so. I feel burned, I worked many days to set up docker containers, scripts and even fixing and compiling plugins, and I now find out that it's for naught. "run a command and produce a URL to the output" is basic functionality of a CI tool. There's no point in using Jenkins without it (for me).

          Perhaps a workaround would be to pipe the output within the step to a file and publish it as an artifact.

          Erik van Velzen added a comment - Perhaps a workaround would be to pipe the output within the step to a file and publish it as an artifact.

          thang bui added a comment - - edited

          erikvv if you are using blue ocean, you can just have the link to the build and once the page open it will automatically scroll to the failed step.

          also another work around https://stackoverflow.com/questions/53444196/get-log-for-each-jenkins-pipeline-stage 

          thang bui added a comment - - edited erikvv if you are using blue ocean, you can just have the link to the build and once the page open it will automatically scroll to the failed step. also another work around  https://stackoverflow.com/questions/53444196/get-log-for-each-jenkins-pipeline-stage  

          Edgars Batna added a comment -

          +1 The advent of Blue Ocean came and went. Jenkins is still a powerful tool, but I feel weird seeing many functional improvements get so stale.

          Edgars Batna added a comment - +1 The advent of Blue Ocean came and went. Jenkins is still a powerful tool, but I feel weird seeing many functional improvements get so stale.

          Helder Magalhães added a comment - - edited

          Late in the game, but this is still not straightforward as it could be.

          Is there already any way to get the link to 'blue/rest/organizations/jenkins/pipelines/<jobname>/runs/<build-id>/nodes/<PipelineNodeImpl-id>/log/ from within a pipeline parallel node?

          Apparently it's possible but, unfortunately, not out-of-the-box:

          Seems that getting the link (out-of-the-box) is now closer with the RUN_DISPLAY_URL environment variable injected by the BlueOcean plugin but it would be very nice to have an environment variable set to the step ID available throughout the whole job (possibly as part of the pipeline plug-in?). Not only for linking but also for obtaining a unique identifier which maps to something and can be used for (temporary?) storage path, artifact filenames, for better diagnostic output, etc.

          Edit: correct link for "building a link"; added some arguments.

          Helder Magalhães added a comment - - edited Late in the game, but this is still not straightforward as it could be. Is there already any way to get the link to 'blue/rest/organizations/jenkins/pipelines/<jobname>/runs/<build-id>/nodes/<PipelineNodeImpl-id>/log/ from within a pipeline parallel node? Apparently it's possible but, unfortunately, not out-of-the-box: For getting the Pipeline implementation node ID, take a look at Unexpected exception when use getContext and sh together in the latest version of Jenkins . The example even works from non-library code! For building a link , check out Jenkins: Generating Blue Ocean URLs . The example even offers to choose between legacy or BlueOcean! Seems that getting the link (out-of-the-box) is now closer with the RUN_DISPLAY_URL environment variable injected by the BlueOcean plugin but it would be very nice to have an environment variable set to the step ID available throughout the whole job (possibly as part of the pipeline plug-in?). Not only for linking but also for obtaining a unique identifier which maps to something and can be used for (temporary?) storage path, artifact filenames, for better diagnostic output, etc. Edit : correct link for "building a link"; added some arguments.

          Denis added a comment - - edited

          +1 for this. 

          Currently we have to perform some tricks to print URL to the necessary BO pipeline node from the groovy job itself.

          First, RUN_DISPLAY_URL is not convenient if you want to add smth like "/pipeline/<node_id>" to it. The thing is that this var just adds /display/redirect to the classic URL, so we get smth like https://<jenkins_host>/<job_name>/<build_id>/display/redirect which is then redirected to  https://<jenkins_host>/blue/organizations/jenkins/<job_name>/<build_id>/pipeline

          So we first need to now the final URL (after redirections) - one can do this for example using [https://gist.github.com/sbglasius/3899754|this snippet]

          Next, we should find necessary node id for the current stage. This step looks ugly, we  just walk through the flow graph looking for a node with a needed name. It works for our pipelines consisting of many parallel jobs, suggestions are welcome for better and more universal code:

          Integer getFlowID() {
              FlowGraphWalker walker = new FlowGraphWalker(currentBuild.rawBuild.getExecution())
              for (FlowNode flowNode: walker) {
                  if (flowNode.getDisplayName() == "Branch: " + env.STAGE_NAME) {
                      return flowNode.getId()
                          }
                  }
              return 0
          }

           

          Definitely having a single variable for this would be a great solution.

          Denis added a comment - - edited +1 for this.  Currently we have to perform some tricks to print URL to the necessary BO pipeline node from the groovy job itself. First, RUN_DISPLAY_URL is not convenient if you want to add smth like "/pipeline/<node_id>" to it. The thing is that this var just adds /display/redirect to the classic URL, so we get smth like https://<jenkins_host>/<job_name>/<build_id>/display/redirect  which is then redirected to  https://<jenkins_host>/blue/organizations/jenkins/<job_name>/<build_id>/pipeline So we first need to now the final URL (after redirections) - one can do this for example using [https://gist.github.com/sbglasius/3899754|this snippet] Next, we should find necessary node id for the current stage. This step looks ugly, we  just walk through the flow graph looking for a node with a needed name. It works for our pipelines consisting of many parallel jobs, suggestions are welcome for better and more universal code: Integer getFlowID() {     FlowGraphWalker walker = new FlowGraphWalker(currentBuild.rawBuild.getExecution())     for (FlowNode flowNode: walker) {         if (flowNode.getDisplayName() == "Branch: " + env.STAGE_NAME) {             return flowNode.getId()                 }         }     return 0 }   Definitely having a single variable for this would be a great solution.

            jglick Jesse Glick
            jglick Jesse Glick
            Votes:
            50 Vote for this issue
            Watchers:
            67 Start watching this issue

              Created:
              Updated: