TT-17495 Fix span Original Path#8311
Conversation
🎯 Recommended Merge TargetsBased on JIRA ticket TT-7519: [Innersource] Include original request path in analytics Fix Version: Tyk 5.14.0
Required:
📋 Workflow
|
|
This PR addresses a bug in OpenTelemetry tracing where the Additionally, the PR includes a minor fix for a YAML indentation issue in a CI test scenario and adds robust regression tests. These new tests utilize a mock OpenTelemetry collector to validate that the Files Changed Analysis
Architecture & Impact Assessment
sequenceDiagram
participant Client
participant Gateway as "Gateway (api_loader.go)"
participant OTEL as "otel.HTTPHandler"
participant NewMiddleware as "withOriginalPathSpanAttribute"
participant DownstreamChain as "Downstream Middleware/Handler"
Client->>Gateway: HTTP Request
activate Gateway
Gateway->>OTEL: Process Request
activate OTEL
Note over OTEL: Starts main inbound span
OTEL->>NewMiddleware: Invoke wrapped handler
activate NewMiddleware
NewMiddleware-->>OTEL: otel.SpanFromContext(r.Context())
NewMiddleware->>OTEL: span.SetAttributes(tyk.original_path)
Note right of NewMiddleware: Attribute is set on the main span
NewMiddleware->>DownstreamChain: next.ServeHTTP(w, r)
deactivate NewMiddleware
deactivate OTEL
deactivate Gateway
Scope Discovery & Context Expansion
Metadata
Powered by Visor from Probelabs Last updated: 2026-06-15T14:21:21.877Z | Triggered by: pr_updated | Commit: 4a6b47e 💡 TIP: You can chat with Visor using |
✅ Architecture Check PassedNo architecture issues found – changes LGTM. ✅ Performance Check PassedNo performance issues found – changes LGTM. \n\n✅ Architecture Check PassedNo architecture issues found – changes LGTM. \n\n✅ Performance Check PassedNo performance issues found – changes LGTM. \n\n✅ Quality Check PassedNo quality issues found – changes LGTM. Powered by Visor from Probelabs Last updated: 2026-06-15T14:21:20.356Z | Triggered by: pr_updated | Commit: 4a6b47e 💡 TIP: You can chat with Visor using |
bojank93
left a comment
There was a problem hiding this comment.
Quinn — QA Review: PR #8311 / TT-17495
PR Summary
This PR fixes a misplacement of the tyk.original_path OpenTelemetry attribute introduced in TT-7519. The attribute was being set on every middleware child span (visible when detailed_tracing is enabled) instead of on the root inbound HTTP span. The fix introduces a thin withOriginalPathSpanAttribute HTTP middleware wrapper in api.go, inserts it inside otel.HTTPHandler in api_loader.go, and removes the two duplicate attribute-setting blocks from middleware.go. A YAML indentation fix to tyk_test_200.yml also restores the broken Tracetest OTel e2e assertion. The implementation matches the Jira description.
Jira Alignment
| Field | Value |
|---|---|
| Ticket | TT-17495 — Original_path trace attribute in wrong span |
| Type | Bug |
| Status | In Test |
| Acceptance Criteria Met? | ✅ Yes (inferred — no explicit AC fields set in Jira) |
| # | Acceptance Criterion | Covered in PR? | Note |
|---|---|---|---|
| 1 | tyk.original_path appears on the main inbound HTTP span |
✅ Yes | withOriginalPathSpanAttribute runs inside otel.HTTPHandler context |
| 2 | tyk.original_path does NOT appear on middleware child spans with detailed_tracing |
✅ Yes | Removed from both TraceMiddleware.ProcessRequest and createMiddleware defer |
| 3 | OTel e2e Tracetest scenario tyk_test_200.yml passes |
✅ Yes | YAML indentation fix restores the User-Agent header assertion nesting |
Unit & Integration Test Coverage
| Package | Tests Added? | What's Covered | Gap | Severity |
|---|---|---|---|---|
gateway (withOriginalPathSpanAttribute) |
✅ Yes | Main span attribute placement via mock OTel collector | See finding T-1 | 🟡 Medium |
gateway (removal from TraceMiddleware.ProcessRequest) |
✅ Yes | TestOriginalRequestPath_OnlyOnMainSpan_DetailedTracing asserts count==1 with full gateway + DetailedTracing=true |
— | ✅ None |
gateway (removal from createMiddleware defer) |
✅ Yes | Same end-to-end test covers both removal paths | — | ✅ None |
ci/tests/tracing YAML fixture |
N/A | Covered by OTel e2e CI run | — | ✅ None |
Finding T-1 (🟡 Medium): TestOriginalRequestPath_MainHTTPSpanAttribute constructs a bare httptest.NewRequest and passes it directly to withOriginalPathSpanAttribute without an explicit ctxSetOriginalRequestPath call. If ctxGetOriginalRequestPath(r) returns "" at that point the wrapper is a no-op and the bytes.Contains(payload, []byte("tyk.original_path")) assertion would be incorrect. Please confirm this test actually passes on the PR branch with the attribute present in the exported payload. If it does, a short comment explaining how the original path enters context in this unit-test scenario would prevent future confusion.
The second test, TestOriginalRequestPath_OnlyOnMainSpan_DetailedTracing, is the authoritative check — full gateway stack, DetailedTracing = true, exactly-one-occurrence assertion. This is the test that matters most and it correctly validates the fix.
UI Test Coverage (Playwright)
No frontend files changed. Section not applicable.
Security Findings
No security issues found.
Code Quality Issues
No code quality issues found.
Tyk Domain Issues
| # | Severity | Location | Issue | Recommendation |
|---|---|---|---|---|
| 1 | 🟡 Medium | gateway/api_loader.go:617 |
Implicit ordering dependency: withOriginalPathSpanAttribute reads ctxGetOriginalRequestPath(r) BEFORE chain executes. Correct only if ctxSetOriginalRequestPath is called upstream of otel.HTTPHandler. Not documented. |
Add a one-line comment at the call site documenting this invariant. If the path is actually set from within the chain, the attribute will always be empty and the integration test is the only safety net. |
| 2 | 🟢 Low | gateway/api.go (new function) |
withOriginalPathSpanAttribute is defined alongside context helpers; its role is middleware construction — minor placement mismatch. |
Cosmetic — move at your discretion, not blocking. |
What was done well
- Surgical fix: Exactly three change sites — add one wrapper, remove two blocks — no scope creep.
- Correct span context:
withOriginalPathSpanAttributeruns insideotel.HTTPHandler's context sootel.SpanFromContext(r.Context())reliably returns the root span. - End-to-end integration test:
TestOriginalRequestPath_OnlyOnMainSpan_DetailedTracingdrives the full gateway withDetailedTracing = trueand uses a tight count-based assertion that catches both "missing" and "extra" span regressions. - YAML fix is unambiguous:
User-Agentwas a sibling ofheadersinstead of a child element — the indentation fix is clear and correct.
Gap Summary
| Area | Gaps Found | Highest Severity |
|---|---|---|
| Unit / Integration Tests | 1 | 🟡 Medium |
| UI Tests (Playwright) | — | N/A |
| Security | 0 | ✅ None |
| Code Quality | 0 | ✅ None |
| Tyk Domain | 2 | 🟡 Medium |
| Jira Alignment | 0 | ✅ Full |
Verdict
APPROVE
The core fix is correct: tyk.original_path is moved out of the per-middleware child span loop onto the root HTTP span via a clean, minimal wrapper. The authoritative integration test (TestOriginalRequestPath_OnlyOnMainSpan_DetailedTracing) covers the exact bug scenario with a tight assertion. The two medium findings are a documentation gap (ordering invariant) and a test-setup clarity question (T-1) — neither is a blocking defect. Please verify T-1 passes with the attribute actually present in the payload, and consider a short comment at the withOriginalPathSpanAttribute call site in api_loader.go documenting the ordering invariant.
Review by Quinn · Tyk QA · 2026-06-15
|
SentinelOne CNS Hardcoded Secret Detector SentinelOne CNS is a cloud-agnostic, agentless CSPM & CWPP solution that continuously detects and prevents vulnerabilities that have the highest probability of being exploited in Azure, AWS, Google Cloud, and Kubernetes. |
🚨 Jira Linter FailedCommit: The Jira linter failed to validate your PR. Please check the error details below: 🔍 Click to view error detailsNext Steps
This comment will be automatically deleted once the linter passes. |
|
|
hi @tbuchaillot can you please fix the CI pipeline before merging this PR. ? |
|



Description
The otel e2e failure happened because tyk.original_path was being added only to middleware spans, while the Tracetest scenarios expect it on the main inbound HTTP span. The trace structure was fine; the attribute was just attached at the wrong level.
This fix sets tyk.original_path on the existing active inbound span right after the original request path is captured. It does not create new spans or change parent/child relationships. It also fixes the malformed User-Agent indentation in tyk_test_200.yml, which was causing that scenario to run with zero assertions, and adds a gateway regression test using the existing mock OTEL collector pattern.
Related Issue
Motivation and Context
How This Has Been Tested
Screenshots (if appropriate)
Types of changes
Checklist