@@ -39781,6 +39781,7 @@ async function collectMetrics(octokit, context) {
3978139781 sha: context.sha || process.env.GITHUB_SHA || '',
3978239782 ref: context.ref || process.env.GITHUB_REF || '',
3978339783 refName: process.env.GITHUB_REF_NAME || null,
39784+ headBranch: context.payload?.pull_request?.head?.ref || null,
3978439785 },
3978539786 event: {
3978639787 name: context.eventName || process.env.GITHUB_EVENT_NAME || '',
@@ -52607,6 +52608,10 @@ function generateTraceId(runId, runAttempt) {
5260752608function generateRootSpanId(runId, runAttempt) {
5260852609 return crypto.createHash('sha256').update(`${runId}${runAttempt}s`).digest('hex').substring(16, 32);
5260952610}
52611+ /** sha256("{runId}{runAttempt}{jobName}")[16:32] — matches githubreceiver newJobSpanID */
52612+ function generateJobSpanId(runId, runAttempt, jobName) {
52613+ return crypto.createHash('sha256').update(`${runId}${runAttempt}${jobName}`).digest('hex').substring(16, 32);
52614+ }
5261052615function buildCicdAttributes(metrics, customAttributes = {}) {
5261152616 const attrs = {
5261252617 'cicd.pipeline.name': metrics.workflow,
@@ -52615,6 +52620,7 @@ function buildCicdAttributes(metrics, customAttributes = {}) {
5261552620 'vcs.repository.url.full': `https://github.com/${metrics.repository.fullName}`,
5261652621 'vcs.ref.head.name': metrics.git.refName || metrics.git.ref,
5261752622 'vcs.ref.head.revision': metrics.git.sha,
52623+ ...(metrics.git.headBranch ? { 'vcs.ref.head.branch': metrics.git.headBranch } : {}),
5261852624 'github.run.number': metrics.run.number.toString(),
5261952625 'github.run.attempt': metrics.run.attempt,
5262052626 'github.event.name': metrics.event.name,
@@ -52771,27 +52777,36 @@ function createTracerProvider(config, idGenerator) {
5277152777 });
5277252778 return { tracerProvider, tracer: tracerProvider.getTracer(config.metricPrefix) };
5277352779}
52774- function recordTraces(tracer, metrics, customAttributes = {}) {
52780+ function recordTraces(tracer, metrics, parentSpanId, customAttributes = {}) {
5277552781 info('Recording traces');
5277652782 const baseAttributes = buildCicdAttributes(metrics, customAttributes);
5277752783 const jobResult = mapToOtelResult(metrics.job.conclusion);
5277852784 const runUrl = `https://github.com/${metrics.repository.fullName}/actions/runs/${metrics.run.id}`;
52785+ // Create a remote parent context pointing at the run-level root span
52786+ // (sha256("{runId}{runAttempt}s")). This makes the job span a child of
52787+ // the workflow run span, matching the githubreceiver hierarchy:
52788+ // workflow_run (root) → job → steps
52789+ const traceId = generateTraceId(metrics.run.id.toString(), metrics.run.attempt);
52790+ const parentContext = trace.setSpanContext(context.active(), {
52791+ traceId,
52792+ spanId: parentSpanId,
52793+ traceFlags: TraceFlags.SAMPLED,
52794+ isRemote: true,
52795+ });
5277952796 const jobSpan = tracer.startSpan(`RUN ${metrics.workflow}`, {
5278052797 kind: SpanKind.SERVER,
5278152798 startTime: metrics.job.startedAt,
5278252799 attributes: {
5278352800 ...baseAttributes,
52784- // Pipeline-level attributes (this is our root span)
5278552801 'cicd.pipeline.action.name': 'RUN',
5278652802 'cicd.pipeline.result': jobResult,
5278752803 'cicd.pipeline.run.url.full': runUrl,
52788- // Task-level attributes
5278952804 'cicd.pipeline.task.name': metrics.job.name,
5279052805 'cicd.pipeline.task.run.id': metrics.job.id.toString(),
5279152806 'cicd.pipeline.task.run.result': jobResult,
5279252807 'cicd.pipeline.task.run.url.full': `${runUrl}/job/${metrics.job.id}`,
5279352808 },
52794- });
52809+ }, parentContext );
5279552810 const jobContext = trace.setSpan(context.active(), jobSpan);
5279652811 for (const step of metrics.steps) {
5279752812 if (step.startedAt && step.completedAt) {
@@ -52855,8 +52870,10 @@ async function run() {
5285552870 const collectorLog = getState('collector-log');
5285652871 const runId = process.env.GITHUB_RUN_ID || '0';
5285752872 const runAttempt = process.env.GITHUB_RUN_ATTEMPT || '1';
52873+ const jobName = getState('job-name') || process.env.GITHUB_JOB || 'unknown';
5285852874 const traceId = generateTraceId(runId, runAttempt);
5285952875 const rootSpanId = generateRootSpanId(runId, runAttempt);
52876+ const jobSpanId = generateJobSpanId(runId, runAttempt, jobName);
5286052877 try {
5286152878 info('Starting OpenTelemetry export post-action');
5286252879 const token = getInput('github-token', { required: true });
@@ -52879,11 +52896,11 @@ async function run() {
5287952896 const metrics = await collectMetrics(octokit, context$1);
5288052897 const { meterProvider: mp, meter } = createMeterProvider(config);
5288152898 meterProvider = mp;
52882- const idGenerator = new DeterministicIdGenerator(traceId, rootSpanId );
52899+ const idGenerator = new DeterministicIdGenerator(traceId, jobSpanId );
5288352900 const { tracerProvider: tp, tracer } = createTracerProvider(config, idGenerator);
5288452901 tracerProvider = tp;
5288552902 recordMetrics(meter, metrics, metricPrefix, customAttributes);
52886- recordTraces(tracer, metrics, customAttributes);
52903+ recordTraces(tracer, metrics, rootSpanId, customAttributes);
5288752904 await shutdownMeterProvider(meterProvider);
5288852905 await shutdownTracerProvider(tracerProvider);
5288952906 if (traceId) {
0 commit comments