Skip to content

[otel-advisor] add github.workflow_ref resource attribute to all OTel spans #28354

@github-actions

Description

@github-actions

📡 OTel Instrumentation Improvement: add github.workflow_ref resource attribute to all OTel spans

Analysis Date: 2026-04-24
Priority: High
Effort: Small (< 2h)

Problem

Every OTel span emitted by send_otlp_span.cjs is missing the github.workflow_ref resource attribute. This attribute would contain the full workflow file path including the git ref — e.g. github/gh-aw/.github/workflows/otel-advisor.yml@refs/heads/main.

Without it, a DevOps engineer cannot answer the question "which workflow YAML file produced this span?" using an OTel backend query alone. A repository with multiple compiled gh-aw workflows (e.g. pr-labeler, issue-triage, daily-report) produces spans that all share service.name = "gh-aw" and can only be distinguished by the non-standard span attribute gh-aw.workflow.name — which backends don't index as a first-class dimension.

The value IS already read from the environment: aw_context.cjs:142 captures process.env.GITHUB_WORKFLOW_REF as workflow_id for workflow dispatch propagation. It just never makes it into the spans.

Why This Matters (DevOps Perspective)

The standard github.* resource attribute set on every span (github.repository, github.run_id, github.ref, github.sha, github.event_name) is rich enough to correlate a span to a specific commit and branch — but not to a specific workflow file. For any multi-workflow repository, dashboard queries like "alert me when the production-deploy workflow fails" require this field.

GITHUB_WORKFLOW_REF includes the branch ref (@refs/heads/main), which means it also distinguishes "this workflow from main" from "this workflow from a feature branch". That distinction is critical for:

  • Scoping production-only alerts (filter github.workflow_ref ends with @refs/heads/main)
  • Attributing cost / token spend to individual workflow files
  • Root-causing regressions introduced by workflow YAML changes across branches

Without this attribute, operators must fall back to parsing the non-standard gh-aw.workflow.name span attribute, which only contains the markdown-defined friendly name and is not indexed as a standard GitHub dimension in Grafana/Honeycomb/Datadog.

Current Behavior

Neither sendJobSetupSpan nor sendJobConclusionSpan includes github.workflow_ref in resource attributes.

// Current: actions/setup/js/send_otlp_span.cjs  (lines 516–536, setup span)
const resourceAttributes = [buildAttr("github.repository", repository), buildAttr("github.run_id", runId)];
if (repository && runId) {
  const [owner, repo] = repository.split("/");
  resourceAttributes.push(buildAttr("github.actions.run_url", buildWorkflowRunUrl({ runId }, { owner, repo })));
}
if (eventName) {
  resourceAttributes.push(buildAttr("github.event_name", eventName));
}
if (ref) {
  resourceAttributes.push(buildAttr("github.ref", ref));
}
if (refName) {
  resourceAttributes.push(buildAttr("github.ref_name", refName));
}
if (headRef) {
  resourceAttributes.push(buildAttr("github.head_ref", headRef));
}
if (sha) {
  resourceAttributes.push(buildAttr("github.sha", sha));
}
resourceAttributes.push(buildAttr("deployment.environment", staged ? "staging" : "production"));
// ❌ github.workflow_ref is never set

The env var is already read elsewhere in the codebase — aw_context.cjs:142 does:

// aw_context.cjs:140–142
// GITHUB_WORKFLOW_REF provides the full workflow file path including the ref,
// e.g. "owner/repo/.github/workflows/dispatcher.yml@refs/heads/main"
workflow_id: process.env.GITHUB_WORKFLOW_REF ?? "",

So the value is available at the same point in the process — it is simply never forwarded into the span.

Proposed Change

In sendJobSetupSpan (around line 493), read the env var:

// actions/setup/js/send_otlp_span.cjs — sendJobSetupSpan
const workflowRef = process.env.GITHUB_WORKFLOW_REF || "";

Then add it to resourceAttributes (after the existing sha block, before deployment.environment):

