Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion router-tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ require (
github.com/wundergraph/cosmo/demo/pkg/subgraphs/projects v0.0.0-20250715110703-10f2e5f9c79e
github.com/wundergraph/cosmo/router v0.0.0-20251125205644-175f80c4e6d9
github.com/wundergraph/cosmo/router-plugin v0.0.0-20250808194725-de123ba1c65e
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.240
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.241
go.opentelemetry.io/otel v1.36.0
go.opentelemetry.io/otel/sdk v1.36.0
go.opentelemetry.io/otel/sdk/metric v1.36.0
Expand Down
4 changes: 2 additions & 2 deletions router-tests/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,8 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/wundergraph/astjson v0.0.0-20250106123708-be463c97e083 h1:8/D7f8gKxTBjW+SZK4mhxTTBVpxcqeBgWF1Rfmltbfk=
github.com/wundergraph/astjson v0.0.0-20250106123708-be463c97e083/go.mod h1:eOTL6acwctsN4F3b7YE+eE2t8zcJ/doLm9sZzsxxxrE=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.240 h1:xnYwsUrmDcQnrZQ4+WZ8oODktsKJyAJWiYplWfmiQuk=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.240/go.mod h1:mX25ASEQiKamxaFSK6NZihh0oDCigIuzro30up4mFH4=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.241 h1:ch/8hfDaw4oz1Cx3Wb+OUl4qiAo17OdGhYMdRYnX8Is=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.241/go.mod h1:mX25ASEQiKamxaFSK6NZihh0oDCigIuzro30up4mFH4=
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg=
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
Expand Down
133 changes: 133 additions & 0 deletions router-tests/telemetry/telemetry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11254,6 +11254,139 @@ func TestFlakyTelemetry(t *testing.T) {
})
})

t.Run("verify errors being attached to unrelated span subgraphs", func(t *testing.T) {
simulateConnectionFailureOnClose := func(w http.ResponseWriter) {
hj, ok := w.(http.Hijacker)
if !ok {
// If the hijacker is not available, we switch to panic
// to simulate a failure
panic("service failure")
}
conn, _, err := hj.Hijack()
if err != nil {
// Hijacking failed, switch to panic
// to simulate a failure
panic(err)
}
_ = conn.Close()
}

t.Run("with one subgraph giving an error", func(t *testing.T) {
t.Parallel()

exporter := tracetest.NewInMemoryExporter(t)
testenv.Run(t, &testenv.Config{
TraceExporter: exporter,
Subgraphs: testenv.SubgraphsConfig{
Products: testenv.SubgraphConfig{
Middleware: func(_ http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
simulateConnectionFailureOnClose(w)
})
},
},
},
}, func(t *testing.T, xEnv *testenv.Environment) {
xEnv.MakeGraphQLRequestOK(testenv.GraphQLRequest{
Query: `query { employees { id isAvailable products derivedMood } }`,
})

sn := exporter.GetSpans().Snapshots()

subgraphThatShouldHaveError := "products"

for _, span := range sn {
if slices.Contains([]string{"Engine - Fetch"}, span.Name()) {
attributes := span.Attributes()
events := span.Events()

hasErrorEvent := false
subgraphName := ""

if len(events) > 0 {
require.Len(t, events, 1)
require.Equal(t, "exception", events[0].Name)
hasErrorEvent = true
}

for _, attributeEntry := range attributes {
if attributeEntry.Key == otel.WgSubgraphName {
subgraphName = attributeEntry.Value.AsString()
}
}

if subgraphName == subgraphThatShouldHaveError {
require.True(t, hasErrorEvent)
} else {
require.False(t, hasErrorEvent)
}
}
}
})
})

t.Run("with multiple subgraphs giving an error", func(t *testing.T) {
t.Parallel()

exporter := tracetest.NewInMemoryExporter(t)
testenv.Run(t, &testenv.Config{
TraceExporter: exporter,
Subgraphs: testenv.SubgraphsConfig{
Products: testenv.SubgraphConfig{
Middleware: func(_ http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
simulateConnectionFailureOnClose(w)
})
},
},
Availability: testenv.SubgraphConfig{
Middleware: func(_ http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
simulateConnectionFailureOnClose(w)
})
},
},
},
}, func(t *testing.T, xEnv *testenv.Environment) {
xEnv.MakeGraphQLRequestOK(testenv.GraphQLRequest{
Query: `query { employees { id isAvailable derivedMood products } }`,
})

sn := exporter.GetSpans().Snapshots()

subgraphsThatShouldHaveError := []string{"products", "availability"}

for _, span := range sn {
if slices.Contains([]string{"Engine - Fetch"}, span.Name()) {
attributes := span.Attributes()
events := span.Events()

hasErrorEvent := false
subgraphName := ""

if len(events) > 0 {
require.Len(t, events, 1)
require.Equal(t, "exception", events[0].Name)
hasErrorEvent = true
}

for _, attributeEntry := range attributes {
if attributeEntry.Key == otel.WgSubgraphName {
subgraphName = attributeEntry.Value.AsString()
}
}

if slices.Contains(subgraphsThatShouldHaveError, subgraphName) {
require.True(t, hasErrorEvent)
} else {
require.False(t, hasErrorEvent)
}
}
}
})
})
})

}

