Implement trace context initialization in Rails for CI job telemetry
## Summary
Implement trace context initialization in Rails so that all telemetry spans for a CI pipeline hierarchy share the same `trace_id`, with each job as a top-level span within the pipeline trace. The trace context and OTEL Collector endpoint(s) are passed to the Runner via the unified `features.tracing` object in the job payload response.
## Job payload change
Add a `tracing` object to the `features` in the `/api/v4/jobs/request` response. Its presence signals that telemetry is enabled for the job; when absent, the Runner skips all telemetry instrumentation.
```json
{
"features": {
"tracing": {
"trace_id": "000000000000000000000000001e240a",
"span_parent_id": "00000000075bcd15",
"otel_endpoints": [
"https://otel-collector.gitlab.net/v1/traces"
]
}
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| `trace_id` | String (32-char hex) | Deterministically derived from the **root** `pipeline_id`. All jobs across the pipeline hierarchy (parent and child pipelines) share this trace ID. |
| `span_parent_id` | String (16-char hex), optional | Present only for child pipeline jobs. Derived from the trigger (bridge) job's database ID (`format('%016x', bridge.id)`), so child pipeline job spans nest under the trigger job in the trace tree. Absent for top-level pipeline jobs (Runner creates root-level spans). |
| `otel_endpoints` | Array of strings (max 2) | OTLP/HTTP endpoint URLs. First entry is GitLab's Collector (Rails application setting, gitlab-org/gitlab#591941). Optional second entry is a customer-configured BYO OTLP endpoint (project/group setting, future). Runner exports spans to all endpoints in parallel. |
## Requirements
1. Generate `trace_id` deterministically from the **root** `pipeline_id` (for example, zero-padded hex representation). Child pipelines inherit the root pipeline's trace ID.
2. For child pipeline jobs, generate `span_parent_id` from the trigger (bridge) job's database ID (`format('%016x', bridge.id)`), so child pipeline spans nest under the trigger job in the trace tree. Omit `span_parent_id` for top-level pipeline jobs.
3. Only include `features.tracing` when:
- The `ci_job_telemetry` feature flag is enabled for the project (see gitlab-org/gitlab#590588), **and**
- The CI telemetry OTEL Collector endpoint application setting is configured (see gitlab-org/gitlab#591941)
4. Populate `otel_endpoints` with the configured OTEL Collector endpoint URL from the Rails application setting as the first entry. A future per-project/group BYO endpoint may be added as a second entry.
5. Include `ci.pipeline.id` and `ci.pipeline.source` as resource attributes in OTLP spans emitted by Rails (alongside `ci.job.id`, `ci.project.id`) — needed to identify the specific pipeline a job belongs to, since `trace_id` maps to the root pipeline
## Architecture Reference
- [Job payload changes](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/ci_job_telemetry/#job-payload-changes)
- [Multi-source trace context coordination](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/ci_job_telemetry/#multi-source-trace-context-coordination)
- [Design decision: OTEL Collector endpoint configuration](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/ci_job_telemetry/#design-decisions)
## Dependencies
- Feature negotiation (gitlab-org/gitlab#590588) must be implemented first — `features.tracing` is only included when the feature flag is enabled
- OTEL Collector endpoint application setting (gitlab-org/gitlab#591941) — the endpoint URL must be configured for `features.tracing` to be included
- Coordinate with ~"group::runner core" on job payload schema changes (&20633)
## Parent Epic
gitlab-org&20945
issue