getsentry / sentry-javascript

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

Add tunneling option to @sentry/astro #10309

Open florian-lefebvre opened 5 months ago

florian-lefebvre commented 5 months ago

Problem Statement

I think the Next package has an option for tunneling, it would be great to have the same for Astro

Solution Brainstorm

Back when I had a look at the docs, there was a snippet with how to create a tunnel endpoint in PHP. Closest thing I find now is https://docs.sentry.io/platforms/javascript/troubleshooting/#using-the-tunnel-option.

Anyway, it seems fairly easy with the injectRoute utility. Here is what I've done for a project of mine:

// src/pages/sy/[...params].ts

import type { APIContext } from "astro";

export const prerender = false;

export async function POST({ request }: APIContext) {
  const body = await request.text();

  let payload: {
    sent_at: string;
    sdk: { name: string; version: string };
    dsn: string;
  };

  try {
    payload = JSON.parse(body.split("\n")[0]);
  } catch (err) {
    console.error(err);
    return new Response(null, { status: 400 });
  }

  if (!payload.dsn) {
    return new Response("Invalid request", { status: 400 });
  }

  const dsn = new URL(payload.dsn);
  const projectID = dsn.pathname.replace(/\//g, "");

  if (projectID !== import.meta.env.SECRET_SENTRY_PROJECT_ID) {
    return new Response("Invalid request", { status: 400 });
  }

  await fetch(`https://sentry.io/api/${projectID}/envelope/`, {
    method: "POST",
    headers: {
      "Content-type": "application/x-sentry-envelope",
    },
    body: JSON.stringify(payload),
  });

  return new Response(null, { status: 200 });
}

It's not always working so something is probably off. I can contribute this if you can help fix the endpoint logic itself

Lms24 commented 5 months ago

Hi @florian-lefebvre thanks for writing in!

So to confirm, the tunnel option in the SDK works for you if you set it in an external sentry.client|server.config.js file? And your request is that the @sentry/astro package exposes a built-in proxy/forwarding functionality, correct?

It sounds like a viable option to me and I like the idea of simply injecting the route. However, right now we don't have the capacity to work on this. I'll backlog it for later. If you want to contribute this feature, feel free to open a PR. I'd recommend taking a look at this PR which was supposed to add guidance on how to implement such a proxy server in Node. Unfortunately this PR got a bit stale which is why it didn't make it to docs yet (I'll follow up on this).

Long story short, we'll need to parse the envelope payload and read the DSN from the envelope headers.

florian-lefebvre commented 5 months ago

Yes that's it! Assign me, I'll submit a PR today

florian-lefebvre commented 5 months ago

Question about the linked PR: what data is sent as body? Since it has to be forwarded with the fetch call, there is no req.body in astro. Should I just forward the body as text?

Lms24 commented 5 months ago

IIRC you should forward the body as application/x-sentry-envelope. The envelope itself is text but some items could be binary. This should work though because the header you need to parse to get the DSN is always text. I think we should avoid parsing the entire envelope but only look at the header, get the DSN and forward the original body.

If you're curious, here's our envelope payload specification.

Hope this answers your question.