func TestExcludeAttributesWithCustomExporter(t *testing.T) {
Expand Down
24 changes: 11 additions & 13 deletions router/core/graphql_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,21 +141,19 @@ func (h *GraphQLHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
)
defer graphqlExecutionSpan.End()

resolveCtx := &resolve.Context{
Variables: reqCtx.operation.variables,
RemapVariables: reqCtx.operation.remapVariables,
Files: reqCtx.operation.files,
Request: resolve.Request{
Header: r.Header,
},
RenameTypeNames: h.executor.RenameTypeNames,
TracingOptions: reqCtx.operation.traceOptions,
InitialPayload: reqCtx.operation.initialPayload,
Extensions: reqCtx.operation.extensions,
ExecutionOptions: reqCtx.operation.executionOptions,
resolveCtx := resolve.NewContext(executionContext)
resolveCtx.Variables = reqCtx.operation.variables
resolveCtx.RemapVariables = reqCtx.operation.remapVariables
resolveCtx.Files = reqCtx.operation.files
resolveCtx.Request = resolve.Request{
Header: r.Header,
}
resolveCtx.RenameTypeNames = h.executor.RenameTypeNames
resolveCtx.TracingOptions = reqCtx.operation.traceOptions
resolveCtx.InitialPayload = reqCtx.operation.initialPayload
resolveCtx.Extensions = reqCtx.operation.extensions
resolveCtx.ExecutionOptions = reqCtx.operation.executionOptions

resolveCtx = resolveCtx.WithContext(executionContext)
if h.authorizer != nil {
resolveCtx = WithAuthorizationExtension(resolveCtx)
resolveCtx.SetAuthorizer(h.authorizer)
Expand Down
31 changes: 16 additions & 15 deletions router/core/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -1007,20 +1007,6 @@ func (h *WebSocketConnectionHandler) executeSubscription(registration *Subscript
return
}
}
resolveCtx := &resolve.Context{
Variables: operationCtx.Variables(),
Request: resolve.Request{
Header: registration.clientRequest.Header,
ID: h.initRequestID,
},
RenameTypeNames: h.graphqlHandler.executor.RenameTypeNames,
RemapVariables: operationCtx.remapVariables,
TracingOptions: operationCtx.traceOptions,
Extensions: operationCtx.extensions,
}
if h.forwardInitialPayload && operationCtx.initialPayload != nil {
resolveCtx.InitialPayload = operationCtx.initialPayload
}

reqContext := buildRequestContext(requestContextOptions{
operationContext: operationCtx,
Expand All @@ -1033,7 +1019,22 @@ func (h *WebSocketConnectionHandler) executeSubscription(registration *Subscript
if origCtx := getRequestContext(h.request.Context()); origCtx != nil {
reqContext.expressionContext = *origCtx.expressionContext.Clone()
}
resolveCtx = resolveCtx.WithContext(withRequestContext(h.ctx, reqContext))

resolveCtx := resolve.NewContext(withRequestContext(h.ctx, reqContext))
resolveCtx.Variables = operationCtx.Variables()
resolveCtx.Request = resolve.Request{
Header: registration.clientRequest.Header,
ID: h.initRequestID,
}
resolveCtx.RenameTypeNames = h.graphqlHandler.executor.RenameTypeNames
resolveCtx.RemapVariables = operationCtx.remapVariables
resolveCtx.TracingOptions = operationCtx.traceOptions
resolveCtx.Extensions = operationCtx.extensions

if h.forwardInitialPayload && operationCtx.initialPayload != nil {
resolveCtx.InitialPayload = operationCtx.initialPayload
}

if h.graphqlHandler.authorizer != nil {
resolveCtx = WithAuthorizationExtension(resolveCtx)
resolveCtx.SetAuthorizer(h.graphqlHandler.authorizer)
Expand Down
2 changes: 1 addition & 1 deletion router/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ require (
github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5
github.com/twmb/franz-go v1.16.1
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.240
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.241
// Do not upgrade, it renames attributes we rely on
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0
go.opentelemetry.io/contrib/propagators/b3 v1.23.0
Expand Down
4 changes: 2 additions & 2 deletions router/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,8 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/wundergraph/astjson v0.0.0-20250106123708-be463c97e083 h1:8/D7f8gKxTBjW+SZK4mhxTTBVpxcqeBgWF1Rfmltbfk=
github.com/wundergraph/astjson v0.0.0-20250106123708-be463c97e083/go.mod h1:eOTL6acwctsN4F3b7YE+eE2t8zcJ/doLm9sZzsxxxrE=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.240 h1:xnYwsUrmDcQnrZQ4+WZ8oODktsKJyAJWiYplWfmiQuk=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.240/go.mod h1:mX25ASEQiKamxaFSK6NZihh0oDCigIuzro30up4mFH4=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.241 h1:ch/8hfDaw4oz1Cx3Wb+OUl4qiAo17OdGhYMdRYnX8Is=
github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.241/go.mod h1:mX25ASEQiKamxaFSK6NZihh0oDCigIuzro30up4mFH4=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
Expand Down
Loading