OTel Instrumentation Improvement: Add github.run_attempt to resource attributes
Analysis Date: 2026-05-06
Priority: Medium
Effort: Small (< 2h)
Problem
github.run_attempt is absent from the OTLP resource attributes emitted by all gh-aw spans. It exists only as a span-level attribute (gh-aw.run.attempt) but is never promoted to the resource block via buildGitHubActionsResourceAttributes in send_otlp_span.cjs (line 300).
Because github.run_id is constant across all retry attempts of the same workflow run, a DevOps engineer watching retried workflows in Grafana Tempo cannot answer: "Which attempt is this trace from, and how does its outcome compare to the previous attempt?" Filtering or grouping by attempt number at the resource level is not possible — you must parse each span individually and look for gh-aw.run.attempt.
Why This Matters (DevOps Perspective)
GitHub Actions workflows are frequently re-run on transient failures. When a workflow is re-run:
- All attempts share the same
github.run_id
- Only
github.run_attempt distinguishes attempt 1 from attempt 2 or 3
Without github.run_attempt in the resource attributes, backends like Grafana Tempo, Datadog, and Honeycomb cannot group traces by retry attempt at the resource level. This means:
- No retry-rate dashboards: You can't build a panel counting "runs that required > 1 attempt" without a per-span scan
- Confusing trace search: Two attempts of the same run appear identical when filtering by
github.run_id, with no resource-level differentiator
- Slower MTTR: An on-call engineer looking at a retried failure can't immediately confirm whether the trace is from the first or second attempt without inspecting individual span attributes
Adding github.run_attempt to the resource block (the standard home for static execution context) puts it alongside github.run_id, making the (run_id, run_attempt) pair — the canonical unique key for a workflow execution — fully present at the resource level.
Current Behavior
buildGitHubActionsResourceAttributes in send_otlp_span.cjs accepts runId but not runAttempt:
// Current: actions/setup/js/send_otlp_span.cjs (lines 300–325)
function buildGitHubActionsResourceAttributes({
repository, runId, eventName = "", ref = "", refName = "",
headRef = "", sha = "", workflowRef = "", staged
}) {
const resourceAttributes = [
buildAttr("github.repository", repository),
buildAttr("github.run_id", runId),
// ... github.event_name, github.ref, github.ref_name, etc.
// github.run_attempt is never added here
];
resourceAttributes.push(buildAttr("deployment.environment", staged ? "staging" : "production"));
return resourceAttributes;
}
runAttempt is read by both callers (sendJobSetupSpan line 860, sendJobConclusionSpan line 1091) and correctly emitted as the span attribute gh-aw.run.attempt, but is not passed to buildGitHubActionsResourceAttributes at line 909 or line 1209.
Proposed Change
Three surgical edits to actions/setup/js/send_otlp_span.cjs:
// 1. Add runAttempt parameter to buildGitHubActionsResourceAttributes (line 300)
function buildGitHubActionsResourceAttributes({
repository, runId, runAttempt = "", eventName = "", ref = "", refName = "",
headRef = "", sha = "", workflowRef = "", staged
}) {
const resourceAttributes = [
buildAttr("github.repository", repository),
buildAttr("github.run_id", runId),
];
if (runAttempt) {
resourceAttributes.push(buildAttr("github.run_attempt", runAttempt));
}
// ... rest of function unchanged
// 2. Pass runAttempt in sendJobSetupSpan (line 909)
const resourceAttributes = buildGitHubActionsResourceAttributes({
repository, runId, runAttempt, eventName, ref, refName, headRef, sha, workflowRef, staged
});
// 3. Pass runAttempt in sendJobConclusionSpan (line 1209)
const resourceAttributes = buildGitHubActionsResourceAttributes({
repository, runId, runAttempt, eventName, ref, refName, headRef, sha, workflowRef, staged
});
Expected Outcome
After this change:
- In Grafana Tempo / Honeycomb / Datadog: Resource-level filtering by
github.run_attempt becomes available. You can build dashboards grouping traces by attempt number, identify workflows that needed retries, and compare error rates between first and subsequent attempts.
- In the JSONL mirror: The resource block will include
{"key":"github.run_attempt","value":{"stringValue":"1"}} for every span, making offline debugging artifacts self-describing.
- For on-call engineers: Opening a trace in Tempo immediately shows whether you're looking at attempt 1 or a retry attempt — no need to expand individual spans to find
gh-aw.run.attempt.
Implementation Steps
Evidence from Live Grafana Data
Sampled from the local OTLP JSONL mirror for workflow run §25418210458:
trace_id: 631a342fdd95f531a96ead6d14b185b6
span_name: gh-aw.agent.setup
Resource attributes actually present (11 attributes):
service.name, service.version, github.repository, github.run_id,
github.actions.run_url, github.event_name, github.ref, github.ref_name,
github.sha, github.workflow_ref, deployment.environment
github.run_attempt → ABSENT from resource
Span attributes (12 attributes) include gh-aw.run.attempt: "1" — confirming the value is available but only emitted at the span level, not promoted to the resource block.
Attribute checklist against resource block:
| Attribute |
Present |
service.version |
✅ 2.1.126 |
github.repository |
✅ github/gh-aw |
github.event_name |
✅ schedule |
github.run_id |
✅ 25418210458 |
deployment.environment |
✅ production |
github.run_attempt |
❌ missing |
Related Files
actions/setup/js/send_otlp_span.cjs — buildGitHubActionsResourceAttributes (line 300), sendJobSetupSpan (line 909), sendJobConclusionSpan (line 1209)
actions/setup/js/action_otlp.test.cjs — resource attribute assertions to update
Generated by the Daily Grafana OTel Instrumentation Advisor workflow
Generated by Daily Grafana OTel Instrumentation Advisor · ● 309.3K · ◷
OTel Instrumentation Improvement: Add
github.run_attemptto resource attributesAnalysis Date: 2026-05-06
Priority: Medium
Effort: Small (< 2h)
Problem
github.run_attemptis absent from the OTLP resource attributes emitted by allgh-awspans. It exists only as a span-level attribute (gh-aw.run.attempt) but is never promoted to the resource block viabuildGitHubActionsResourceAttributesinsend_otlp_span.cjs(line 300).Because
github.run_idis constant across all retry attempts of the same workflow run, a DevOps engineer watching retried workflows in Grafana Tempo cannot answer: "Which attempt is this trace from, and how does its outcome compare to the previous attempt?" Filtering or grouping by attempt number at the resource level is not possible — you must parse each span individually and look forgh-aw.run.attempt.Why This Matters (DevOps Perspective)
GitHub Actions workflows are frequently re-run on transient failures. When a workflow is re-run:
github.run_idgithub.run_attemptdistinguishes attempt 1 from attempt 2 or 3Without
github.run_attemptin the resource attributes, backends like Grafana Tempo, Datadog, and Honeycomb cannot group traces by retry attempt at the resource level. This means:github.run_id, with no resource-level differentiatorAdding
github.run_attemptto the resource block (the standard home for static execution context) puts it alongsidegithub.run_id, making the(run_id, run_attempt)pair — the canonical unique key for a workflow execution — fully present at the resource level.Current Behavior
buildGitHubActionsResourceAttributesinsend_otlp_span.cjsacceptsrunIdbut notrunAttempt:runAttemptis read by both callers (sendJobSetupSpanline 860,sendJobConclusionSpanline 1091) and correctly emitted as the span attributegh-aw.run.attempt, but is not passed tobuildGitHubActionsResourceAttributesat line 909 or line 1209.Proposed Change
Three surgical edits to
actions/setup/js/send_otlp_span.cjs:Expected Outcome
After this change:
github.run_attemptbecomes available. You can build dashboards grouping traces by attempt number, identify workflows that needed retries, and compare error rates between first and subsequent attempts.{"key":"github.run_attempt","value":{"stringValue":"1"}}for every span, making offline debugging artifacts self-describing.gh-aw.run.attempt.Implementation Steps
runAttempt = ""to thebuildGitHubActionsResourceAttributesdestructured parameter listif (runAttempt) { resourceAttributes.push(buildAttr("github.run_attempt", runAttempt)); }after thegithub.run_identryrunAttemptin thebuildGitHubActionsResourceAttributescall insidesendJobSetupSpan(~line 909)runAttemptin thebuildGitHubActionsResourceAttributescall insidesendJobConclusionSpan(~line 1209)actions/setup/js/action_otlp.test.cjsto assertgithub.run_attemptis present in resource attributescd actions/setup/js && npx vitest runto confirm tests passmake fmtto ensure formattingEvidence from Live Grafana Data
Sampled from the local OTLP JSONL mirror for workflow run §25418210458:
Resource attributes actually present (11 attributes):
github.run_attempt→ ABSENT from resourceSpan attributes (12 attributes) include
gh-aw.run.attempt: "1"— confirming the value is available but only emitted at the span level, not promoted to the resource block.Attribute checklist against resource block:
service.version2.1.126github.repositorygithub/gh-awgithub.event_nameschedulegithub.run_id25418210458deployment.environmentproductiongithub.run_attemptRelated Files
actions/setup/js/send_otlp_span.cjs—buildGitHubActionsResourceAttributes(line 300),sendJobSetupSpan(line 909),sendJobConclusionSpan(line 1209)actions/setup/js/action_otlp.test.cjs— resource attribute assertions to updateGenerated by the Daily Grafana OTel Instrumentation Advisor workflow