Skip to content

feat: merge all OTLP endpoints from shared agentic workflow imports#30209

Merged
pelikhan merged 4 commits intomainfrom
copilot/merge-observability-endpoints
May 4, 2026
Merged

feat: merge all OTLP endpoints from shared agentic workflow imports#30209
pelikhan merged 4 commits intomainfrom
copilot/merge-observability-endpoints

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 4, 2026

When multiple shared workflows each define observability.otlp, only the first import's endpoint survived (first-wins). All subsequent imports' endpoints were silently dropped. This change collects all endpoints from all imports, merges them with the main workflow's endpoints, deduplicates by URL, and injects the full array for fan-out telemetry.

Changes

pkg/parser/import_field_extractor.go

  • observabilityBuilder strings.BuilderobservabilityConfigs []string: collect all observability JSON blobs, not just the first
  • New extractOTLPEndpointsFromObsMap(): handles string/object/array endpoint notation, preserving headers in original format (map vs string) to avoid false deprecation warnings
  • New mergeObservabilityConfigs(): deduplicates by URL (first-occurrence wins), produces a single {"otlp":{"endpoint":[...]}} array-form JSON

pkg/workflow/observability_otlp.go

  • New extractRawOTLPEndpointMaps(): extracts endpoint map[string]any entries with headers intact — unlike collectAllOTLPEndpoints, does not normalize headers to string form

pkg/workflow/compiler_orchestrator_workflow.go

  • Merge now always runs (previously skipped when main workflow already had observability)
  • Main workflow endpoints take precedence; import endpoints appended unless already seen

pkg/workflow/observability_job_summary_test.go

  • New TestCompileWorkflow_MultipleImportsOTLPEndpointsMerged: end-to-end regression test compiling a workflow with 3 imports (string, object, and array endpoint notation) plus a main-workflow endpoint; asserts all distinct endpoints appear in GH_AW_OTLP_ENDPOINTS and the main endpoint is the primary OTEL_EXPORTER_OTLP_ENDPOINT
  • New TestCompileWorkflow_TwoImportsWithOTLPNoMainEndpoint: verifies first import's endpoint becomes primary when the main workflow has no observability section
  • New TestCompileWorkflow_DuplicateOTLPEndpointAcrossImportsDeduped: verifies that the same URL defined in two imports produces exactly one entry in GH_AW_OTLP_ENDPOINTS

Example — previously broken, now works

# shared/vendor-otlp.md
observability:
  otlp:
    endpoint: https://vendor.example.com:4317

# shared/internal-otlp.md  
observability:
  otlp:
    endpoint:
      url: https://internal.corp:4317
      headers: {X-Token: "${{ secrets.INTERNAL_TOKEN }}"}

# main.md
imports:
  - shared/vendor-otlp.md
  - shared/internal-otlp.md
# Result: GH_AW_OTLP_ENDPOINTS contains both endpoints; only vendor endpoint was set before

Supports mix of string, object, and array endpoint notation across imports. Deduplication is URL-based; headers from the first occurrence of a given URL win.

Copilot AI and others added 2 commits May 4, 2026 18:29
- Change observabilityBuilder (first-wins) to observabilityConfigs []string
  that collects ALL imported observability JSON blobs
- Add mergeObservabilityConfigs() in pkg/parser that deduplicates by URL
  and produces a single array-form JSON for all imports' endpoints
- Add extractOTLPEndpointsFromObsMap() in pkg/parser that handles
  string/object/array endpoint forms, preserving raw headers format
- Add extractRawOTLPEndpointMaps() in pkg/workflow/observability_otlp.go
  that extracts endpoint maps with original headers (prevents false
  deprecation warnings from normalized strings)
- Update compiler_orchestrator_workflow.go to always merge endpoints from
  main workflow AND imports (not only when main has no observability),
  deduplicating by URL with main workflow taking precedence
- Add comprehensive tests for all new helpers (21 new test cases)

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/bc1e4ef7-1c91-435e-8170-a4337b3c5993

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…ssages

- Document shallow copy intent in extractRawOTLPEndpointMaps
- Add granular logging in compiler (main vs import endpoint counts)
- Include import index in unmarshal error message
- Include endpoint count in marshal error message

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/bc1e4ef7-1c91-435e-8170-a4337b3c5993

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan pelikhan marked this pull request as ready for review May 4, 2026 19:10
Copilot AI review requested due to automatic review settings May 4, 2026 19:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes OTLP observability endpoint handling when multiple shared workflows are imported by merging all imported observability.otlp.endpoint values (plus any main workflow endpoints) into a single deduplicated endpoint array for fan-out telemetry.

Changes:

  • Collect observability configs from all imports, extract OTLP endpoints across string/object/array forms, and merge/deduplicate by URL.
  • Preserve header representation (string vs map) through merging to avoid emitting false deprecation warnings.
  • Always merge imported + main endpoints into RawFrontmatter before OTLP injection so downstream compilation sees the full endpoint set.
