Skip to content

feat(solidstart): Add server action instrumentation helper #13035

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 30, 2024

Conversation

andreiborza
Copy link
Member

@andreiborza andreiborza commented Jul 24, 2024

Can be used like this:

const getUserData = async () => {
  'use server';
  return await withServerActionInstrumentation('getData', () => {
    return { prefecture: 'Kanagawa' };
  });
};

Shows up like this:
CleanShot 2024-07-29 at 10 55 53@2x

Can also be used for api routes like this:

export async function GET() {
    return await withServerActionInstrumentation('getUser', () => {
        return json({ prefecture: 'Akita' })
    })
}

Shows up like this for pageloads on a route that makes a fetch call to an api route
CleanShot 2024-07-30 at 09 44 11@2x

@andreiborza andreiborza added the Package: solidstart Issues related to the Sentry SolidStart SDK label Jul 24, 2024
@andreiborza andreiborza requested review from Lms24, chargome and s1gr1d July 24, 2024 11:04
Comment on lines 16 to 32
const sentryTrace = (headers && headers.get('sentry-trace')) || undefined;
const baggage = (headers && headers.get('baggage')) || null;
Copy link
Member

Choose a reason for hiding this comment

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

L: is there a reason why one is set to null and one to undefined?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure tbh, the types were already like this. I think I could change it both to null but no strong feelings.

Copy link
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

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

LGTM! We could think about extracting the getTracePropagationData and flushIfServerless out to utils because we have them in at least 3 SDKs each. But for now it's also fine to live with the duplication.

Comment on lines +47 to +49
const hasValidLocation = typeof error.headers.get('location') === 'string';
const hasValidStatus = error.status >= 300 && error.status <= 308;
return hasValidLocation && hasValidStatus;
Copy link
Member

Choose a reason for hiding this comment

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

out of curiosity/no action required: the status code makes total sense to me. Why is thelocation header important?

Copy link
Member Author

Choose a reason for hiding this comment

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

I suppose people might set some weird status codes on errors that aren't redirects and we wouldn't want to ignore those? Not sure tbh, no strong feelings on removing this check.

Copy link
Member

Choose a reason for hiding this comment

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

Ah nevermind, I read up on the location header. Makes sense to me!

Copy link
Member

@chargome chargome left a comment

Choose a reason for hiding this comment

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

LGTM 🚀

Maybe we should also check if this works as expected on vercel/edge

@andreiborza andreiborza force-pushed the ab/solidstart-wrap-server-function branch from 281463d to 426ce94 Compare July 29, 2024 12:56
@andreiborza
Copy link
Member Author

I rewrote this since the previous push to not use continueTrace and instead just start a span to get proper nesting under the http spans.

Additionally, I only rewrite the transaction name when the target isn't /_server which happens for example for pageloads to a route that uses a server action. That way we keep the more meaningful GET /some-route over GET someServerAction.

* function body with Sentry Error and Performance instrumentation.
*/
export async function withServerActionInstrumentation<A extends (...args: unknown[]) => unknown>(
serverActionName: string,
Copy link
Member

Choose a reason for hiding this comment

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

Is there some way to infer the name, possibly? That would be ideal... if not, this is fine for now!

Copy link
Member Author

Choose a reason for hiding this comment

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

Don't think so. Accessing a parent's function name isn't available in strict mode, also it wouldn't work for minifed code either. Unfortunately I think we have to live with this :(

description: 'getPrefecture',
data: {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.server_action',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'manual',
Copy link
Member

Choose a reason for hiding this comment

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

l/m: I'm not sure if manual is the correct origin here b/c it's not users calling startSpan. However, the way I understand the usage, users have call the wrapper manually, right? So it's probably fine as long as we don't auto instrument server actions.

Copy link
Member

Choose a reason for hiding this comment

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

nothing we emit from the SDK OOTB should have origin: manual - that's the base rule of thumb here :D We should always assign a proper origin that matches (see https://develop.sentry.dev/sdk/performance/trace-origin/) for any span that any SDK starts.

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct, user's have to manually wrap their server action function bodies with the wrapper.

How about auto.function.solidstart? The sveltekit sdk uses auto.function.sveltekit for wrapServerLoadWithSentry.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated, please have another look.

* Takes a request event and extracts traceparent and DSC data
* from the `sentry-trace` and `baggage` DSC headers.
*/
export function getTracePropagationData(event: RequestEvent | undefined): {
Copy link
Member

Choose a reason for hiding this comment

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

l: do we still need this function?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, good catch! I had it removed and the re-added after trying some things out. Forgot to remove it again :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed

op: 'function.server_action',
name: serverActionName,
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
Copy link
Member

Choose a reason for hiding this comment

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

is this a route though? Users could specify anything here, right? I guess component makes more sense?
I tried looking up the transaction name source values but only found this orphaned page. To me the component definition makes sense but feel free to overrule me :D

Copy link
Member Author

Choose a reason for hiding this comment

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

Judging from that page, component also makes the most sense to me. I initially had it on url but changed it to route after @mydea looked over it.

wdyt about using component instead @mydea?

Copy link
Member

Choose a reason for hiding this comment

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

yeah, component makes sense to me too! Sorry about the misdirection to use route 😅

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated.

@andreiborza andreiborza requested review from mydea and Lms24 July 29, 2024 15:52
Copy link
Contributor

github-actions bot commented Jul 29, 2024

size-limit report 📦

Path Size
@sentry/browser 22.45 KB (0%)
@sentry/browser (incl. Tracing) 34.22 KB (0%)
@sentry/browser (incl. Tracing, Replay) 70.26 KB (0%)
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 63.59 KB (0%)
@sentry/browser (incl. Tracing, Replay with Canvas) 74.66 KB (0%)
@sentry/browser (incl. Tracing, Replay, Feedback) 87.24 KB (0%)
@sentry/browser (incl. Tracing, Replay, Feedback, metrics) 89.08 KB (0%)
@sentry/browser (incl. metrics) 26.75 KB (0%)
@sentry/browser (incl. Feedback) 39.37 KB (0%)
@sentry/browser (incl. sendFeedback) 27.06 KB (0%)
@sentry/browser (incl. FeedbackAsync) 31.7 KB (0%)
@sentry/react 25.22 KB (0%)
@sentry/react (incl. Tracing) 37.22 KB (0%)
@sentry/vue 26.6 KB (0%)
@sentry/vue (incl. Tracing) 36.06 KB (0%)
@sentry/svelte 22.58 KB (0%)
CDN Bundle 23.64 KB (0%)
CDN Bundle (incl. Tracing) 35.88 KB (0%)
CDN Bundle (incl. Tracing, Replay) 70.26 KB (0%)
CDN Bundle (incl. Tracing, Replay, Feedback) 75.53 KB (0%)
CDN Bundle - uncompressed 69.37 KB (0%)
CDN Bundle (incl. Tracing) - uncompressed 106.31 KB (0%)
CDN Bundle (incl. Tracing, Replay) - uncompressed 217.95 KB (0%)
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 230.78 KB (0%)
@sentry/nextjs (client) 37.08 KB (0%)
@sentry/sveltekit (client) 34.81 KB (0%)
@sentry/node 111.92 KB (0%)
@sentry/node - without tracing 89.33 KB (+0.01% 🔺)
@sentry/aws-serverless 98.5 KB (0%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Package: solidstart Issues related to the Sentry SolidStart SDK
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants