Skip to content

TT-17495 Fix span Original Path#8311

Merged
tbuchaillot merged 8 commits into
masterfrom
fix-TT-7519
Jun 16, 2026
Merged

TT-17495 Fix span Original Path#8311
tbuchaillot merged 8 commits into
masterfrom
fix-TT-7519

Conversation

@tbuchaillot

@tbuchaillot tbuchaillot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

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

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactoring or add test (improvements in base code or adds test coverage to functionality)

Checklist

  • I ensured that the documentation is up to date
  • I explained why this PR updates go.mod in detail with reasoning why it's required
  • I would like a code coverage CI quality gate exception and have explained why

@tbuchaillot
tbuchaillot requested a review from a team as a code owner June 11, 2026 13:25
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

🎯 Recommended Merge Targets

Based on JIRA ticket TT-7519: [Innersource] Include original request path in analytics

Fix Version: Tyk 5.14.0

⚠️ Warning: Expected release branches not found in repository

Required:

  • master - No matching release branches found. Fix will be included in future releases.

📋 Workflow

  1. Merge this PR to master first

@probelabs

probelabs Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

This PR addresses a bug in OpenTelemetry tracing where the tyk.original_path attribute was being incorrectly attached to middleware child spans instead of the main inbound HTTP request span. The fix introduces a new, dedicated middleware, withOriginalPathSpanAttribute, which wraps the primary request handler chain. This ensures the attribute is set on the correct parent span immediately after the request is received and the main span is created. The old logic in the generic trace middleware has been removed to prevent incorrect, redundant attribute setting.

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 tyk.original_path attribute is correctly present on the main span and, crucially, appears only once, even when detailed middleware tracing is enabled.

Files Changed Analysis

  • gateway/api.go: Introduces the new withOriginalPathSpanAttribute middleware. This function wraps the main http.Handler to get the active span from the context and set the tyk.original_path attribute.
  • gateway/api_loader.go: Integrates the new middleware. It modifies the API processing logic to wrap the handler chain with withOriginalPathSpanAttribute when OpenTelemetry tracing is enabled, applying the fix globally.
  • gateway/middleware.go: Removes the incorrect logic that previously added the tyk.original_path attribute within the generic TraceMiddleware, which executed for every middleware and created child spans.
  • gateway/original_request_path_test.go: Adds significant test coverage. TestOriginalRequestPath_MainHTTPSpanAttribute verifies the attribute is correctly added, and TestOriginalRequestPath_OnlyOnMainSpan_DetailedTracing ensures it is added only to the main span and not to any child spans.
  • ci/tests/tracing/scenarios/tyk_test_200.yml: Contains a minor fix for a User-Agent header indentation error in the test definition.

Architecture & Impact Assessment

  • What this PR accomplishes: It corrects the placement of the tyk.original_path span attribute in OpenTelemetry traces, ensuring it is attached to the main parent HTTP span for accurate request tracing.
  • Key technical changes introduced: The primary change is the shift from setting the attribute in a broad middleware to a dedicated middleware (withOriginalPathSpanAttribute) applied at the top of the request handler chain. This centralizes the logic and guarantees it executes in the correct context.
  • Affected system components: The change is narrowly focused on the Gateway's OpenTelemetry tracing subsystem. It modifies how trace data is enriched but does not alter core API gateway functionality, making it a low-risk change.
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
Loading

Scope Discovery & Context Expansion

  • The modification in gateway/api_loader.go is the central integration point. Since processSpec handles the construction of the request processing chain for each API definition, this change ensures the fix is applied globally to all APIs with OpenTelemetry tracing enabled.
  • The removal of attribute-setting logic from gateway/middleware.go is a critical cleanup step, preventing the attribute from being redundantly and incorrectly added to child spans created during detailed tracing.
  • The new tests in gateway/original_request_path_test.go are robust, establishing a mock OpenTelemetry collector to inspect the actual exported trace payload. This provides strong end-to-end validation of the fix and protects against future regressions.
  • The value for the attribute is sourced from ctxGetOriginalRequestPath, which retrieves the path from the request context. This context value is set earlier in the request lifecycle by the OriginalRequestPath middleware, ensuring the data is available when the new tracing middleware executes.
Metadata
  • Review Effort: 2 / 5
  • Primary Label: bug

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 /visor ask <your question>

@probelabs

probelabs Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

✅ Architecture Check Passed

No architecture issues found – changes LGTM.

✅ Performance Check Passed

No performance issues found – changes LGTM.

\n\n

✅ Architecture Check Passed

No architecture issues found – changes LGTM.

\n\n

✅ Performance Check Passed

No performance issues found – changes LGTM.

\n\n

✅ Quality Check Passed

No 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 /visor ask <your question>

@tbuchaillot tbuchaillot changed the title TT-7519 Fix span Original Path TT-17495 Fix span Original Path Jun 12, 2026
@tbuchaillot
tbuchaillot enabled auto-merge (squash) June 12, 2026 09:44

@mativm02 mativm02 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@tbuchaillot
tbuchaillot disabled auto-merge June 12, 2026 12:06

@bojank93 bojank93 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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: withOriginalPathSpanAttribute runs inside otel.HTTPHandler's context so otel.SpanFromContext(r.Context()) reliably returns the root span.
  • End-to-end integration test: TestOriginalRequestPath_OnlyOnMainSpan_DetailedTracing drives the full gateway with DetailedTracing = true and uses a tight count-based assertion that catches both "missing" and "extra" span regressions.
  • YAML fix is unambiguous: User-Agent was a sibling of headers instead 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-cnapp-eu1

Copy link
Copy Markdown

SentinelOne CNS Hardcoded Secret Detector
✅ Congratulations, your code is safe

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.

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Jira Linter Failed

Commit: 4a6b47e
Failed at: 2026-06-15 14:20:08 UTC

The Jira linter failed to validate your PR. Please check the error details below:

🔍 Click to view error details
failed to validate branch and PR title rules: PR title contains 'TT-17495' but branch has 'TT-7519' - they must match

Next Steps

  • Ensure your branch name contains a valid Jira ticket ID (e.g., ABC-123)
  • Verify your PR title matches the branch's Jira ticket ID
  • Check that the Jira ticket exists and is accessible

This comment will be automatically deleted once the linter passes.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Passed Quality Gate passed

Issues
0 New issues
1 Accepted issue

Measures
0 Security Hotspots
100.0% Coverage on New Code
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

@bojank93

Copy link
Copy Markdown

hi @tbuchaillot can you please fix the CI pipeline before merging this PR. ?

@tbuchaillot

Copy link
Copy Markdown
Contributor Author

hi @tbuchaillot can you please fix the CI pipeline before merging this PR. ?
The sentinelOne/Jira and arm64 upgrade doesn't seems related to these changes :)

@tbuchaillot
tbuchaillot merged commit d8435cb into master Jun 16, 2026
46 of 56 checks passed
@tbuchaillot
tbuchaillot deleted the fix-TT-7519 branch June 16, 2026 08:39
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