How do I analyse a HAR file for Blue Ocean?

Issue

  • When analyse errors in Blue Ocean one important part is the HAR file that the
    customer can provide. This file is so important since it will show the communication
    between the front end and the REST API (including the REST response)
  • Another important part to truly debug Blue Ocean is the console OUTPUT from the customer after activating
    Blue Ocean logging on the client site.

Environment

  • CloudBees Jenkins Enterprise 
  • Jenkins
  • Jenkins LTS

Resolution

We assume you are familiar with generating a HAR file, if not have a look at
Generating a HAR file for troubleshooting

Having created the HAR you can then import it in e.g “HTTP Archive Viewer”.

Step by step

First import the HAR file.

![import](./How_do_I_analyse_a_HAR_file_for_Blue Ocean/1.png)
![import](./How_do_I_analyse_a_HAR_file_for_Blue Ocean/2.png)

Then you can review the different resources that had been requested.

![import](./How_do_I_analyse_a_HAR_file_for_Blue Ocean/3.png)

Finding problems

Normally the first thing is to determine what the exact problem is. For this, you first look in the HAR file and look for responses that have status code >400.
Those statuses indicate problems with the backend and require further investigating in the backend. In case there are no such errors, you would need to debug the response in more detail.

Debug problems

Depending on the problem you see you will need to look in the different rest answer. For example if you are debugging the detail view of a pipeline,
you most likely want to look for http://example.com:8080/jenkins/blue/rest/organizations/jenkins/pipelines/${pipelineName}/branches/${branchName}/runs/${id}/nodes/
to examine the different nodes of the run.

You can now use the response data and create a new “ide-scripting” console script. Since the response of the server has to be a valid json object you
can simply create a variable like the following:

const nodes = [{
    "_class": "io.jenkins.Blue Ocean.rest.impl.pipeline.PipelineNodeImpl",
    "_links": {
        "self": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/5/"
        },
        "actions": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/5/actions/"
        },
        "steps": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/5/steps/"
        }
    },
    "actions": [],
    "displayName": "hey",
    "durationInMillis": 7559,
    "id": "5",
    "input": null,
    "result": "SUCCESS",
    "startTime": "2017-03-24T20:48:21.435+0100",
    "state": "FINISHED",
    "causeOfBlockage": null,
    "edges": [{"_class": "io.jenkins.Blue Ocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl", "id": "7"}]
}, {
    "_class": "io.jenkins.Blue Ocean.rest.impl.pipeline.PipelineNodeImpl",
    "_links": {
        "self": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/7/"
        },
        "actions": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/7/actions/"
        },
        "steps": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/7/steps/"
        }
    },
    "actions": [],
    "displayName": "parallel",
    "durationInMillis": 17974,
    "id": "7",
    "input": null,
    "result": "SUCCESS",
    "startTime": "2017-03-24T20:48:29.006+0100",
    "state": "FINISHED",
    "causeOfBlockage": null,
    "edges": [{
        "_class": "io.jenkins.Blue Ocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
        "id": "10"
    }, {"_class": "io.jenkins.Blue Ocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl", "id": "11"}]
}, {
    "_class": "io.jenkins.Blue Ocean.rest.impl.pipeline.PipelineNodeImpl",
    "_links": {
        "self": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/10/"
        },
        "actions": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/10/actions/"
        },
        "steps": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/10/steps/"
        }
    },
    "actions": [],
    "displayName": "firstBranch",
    "durationInMillis": 17973,
    "id": "10",
    "input": null,
    "result": "SUCCESS",
    "startTime": "2017-03-24T20:48:29.007+0100",
    "state": "FINISHED",
    "causeOfBlockage": null,
    "edges": [{"_class": "io.jenkins.Blue Ocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl", "id": "21"}]
}, {
    "_class": "io.jenkins.Blue Ocean.rest.impl.pipeline.PipelineNodeImpl",
    "_links": {
        "self": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/11/"
        },
        "actions": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/11/actions/"
        },
        "steps": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/11/steps/"
        }
    },
    "actions": [],
    "displayName": "secondBranch",
    "durationInMillis": 17972,
    "id": "11",
    "input": null,
    "result": "SUCCESS",
    "startTime": "2017-03-24T20:48:29.008+0100",
    "state": "FINISHED",
    "causeOfBlockage": null,
    "edges": [{"_class": "io.jenkins.Blue Ocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl", "id": "21"}]
}, {
    "_class": "io.jenkins.Blue Ocean.rest.impl.pipeline.PipelineNodeImpl",
    "_links": {
        "self": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/21/"
        },
        "actions": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/21/actions/"
        },
        "steps": {
            "_class": "io.jenkins.Blue Ocean.rest.hal.Link",
            "href": "/blue/rest/organizations/jenkins/pipelines/scherler/branches/karaoke-parallel/runs/59/nodes/21/steps/"
        }
    },
    "actions": [],
    "displayName": "ho",
    "durationInMillis": 9413,
    "id": "21",
    "input": null,
    "result": "SUCCESS",
    "startTime": "2017-03-24T20:48:46.993+0100",
    "state": "FINISHED",
    "causeOfBlockage": null,
    "edges": []
}];

You may have to “clean” the response since it may be formatted as JSON Object. I am using the regexp “\s*\n\s*” to remove all unneeded
line breaks and whitespace characters, so I get one big line. You can use your IDE to format the code again.

In case you want to reduce the information of the nodes to their id and their edges, you can do the following:

const cleaned = nodes.map((item) => {return {id: item.id, edges: item.edges}});
console.log(cleaned);
// outputs 
[ { id: '5', edges: [ [Object] ] },
  { id: '7', edges: [ [Object], [Object] ] },
  { id: '10', edges: [ [Object] ] },
  { id: '11', edges: [ [Object] ] },
  { id: '21', edges: [] } ]

Or if you want to filter the above for a certain state and a specific id you can do e.g.

const cleaned = nodes
        .filter((item) => item.state === "FINISHED" && item.id==="21")
        .map((item) => {return {id: item.id, edges: item.edges}})
;
[ { id: '21', edges: [] } ]

You get the idea to validate/debug the data via scripting, however this
is only really useful if you exactly know what you are looking
for.

To find out Blue Ocean offers some useful tools for power user which can help
to find out what is going wrong/on.

Console debugging

You may have noticed that when you open the console in chrome that there is a teaser message like
Browser configuration of @jenkins-cd/logging is explained at https://tfennelly.github.io/jenkins-js-logging/index.html#browser-config
we highly recommend that link as reference on how you can further debug the app. With the logging Blue Ocean added some basic information that
can help to track down the problem.

You can either use the Chrome Extension plugin or directly the localStorage
to change the log levels.

![import](./How_do_I_analyse_a_HAR_file_for_Blue Ocean/4.png)

After you refresh you will see much more information in the console.

![import](./How_do_I_analyse_a_HAR_file_for_Blue Ocean/5.png)

Preferences for debugging

Blue Ocean will (not yet merged to master) support setting of preferences in the localStorage of the browser. We are applying the
same principals as we did with logging earlier. The user can configure different parts of the applications by setting
preferences.

![import](./How_do_I_analyse_a_HAR_file_for_Blue Ocean/chrome-config.png)

Especially the runDetails.pipeline.updateOnFinish preference should come in handy if set to never. This will allow
to stop “karaoke mode” (following a live build) and prevent that the
run will be refreshed. Which then allows to analyse the state on which it was
stopped much easier.

Have more questions? Submit a request

0 Comments

Please sign in to leave a comment.