if (workflowRef) {
  resourceAttributes.push(buildAttr("github.workflow_ref", workflowRef));
}

In sendJobConclusionSpan (around line 704), read with aw_info fallback:

// actions/setup/js/send_otlp_span.cjs — sendJobConclusionSpan
const workflowRef = process.env.GITHUB_WORKFLOW_REF || (typeof awInfo.context?.workflow_id === "string" ? awInfo.context.workflow_id : "");

Then add to resourceAttributes (same position, before deployment.environment):

if (workflowRef) {
  resourceAttributes.push(buildAttr("github.workflow_ref", workflowRef));
}

The fallback to awInfo.context?.workflow_id ensures conclusion spans for dispatched child workflows still carry the caller's workflow ref when GITHUB_WORKFLOW_REF is not in the environment.

Expected Outcome

After this change:

  • In Grafana / Honeycomb / Datadog: every span can be filtered or grouped by github.workflow_ref. Dashboard panels like "P95 agent latency by workflow" and "error rate by workflow file" become a one-line query rather than a regex over gh-aw.workflow.name.
  • In the JSONL mirror (/tmp/gh-aw/otel.jsonl): the resourceSpans[0].resource.attributes array in every entry will contain {"key": "github.workflow_ref", "value": {"stringValue": "github/gh-aw/.github/workflows/otel-advisor.yml@refs/heads/main"}}, making artifact-based post-hoc debugging faster.
  • For on-call engineers: "which workflow YAML is responsible for this alert?" becomes answerable directly from the span, without cross-referencing the run URL or gh-aw.workflow.name.
Implementation Steps
  • In sendJobSetupSpan (~line 493): add const workflowRef = process.env.GITHUB_WORKFLOW_REF || "";
  • In sendJobSetupSpan resource attributes block (~line 530): add conditional if (workflowRef) { resourceAttributes.push(buildAttr("github.workflow_ref", workflowRef)); }
  • In sendJobConclusionSpan (~line 704): add const workflowRef = process.env.GITHUB_WORKFLOW_REF || (typeof awInfo.context?.workflow_id === "string" ? awInfo.context.workflow_id : "");
  • In sendJobConclusionSpan resource attributes block (~line 817): add the same conditional push
  • Update send_otlp_span.test.cjs to assert github.workflow_ref is present when GITHUB_WORKFLOW_REF is set, following the same pattern as the existing github.ref / github.sha tests (e.g. lines 1202–1243)
  • Add a test asserting the attribute is absent when GITHUB_WORKFLOW_REF is not set
  • Run cd actions/setup/js && npx vitest run to confirm tests pass
  • Run make fmt to ensure formatting
  • Open a PR referencing this issue
Evidence from Live Sentry Data

The Sentry MCP server had no tools registered in this workflow run (sentry.json was empty), so live span sampling was not possible. The finding is based entirely on static analysis of the instrumentation code.

Structural evidence from the code:

  • aw_context.cjs:142 already reads process.env.GITHUB_WORKFLOW_REF and stores it as workflow_id, proving the env var is available at runtime.
  • send_otlp_span.cjs:516–536 and send_otlp_span.cjs:802–822 enumerate all resource attributes built for each span — github.workflow_ref is absent from both lists.
  • send_otlp_span.test.cjs has explicit coverage for every other github.* resource attribute (github.repository, github.run_id, github.event_name, github.ref, github.ref_name, github.head_ref, github.sha, github.actions.run_url) but no test case for github.workflow_ref.
Related Files
  • actions/setup/js/send_otlp_span.cjs — primary change location (both sendJobSetupSpan and sendJobConclusionSpan)
  • actions/setup/js/send_otlp_span.test.cjs — test assertions to add
  • actions/setup/js/aw_context.cjs — already reads GITHUB_WORKFLOW_REF as workflow_id; no change needed

Generated by the Daily OTel Instrumentation Advisor workflow

Generated by Daily OTel Instrumentation Advisor · ● 266.3K ·

  • expires on May 1, 2026, 9:32 PM UTC

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions