Source code links for stack frames

Embed
Preview of the card
<a href="https://watchtowerops.net/docs/source-code-links"><img src="https://watchtowerops.net/docs/_api/public/orgs/aa5959cb-1a0b-4a9a-bc9a-913e7ac31cd9/spaces/b7aac181-9916-4805-b253-becc5fd2ca62/pages/89a8c14a-8969-407c-980d-faa802e9ff03/social-card.svg?v=3e7ae33eec8b" alt="Source code links for stack frames" width="600" height="315"></a>

In-app frames of backend and browser events link to the exact line in the repository at the commit that ran, and can show the source around it, for GitHub, GitLab, Bitbucket and Azure Repos.

The repository

In order, the first that exists:

  1. The service's repository link: Settings, "Source code links", or PUT /v1/projects/{p}/repo-links/{service} with {provider: github|gitlab|bitbucket|azurerepos, base_url, path_rules?, strip_prefix?} (DELETE removes it; manage_project).

  2. The catalog repo_url of the service, when it is on github.com, gitlab.com, bitbucket.org, dev.azure.com or *.visualstudio.com.

  3. The event's vcs.repository.url.full (OTel resource attribute; the worker copies vcs.* resource attributes onto error events), same hosts.

The commit

The event's vcs.ref.head.revision (or vcs.repository.ref.revision, git.commit.sha), else the newest commit of the event's release (release commits from wtctl, the deploy script or the SCM fill), else the release's ref when it is a commit sha, else the release version itself when it is a sha. Set OTEL_RESOURCE_ATTRIBUTES=vcs.ref.head.revision=$GIT_SHA at build time to get exact links without any release setup.

Paths

A frame path is mapped to a repository path by, in order: the link's path_rules ([{from: "file:///app/", to: ""}, {from: "/srv/build/", to: "services/api"}], first match wins, at most 20), its strip_prefix, then the common container roots /usr/src/app/, /usr/src/, /app/, /var/task/, /workspace/, /opt/app/, /srv/app/, /home/app/, /code/. A file:// scheme is ignored. A path with .., a backslash or a URL gets no link. Each mapped frame carries repo_path.

  • Issues: source_url on each in-app frame of latest-event and event pages; "Show source" reads the lines around the frame (GET /v1/projects/{p}/source/snippet?service&file&line&version&ref&context, default 5 lines either side, at most 25) and "Blame" the last change (/source/blame). Both read through the org's connected SCM installation (GitHub App, GitLab, Bitbucket, Azure Repos token) and need run_investigation; without one the snippet is 404.

  • Traces: the span's code.filepath/code.lineno link through GET /v1/projects/{p}/code-links (with ref from the span's vcs.ref.head.revision).

  • Profiles: the selected frame links the same way; "Show source" opens the whole file (/profiles/source, which now also returns source_url).

Blob URLs: GitHub blob/{sha}/{path}#L{n}, GitLab -/blob/{sha}/{path}#L{n}, Bitbucket src/{sha}/{path}#lines-{n}, Azure Repos ?path=/{path}&version=GC{sha}&line={n}.

Suspect commits from git blame

The issue page asks POST /v1/projects/{p}/issues/{id}/suspects/blame (needs run_investigation). It blames the 3 innermost in-app frames of the latest event at the event's commit (vcs.ref.head.revision, git.commit.sha), else the release's newest commit. GitHub counts the lines the commit last changed within 5 lines of the frame line; GitLab blames the one line; Bitbucket and Azure Repos have no blame API, so the newest commit of the file stands in (blame_frame_file, half weight). Score per commit = sum of lines / frame depth, divided by 1 + age_days / 30; the 5 best are kept with the commit page and the pull or merge requests that contain the commit.

The result is cached per issue and release (issue_blame_suspects); without a repository link nothing is cached. GET /v1/projects/{p}/issues/{id}/suspects lists the release-commit suspects first, then the newest cached blame suspects (author, commit_url, pull_urls), without repeating a sha. Author and summary are repository text and shown as data. A suspect is evidence, not a finding that the commit caused the error.

Updated