Fix missing OTel span error recording in proxy handler; consolidate to semconv/v1.41.0#7576
Conversation
…semconv import in genai_attrs.go - P0 Bug: Add tracing.RecordSpanError/RecordSpanErrorOnAll calls for the three error paths in handleWithDIFC that ended spans without marking them as errors: 1. Guard not initialized (returns HTTP 503) 2. RunPipelinePrePhases non-access-denied failure (returns HTTP 502) 3. forwardAndReadBody returns nil/network error (returns HTTP 502) - P1 Cleanup: Consolidate genai_attrs.go from semconv/v1.34.0 to semconv/v1.41.0 for the five GenAI attribute keys available in v1.41.0 (GenAIToolNameKey, GenAIOperationNameKey, GenAIConversationIDKey, GenAIAgentNameKey, GenAIAgentIDKey). GenAISystem is defined as a raw attribute.Key since gen_ai.system was removed from semconv/v1.41.0, preserving the same string value for backward compatibility. Closes #7569
There was a problem hiding this comment.
Pull request overview
This pull request improves OpenTelemetry observability by ensuring proxy DIFC pipeline failures are correctly recorded as span errors (so 502/503 failures don’t appear as successful traces), and it standardizes semantic convention usage by consolidating GenAI attribute keys on semconv/v1.41.0.
Changes:
- Record span errors on three early-return failure paths in
proxyHandler.handleWithDIFC(including marking both forward + pipeline spans when upstream forwarding fails). - Switch
internal/tracing/genai_attrs.gotosemconv/v1.41.0and preserve the legacygen_ai.systemkey via a rawattribute.Key.
Show a summary per file
| File | Description |
|---|---|
| internal/tracing/genai_attrs.go | Updates GenAI semconv import to v1.41.0 and preserves gen_ai.system as a raw key. |
| internal/proxy/handler.go | Records span errors for previously unmarked DIFC/forwarding failure paths. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 3
| // GenAI semantic convention attribute keys. | ||
| // These are aliases for the official OpenTelemetry gen_ai semconv constants | ||
| // (semconv/v1.34.0), re-exported here for convenience. | ||
| // (semconv/v1.41.0), re-exported here for convenience. |
| errMsg := "returning 503: proxy enforcement not configured (no --policy flag provided)" | ||
| logHandler.Print(errMsg) | ||
| logger.LogError("proxy", "%s", errMsg) | ||
| tracing.RecordSpanError(difcSpan, errors.New("proxy enforcement not configured"), "service unavailable") | ||
| httputil.WriteErrorResponse(w, http.StatusServiceUnavailable, "service_unavailable", "proxy enforcement not configured") |
| } | ||
| if resp == nil { | ||
| tracing.RecordSpanErrorOnAll(errors.New("upstream request failed"), "upstream request failed", fwdSpan, difcSpan) | ||
| return |
|
@copilot address review feedback |
…ption, add span error tests
All three review items addressed in the latest commit:
|
|
@copilot address review feedback |
All review feedback was already addressed in commit To summarise what's in that commit:
|
Three error paths in
handleWithDIFCsilently ended spans without marking them as errors, causing 502/503 failures to appear as successful spans in tracing backends. Additionally,genai_attrs.goimportedsemconv/v1.34.0solely for GenAI attribute keys while the rest of the codebase usessemconv/v1.41.0.P0 — Span error recording gaps in
proxy/handler.goThree paths in
handleWithDIFCnow calltracing.RecordSpanError/RecordSpanErrorOnAllbefore returning:RecordSpanError(difcSpan, ...)with description"proxy enforcement not configured"RunPipelinePrePhasesnon-access-denied failureRecordSpanError(difcSpan, err, ...)forwardAndReadBodyreturns nilRecordSpanErrorOnAll(..., fwdSpan, difcSpan)P1 — Consolidate dual semconv imports
Switches
genai_attrs.gofromsemconv/v1.34.0tosemconv/v1.41.0— all five needed GenAI keys (GenAIToolNameKey,GenAIOperationNameKey,GenAIConversationIDKey,GenAIAgentNameKey,GenAIAgentIDKey) are present in v1.41.0.GenAISystemis defined as a rawattribute.Key("gen_ai.system")since that constant was dropped from v1.41.0, preserving the same wire string. The block comment on these constants is updated to make clear thatGenAISystemis special-cased and not a semconv alias.P2 — Regression tests for span error recording
Added
internal/proxy/handler_difc_test.gowith three tests that inject an in-memory recording tracer viaCachedTracerand assert span status code and exception events on each failure path:TestHandleWithDIFC_GuardNotInitialized_SetsSpanError— verifies the 503 path setsErrorstatus with description"proxy enforcement not configured"and emits anexceptionevent on the DIFC pipeline span.TestHandleWithDIFC_LabelResourceError_SetsSpanError— verifies the 502 pre-phases-failure path setsErrorstatus with description"resource labeling failed"and emits anexceptionevent.TestHandleWithDIFC_UpstreamFailure_SetsSpanError— verifies the 502 upstream-nil path setsErrorstatus on both theproxy.backend.forwardchild span and theproxy.difc_pipelineparent span.