Repository navigation
feat: opt-in deterministic trace and job span IDs - #219
georgegebbett wants to merge 1 commit into
Conversation
Adds a DETERMINISTIC_TRACE_IDS input. When enabled, the trace ID is derived from the repository, run ID and run attempt, and job span IDs from the job ID, so other tools can attach spans to a workflow run's trace without talking to this action. The derivation is documented in the README. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
paper2
left a comment
There was a problem hiding this comment.
This is a good idea. Deriving the trace ID from the run lets another tool join the trace without this action passing the ID over, which fits an action that builds the trace after the workflow finishes.
Deriving the job span IDs as well seems to add more complexity: three public span formulas, the numeric job id, and parenting extra spans under a specific job span. I want to check that this part is actually needed.
If the goal is to parent extra spans under a job, could you describe that case? Which tool emits the span, and does it run inside the job or after the workflow has finished? Which of the three job spans should it use as its parent, and why is sharing the trace ID not enough? How does that tool obtain the numeric job id, as opposed to github.job?
| Step spans keep random IDs. For example, to parent a span under a job in shell: | ||
|
|
||
| ```bash | ||
| trace_id=$(printf '%s' "$GITHUB_REPOSITORY:$RUN_ID:$RUN_ATTEMPT" | sha256sum | cut -c1-32) |
There was a problem hiding this comment.
This example does not hash the same key the implementation uses.
workflowTraceId is SHA-256 of repository + : + the workflow run id + : + run_attempt (GITHUB_RUN_ID / GITHUB_RUN_ATTEMPT, not the workflow definition id). jobSpanId is SHA-256 of job: + the numeric Actions job id from the jobs API.
$RUN_ID, $RUN_ATTEMPT, and $JOB_ID are not set by GitHub. GITHUB_JOB / github.job is the YAML job key (build), not that numeric id. Hashing the YAML key, or an empty JOB_ID, produces a different span id, so a child span will not land on this action's job span. The table's <job_id> has the same ambiguity.
Use $GITHUB_REPOSITORY:$GITHUB_RUN_ID:$GITHUB_RUN_ATTEMPT, and job:$JOB_ID only after defining JOB_ID as the numeric job id (jobs[].id; on github.com and GHEC that is ${{ job.check_run_id }}, not github.job). printf '%s' | sha256sum | cut -c1-32 / cut -c1-16 already matches hashId.
| test('should keep random IDs unless deterministic IDs are enabled', async () => { | ||
| const traceId = await createTrace(workflowRunResults) | ||
| expect(traceId).toMatch(/^[0-9a-f]{32}$/) | ||
| expect(traceId).not.toBe('9b622c3f42e4e04dcc07e34075e07913') |
There was a problem hiding this comment.
[nits] It should be wrote :)
| expect(traceId).not.toBe('9b622c3f42e4e04dcc07e34075e07913') | |
| // Hard-coded: these are the documented contract other tools compute against. | |
| expect(traceId).not.toBe('9b622c3f42e4e04dcc07e34075e07913') |
| import { createHash } from 'node:crypto' | ||
| import { IdGenerator, RandomIdGenerator } from '@opentelemetry/sdk-trace-base' | ||
|
|
||
| export type SpanIds = { traceId?: string; spanId?: string } |
There was a problem hiding this comment.
[imo] SpanIds reads like a collection of span IDs, but this is the trace ID and span ID preset for a single startSpan. PresetIds matches withIds / preset.
|
Thank you very much! I understood the intention. It is a policy to incorporate this change. It is no problem to be determinstic in all spans. Please respond to the comments on the pull request! |

Adds a DETERMINISTIC_TRACE_IDS input. When enabled, the trace ID is derived from the repository, run ID and run attempt, and job span IDs from the job ID, so other tools can attach spans to a workflow run's trace without talking to this action. The derivation is documented in the README.