feat: OTLP trace export via observability.otlp frontmatter config#24441
feat: OTLP trace export via observability.otlp frontmatter config#24441
Conversation
…issue) Agent-Logs-Url: https://github.com/github/gh-aw/sessions/49301b6f-02ce-44b4-8fd5-1bc9a878d6cc Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
@copilot,add a JavaScript implementation to push messages to the OTLP endpoint and instrument the action setup to take the job name as an input so it pushes a message each time it runs the job. |
…e input Agent-Logs-Url: https://github.com/github/gh-aw/sessions/5738fc76-45bf-47ab-af6c-8de1dc9ec689 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/5738fc76-45bf-47ab-af6c-8de1dc9ec689 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in c890c53 (building on 233b74c):
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
set the trace id as an output of the action and also as a optional input so that you can correlate all jobs (use traceid from activation job, ignore preactivation) |
…orrelation Agent-Logs-Url: https://github.com/github/gh-aw/sessions/461b1d13-5dec-4bb7-8daa-d36d583465a4 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/461b1d13-5dec-4bb7-8daa-d36d583465a4 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…idTraceId in index.js Agent-Logs-Url: https://github.com/github/gh-aw/sessions/461b1d13-5dec-4bb7-8daa-d36d583465a4 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 4a40521 (building on ffd3965 and 6a3a6b9):
Usage for cross-job correlation: # Activation job
- uses: github/gh-aw/actions/setup@main
id: setup
with:
job-name: activation
# Agent job (depends on activation)
- uses: github/gh-aw/actions/setup@main
with:
job-name: agent
trace-id: ${{ needs.activation.outputs.setup-trace-id }}Pre-activation jobs that don't pass |
actions/setup/js/send_otlp_span.cjs
Outdated
| }, | ||
| scopeSpans: [ | ||
| { | ||
| scope: { name: "gh-aw.setup", version: "1.0.0" }, |
There was a problem hiding this comment.
- name gh-aw
- pass current version
There was a problem hiding this comment.
Done in 965d5d7:
- Scope
namechanged from"gh-aw.setup"to"gh-aw" - Scope
versionnow readsprocess.env.GH_AW_INFO_VERSION || "unknown"(same env var written by the compiler for every job)
actions/setup/js/send_otlp_span.cjs
Outdated
| body: JSON.stringify(payload), | ||
| }); | ||
| if (!response.ok) { | ||
| throw new Error(`OTLP export failed: HTTP ${response.status} ${response.statusText}`); |
There was a problem hiding this comment.
Done in 965d5d7. sendOTLPSpan now:
- Uses
console.warninstead of throwing on non-2xx responses - Retries up to 3 times (configurable) with exponential back-off (100 ms, 200 ms) before the final warning
|
@copilot add support for configuring headers for otel |
… spans for safe-outputs/conclusion jobs" Agent-Logs-Url: https://github.com/github/gh-aw/sessions/2a7e539d-2a7e-452d-8b26-8de15a7ebabe Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 965d5d7:
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
…nfig Agent-Logs-Url: https://github.com/github/gh-aw/sessions/8f5dc8d2-75f6-4186-affe-e329b01b1aaf Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/8f5dc8d2-75f6-4186-affe-e329b01b1aaf Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Usage: observability:
otlp:
endpoint: ${{ secrets.OTLP_ENDPOINT }}
headers: ${{ secrets.OTLP_HEADERS }} # e.g. "Authorization=******"Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
The OTel dependency in gh-aw was dormant — no way to export structured per-call span data to any OTLP backend. This adds the configuration plumbing to activate it, including a JavaScript implementation that instruments every job run with OTLP spans and supports cross-job trace correlation.
Changes
Go compiler
OTLPConfigstruct + schema — newobservability.otlp.endpointandobservability.otlp.headersfrontmatter fields; validated by the JSON schema withadditionalProperties: falseobservability_otlp.go— focused helpers:extractOTLPEndpointDomain— parses hostname from static URLs; skips${{ expressions }}that can't be resolved at compile timegetOTLPEndpointEnvValue— reads endpoint fromFrontmatterConfig(*Compiler).injectOTLPConfig— auto-adds domain toNetworkPermissions.Allowed(AWF firewall) and appendsOTEL_EXPORTER_OTLP_ENDPOINT,OTEL_SERVICE_NAME=gh-aw, andOTEL_EXPORTER_OTLP_HEADERS(when configured) to the workflow-levelenv:blockgenerateOTLPConclusionSpanStep— generates aif: always()/continue-on-error: trueGitHub Actions step that callssendJobConclusionSpancompiler_orchestrator_workflow.go— single call toinjectOTLPConfigafterextractYAMLSections; no-op when unconfiguredcompiler_safe_outputs_job.go— appends agh-aw.job.safe-outputsOTLP span step at the end of the safe_outputs jobnotify_comment.go— appends agh-aw.job.conclusionOTLP span step at the end of the conclusion jobJavaScript instrumentation
actions/setup/js/send_otlp_span.cjs:gh-aw.job.setupspan toOTEL_EXPORTER_OTLP_ENDPOINT/v1/tracesusing nativefetch(Node 24, no extra dependencies)nameis"gh-aw"andversionis read fromGH_AW_INFO_VERSIONat runtimeparseOTLPHeaders(raw)— parses the OTel speckey=value,key=valueformat with percent-decoding (decode-before-trim); merged into every request alongsideContent-TypesendOTLPSpanreadsOTEL_EXPORTER_OTLP_HEADERSfrom the environment and includes the parsed headers in every export request; retries up to 3 times with exponential back-off (100 ms, 200 ms) and warns viaconsole.warnon failure instead of throwing — OTLP failures can never break a workflowsendJobSetupSpan— span attributes includegh-aw.job.name,gh-aw.workflow.name,gh-aw.engine.id,gh-aw.run.id,gh-aw.run.actor, andgh-aw.repository; always returns the trace ID usedsendJobConclusionSpan(spanName)— readsaw_info.jsonfor workflow/engine/model/version metadata andGH_AW_EFFECTIVE_TOKENSfor token usage; called from the safe_outputs and conclusion jobsisValidTraceId()— validates the 32-character lowercase hex format; upstream uppercase values are normalised; invalid values fall back to a freshly generated IDgenerate_observability_summary.cjs— callssendJobConclusionSpan("gh-aw.job.conclusion")after writing the step summary (agent job instrumentation)actions/setup/action.yml— addedjob-nameinput;trace-idoptional input (32-char hex) andtrace-idoutput for cross-job correlationactions/setup/index.js— callssendJobSetupSpan({ startMs })aftersetup.shcompletes; writes the resolved trace ID toGITHUB_OUTPUT; errors are swallowedUsage
In the workflow step that uses
actions/setup, pass the job name and wire up trace correlation across jobs:Pre-activation jobs that omit
trace-ideach get an independent trace ID; only jobs that explicitly pass the activation job'strace-idoutput are correlated under the same trace.The safe_outputs and conclusion jobs automatically emit conclusion spans containing
aw_infometadata and effective token usage — no additional configuration required.When a static URL is given (e.g.
https://traces.example.com:4317), the hostname is automatically allowlisted in the AWF firewall. When a secret expression is used, the domain cannot be resolved at compile time — users must add it tonetwork.allowedmanually.The generated workflow gets:
and
traces.example.comis injected into every engine's--allow-domainsflag viaNetworkPermissions.Allowed— no changes to existing domain function signatures required.