getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
7.87k stars 1.55k forks source link

Sentry Browser - Better Graphql support #13215

Open plxel opened 1 month ago

plxel commented 1 month ago

Problem Statement

Problem

Sentry does not really helps with GraphQL, since there is just one endpoint, it is kind of hard to understand what is going on. Since GraphQL is not a new thing anymore, would be nice to have better support for GraphQL out of the box

Would be nice to have query/mutation name

Image

I know there are some existing issues regarding this, but looks like they are closed and people trying to implement it themselves

Solution Brainstorm

Would be nice to have query/mutation name whenever GraphQL request is met

andreiborza commented 1 month ago

Hello, thanks for writing in. What are you using to interact with graphql on the frontend? Is it instrumented by sentry?

If you instrument your backend with Sentry you should be getting query spans via our graphql instrumentation.

plxel commented 1 month ago

hey @andreiborza on frontend for graphql we use graphql-request package

Is it instrumented by sentry

we have sentry installed on FE and on BE now, but not sure we did anything except standard setup there

andreiborza commented 1 month ago

Could you please provide a reproduction repo or stackblitz so we can look into it?

As for the description of the transaction, that's correct but you should be able to see query spans as children to this transaction.

plxel commented 1 month ago

making repo would be kind of hard.. maybe there is something else I can provide ?

I only see this :(

Image

andreiborza commented 1 month ago

Please provide the link that that event, it would help investigating this. Only Sentry staff will be able to view the event.

AbhiPrasad commented 1 month ago

Although we do have GraphQL client integrations specced out in our sdk docs, we don't currently have frontend integrations for GraphQL clients in the SDK that can take care of mutating spans and similar.

I assume this is for Apollo client support? Or are you looking at changing names for others?

mydea commented 1 month ago

Also, another thing I noticed, could it be that you have not configured tracePropagationTargets in your frontend app? See: https://docs.sentry.io/platforms/javascript/tracing/#configure - you'll need to configure the API of your backend where the graphql server runs, then you should see the http.server request with the child spans below the http.client request. So e.g.

Sentry.init({
  // continue traces to these external URLs
  tracePropagationTargets: ['my-api-page.com/api']
})
plxel commented 1 month ago

@andreiborza example link: https://coperniq.sentry.io/performance/trace/8251b384a627423b9047b0294c701500/?eventId=f29c0d0272704b62815d9dedff0adfe7&fov=1%2C3563.699951171875&node=span-a493df09ce5e403c&node=txn-f29c0d0272704b62815d9dedff0adfe7&project=5515247&query=&source=performance_transaction_summary&spanSlug=http.client%3Af29c0d0272704b62815d9dedff0adfe7&statsPeriod=14d&tab=spans&timestamp=1722961548&transaction=%2F%2A%2Fprojects

@mydea interesting. yeah, we didnt specify tracePropagationTargets on frontend. Will try do we need to specify anything on backend sentry?

plxel commented 1 month ago

@AbhiPrasad we dont use apollo atm, just react-query with graphql-request

mydea commented 1 month ago

@mydea interesting. yeah, we didnt specify tracePropagationTargets on frontend. Will try do we need to specify anything on backend sentry?

No, you just need to configure this on the frontend, the backend will automatically pick this up then!

Let us know how that works - with this in place, you should be able to properly see the connected traces including the info about the query captured on the backend, at least!

scottopherson commented 1 month ago

I came here looking for better graphql support as well. Mainly just interested in OperationNames at this point. I see the ios sdks got something similar a few months ago: https://github.com/getsentry/sentry-cocoa/pull/3931

mydea commented 1 month ago

Hmm I see - that's a great pointer! I believe we could add an optional integration for this, which enhances breadcrumbs & spans accordingly, when used! Something like this:

Sentry.init({
  integrations: [
    Sentry.graphqlClientIntegration({
      endpoints: ['/graphql'],  
    })
  ]
})

I created an issue to properly track this, PRs are welcome for this feature :D https://github.com/getsentry/sentry-javascript/issues/13399

sregg commented 2 weeks ago

It would be great if this works also for the react-native SDK 🤞

andreiborza commented 2 weeks ago

@sregg thanks for the feedback. I referenced your comment on the issue we created from this: https://github.com/getsentry/sentry-javascript/issues/13399

sregg commented 2 weeks ago

I made this patch for now.

diff --git a/node_modules/@sentry-internal/tracing/cjs/browser/request.js b/node_modules/@sentry-internal/tracing/cjs/browser/request.js
index a2e39de..6aa1cd2 100644
--- a/node_modules/@sentry-internal/tracing/cjs/browser/request.js
+++ b/node_modules/@sentry-internal/tracing/cjs/browser/request.js
@@ -227,9 +227,15 @@ function xhrCallback(
   const fullUrl = getFullURL(sentryXhrData.url);
   const host = fullUrl ? utils.parseUrl(fullUrl).host : undefined;

+  // hack: detect if the request is a graphql operation and if so, use the operation name as span name
+  const body = handlerData?.xhr?.__sentry_xhr_v3__?.body;
+  const graphqlBody = JSON.parse(body);
+  const graphqlOperationName = body ? graphqlBody?.operationName : undefined;
+  const name = graphqlOperationName ? `graphql - ${graphqlOperationName}` : `${sentryXhrData.method} ${sentryXhrData.url}`;
+
   const span = shouldCreateSpanResult
     ? core.startInactiveSpan({
-        name: `${sentryXhrData.method} ${sentryXhrData.url}`,
+        name,
         onlyIfParent: true,
         attributes: {
           type: 'xhr',
@@ -238,6 +244,7 @@ function xhrCallback(
           url: sentryXhrData.url,
           'server.address': host,
           [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser',
+          'graphql.body': graphqlBody,
         },
         op: 'http.client',
       })
Before After
Image Image