Make OTEL service names workflow-specific in compiled OTLP workflows#32488
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
@copilot Use the workflow name as the workflow call ID, which also handles workflow calls. There is a more general name you can use. |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates compiled OTLP workflows so OTEL_SERVICE_NAME can be workflow-specific instead of always gh-aw.
Changes:
- Adds
otelServiceNameand uses it during OTLP env injection. - Updates/extends OTLP unit tests for service-name behavior.
- Updates OpenTelemetry docs for the new service-name format.
Show a summary per file
| File | Description |
|---|---|
pkg/workflow/observability_otlp.go |
Computes and injects workflow-scoped OTEL service names. |
pkg/workflow/observability_otlp_test.go |
Updates OTLP injection expectations and adds helper tests. |
docs/src/content/docs/reference/open-telemetry.md |
Documents the new OTEL_SERVICE_NAME behavior. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (1)
pkg/workflow/observability_otlp_test.go:666
- This test locks in display-name precedence, but the workflow-scoped service name should be based on WorkflowID when it is present. Please cover the normal compiler case where both Name and WorkflowID are populated and assert the WorkflowID-derived suffix so duplicate display names across files cannot regress.
t.Run("uses workflow-specific service name when workflow name is present", func(t *testing.T) {
got := otelServiceName(&WorkflowData{Name: "Repo Triage/Weekly"})
assert.Equal(t, "gh-aw.repo-triage-weekly", got)
- Files reviewed: 3/3 changed files
- Comments generated: 3
| // Prefer the compiled workflow name because it also reflects workflow_call | ||
| // invocations; fall back to WorkflowID for compatibility in edge/test cases. | ||
| workflowNameOrID := strings.TrimSpace(workflowData.Name) | ||
| if workflowNameOrID == "" { | ||
| workflowNameOrID = workflowData.WorkflowID |
| | --- | --- | | ||
| | `OTEL_EXPORTER_OTLP_HEADERS` | Comma-separated `key=value` headers for the first endpoint (when headers are configured). | | ||
| | `OTEL_SERVICE_NAME` | Always `gh-aw`. | | ||
| | `OTEL_SERVICE_NAME` | `gh-aw.<sanitized-workflow-name>` when the workflow name is available (for example, `Repo Triage/Weekly` → `gh-aw.repo-triage-weekly`); otherwise `gh-aw`. | |
| t.Run("OTEL_SERVICE_NAME includes sanitized workflow name when available", func(t *testing.T) { | ||
| c := newCompiler() | ||
| wd := &WorkflowData{ | ||
| Name: "Repo Triage/Weekly", | ||
| ParsedFrontmatter: &FrontmatterConfig{ |
There was a problem hiding this comment.
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · ● 5.5M
| got := otelServiceName(&WorkflowData{Name: "Repo Triage/Weekly"}) | ||
| assert.Equal(t, "gh-aw.repo-triage-weekly", got) | ||
| }) | ||
|
|
There was a problem hiding this comment.
[/tdd] The test value WorkflowID: "Repo Triage/Weekly" doesn't reflect what WorkflowID actually looks like at runtime — GetWorkflowIDFromPath always returns a plain basename without extension (e.g. "repo-triage"), never a slash-separated display name.
Using a realistic value would make this test a better specification and avoid the false implication that WorkflowID can contain slashes or spaces:
t.Run("falls back to workflow ID when workflow name is empty", func(t *testing.T) {
got := otelServiceName(&WorkflowData{WorkflowID: "repo-triage"})
assert.Equal(t, "gh-aw.repo-triage", got)
})The current value still exercises SanitizeWorkflowName, but it conflates the WorkflowID and Name concepts in a way that could mislead future readers.
| // invocations; fall back to WorkflowID for compatibility in edge/test cases. | ||
| workflowNameOrID := strings.TrimSpace(workflowData.Name) | ||
| if workflowNameOrID == "" { | ||
| workflowNameOrID = workflowData.WorkflowID |
There was a problem hiding this comment.
[/tdd] strings.TrimSpace is applied to workflowData.Name on the previous line but not to workflowData.WorkflowID here. In practice WorkflowID is set from filepath.Base(path) so it won't have surrounding whitespace, but the asymmetry is a latent bug if that invariant ever changes. A quick fix keeps the function consistent:
workflowNameOrID = strings.TrimSpace(workflowData.WorkflowID)
🧪 Test Quality Sentinel ReportTest Quality Score: 90/100✅ Excellent test quality
Test Classification DetailsView all 3 analyzed tests
AnalysisAll three changed/added tests are behavioral contract tests — they assert on the observable output of The new Minor Notes (non-blocking)Two Score Breakdown
Language SupportTests analyzed:
Verdict
📖 Understanding Test ClassificationsDesign Tests (High Value) verify what the system does:
Implementation Tests (Low Value) verify how the system does it:
Goal: Shift toward tests that describe the system's behavioral contract. References: §25945201645
|
There was a problem hiding this comment.
✅ Test Quality Sentinel: 90/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 3 analyzed tests verify behavioral contracts directly, including the new fallback coverage for the WorkflowID-based service name.
|
Unresolved review feedback remains on OTEL service naming precedence and the workflow-id fixture. Please update the implementation to prefer WorkflowID when available, adjust the tests/docs to use a realistic basename WorkflowID, and then request another review.
|
|
@copilot review all comments |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Addressed all actionable review feedback in commits
|
observability.otlpcurrently emits a singleOTEL_SERVICE_NAME(gh-aw) across all compiled workflows, which collapses traces into one logical service and makes workflow-level filtering noisy.This change scopes service naming to each workflow while preserving backward-compatible fallback behavior.
Compiler behavior
injectOTLPConfignow sets:OTEL_SERVICE_NAME: gh-aw.<sanitized-workflow-id>whenWorkflowIDis availableOTEL_SERVICE_NAME: gh-awwhen it is nototelServiceName(workflowData *WorkflowData)to centralize naming logic.Sanitization contract
Targeted coverage updates
gh-awto workflow-scoped names where applicable.Docs
gh-aw.<sanitized-workflow-id>and include a concrete transformation example.