Show a summary per file
File Description
pkg/workflow/observability_otlp.go Adds raw endpoint extraction helper to preserve header formats during merge.
pkg/workflow/observability_otlp_test.go Adds unit tests for raw endpoint extraction across endpoint notations.
pkg/workflow/compiler_orchestrator_workflow.go Updates compilation orchestration to merge imported + main OTLP endpoints (URL-deduped, main-first).
pkg/parser/import_processor.go Updates MergedObservability documentation to reflect merged endpoint-array behavior.
pkg/parser/import_field_extractor.go Collects observability from all imports and adds endpoint extraction + merge/dedup into a single JSON blob.
pkg/parser/import_field_extractor_test.go Adds tests for endpoint extraction and merged observability JSON output/dedup behavior.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 6/6 changed files
  • Comments generated: 1

Comment on lines +171 to +210
// Merge observability endpoints from imports with those from the main workflow.
// All OTLP endpoints from both sources are combined into an array, deduplicating
// by URL (main workflow endpoints take precedence). This allows multiple shared
// workflows each defining their own OTLP endpoint to fan out to all collectors.
if obs := engineSetup.importsResult.MergedObservability; obs != "" {
if _, hasObs := workflowData.RawFrontmatter["observability"]; !hasObs {
var obsMap map[string]any
if err := json.Unmarshal([]byte(obs), &obsMap); err == nil {
workflowData.RawFrontmatter["observability"] = obsMap
orchestratorWorkflowLog.Printf("Merged observability config from imports into RawFrontmatter")
var importedObs map[string]any
if err := json.Unmarshal([]byte(obs), &importedObs); err == nil {
seen := make(map[string]bool)
var mergedEndpoints []any

// Main workflow endpoints take precedence (first in, first wins dedup).
var mainObs map[string]any
if v, ok := workflowData.RawFrontmatter["observability"]; ok {
mainObs, _ = v.(map[string]any)
}
for _, ep := range extractRawOTLPEndpointMaps(mainObs) {
if url, _ := ep["url"].(string); url != "" && !seen[url] {
seen[url] = true
mergedEndpoints = append(mergedEndpoints, ep)
}
}

// Append import endpoints that aren't already present.
importAdded := 0
for _, ep := range extractRawOTLPEndpointMaps(importedObs) {
if url, _ := ep["url"].(string); url != "" && !seen[url] {
seen[url] = true
mergedEndpoints = append(mergedEndpoints, ep)
importAdded++
}
}

if len(mergedEndpoints) > 0 {
mainCount := len(mergedEndpoints) - importAdded
workflowData.RawFrontmatter["observability"] = map[string]any{
"otlp": map[string]any{
"endpoint": mergedEndpoints,
},
}
orchestratorWorkflowLog.Printf("Merged OTLP endpoints into RawFrontmatter: %d from main workflow, %d from imports (%d total)", mainCount, importAdded, len(mergedEndpoints))
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented May 4, 2026

@copilot merge main and recompile

Copilot AI and others added 2 commits May 4, 2026 19:23
…bility-endpoints

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…merging

- TestCompileWorkflow_MultipleImportsOTLPEndpointsMerged: full scenario
  with 3 imports (string, object, array notation) + main workflow endpoint;
  verifies all distinct endpoints appear in GH_AW_OTLP_ENDPOINTS and
  main-workflow endpoint is the primary OTEL_EXPORTER_OTLP_ENDPOINT
- TestCompileWorkflow_TwoImportsWithOTLPNoMainEndpoint: no main observability
  section; first import's endpoint becomes the primary
- TestCompileWorkflow_DuplicateOTLPEndpointAcrossImportsDeduped: same URL
  in two imports produces only one entry in GH_AW_OTLP_ENDPOINTS

Also includes merge of origin/main and workflow recompile.

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/bc26ac42-007e-4dae-94bc-93199026096c

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 4, 2026

@copilot merge main and recompile

Done — merged origin/main and recompiled all 213 workflows (0 errors). Also added the end-to-end regression tests requested in the review (commit ca5a22a).

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:

  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv (http block)
  • https://api.github.com/repos/actions/download-artifact/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/download-artifact/git/ref/tags/v8 --jq [.object.sha, .object.type] | @tsv (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v9
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv cp .github/aw/actions-lock.json pkg/actionpins/data/action_pins.json; \ cp .github/aw/actions-lgit (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv cli/install.sh...&#34; (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv (http block)
  • https://api.github.com/repos/docker/metadata-action/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/docker/metadata-action/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv (http block)
  • https://api.github.com/repos/docker/setup-buildx-action/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/docker/setup-buildx-action/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv (http block)
  • https://api.github.com/repos/github/gh-aw
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw --jq .default_branch (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from pelikhan May 4, 2026 19:32
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented May 4, 2026

@copilot review all comments

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 4, 2026

@copilot review all comments

All comments have been addressed:

  1. Code review (missing end-to-end tests) → Added 3 regression tests in ca5a22a: TestCompileWorkflow_MultipleImportsOTLPEndpointsMerged (full scenario with 3 imports + main endpoint, string/object/array notation, dedup), TestCompileWorkflow_TwoImportsWithOTLPNoMainEndpoint (no main obs section), and TestCompileWorkflow_DuplicateOTLPEndpointAcrossImportsDeduped (same URL in two imports → single entry).

  2. Merge main + recompile → Done: origin/main merged, all 213 workflows recompiled (0 errors).

No open items remain.

@pelikhan pelikhan merged commit 811dafd into main May 4, 2026
1 check passed
@pelikhan pelikhan deleted the copilot/merge-observability-endpoints branch May 4, 2026 21:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants