Skip to content
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

feat: Add express & fastify tunnel examples #8144

Closed
wants to merge 5 commits into from
Closed
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
94 changes: 93 additions & 1 deletion src/platforms/javascript/common/troubleshooting/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,99 @@ Sentry.init({
});
```

Once configured, all events will be sent to the `/tunnel` endpoint. This solution, however, requires an additional configuration on the server, as the events now need to be parsed and redirected to Sentry. Here's an example for your server component:
Once configured, all events will be sent to the `/tunnel` endpoint. This will require an additional configuration on the server because the events will need to be parsed and redirected to Sentry.

### Using a Tunneling Server

Here's an example of how to set up an endpoint on your server that will tunnel events to Sentry:

```js {tabTitle:Express}
// Change this to suit your needs
const SENTRY_HOST = "oXXXXXX.ingest.sentry.io";
const SENTRY_KNOWN_PROJECTS = ["123456"];

app.post("/bugs", (req, res) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
app.post("/bugs", (req, res) => {
app.post("/tunnel", (req, res) => {

try {
const envelope = req.body;

const piece = envelope.toString().split("\n")[0];
const header = JSON.parse(piece);

const dsn = new URL(header.dsn);
if (dsn.hostname !== SENTRY_HOST) {
Copy link
Member

Choose a reason for hiding this comment

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

m: I assume we do this so that the endpoint can't be abused. We should add a comment to describe this because strictly speaking SENTRY_HOST is not necessary.

Ditto for SENTRY_KNOWN_PROJECTS.

Copy link
Member Author

Choose a reason for hiding this comment

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

hmm, this is based on the existing tunnel examples, where they have set this up in a similar way too 🤔 not sure if it helps to explain this more, or just bloats this up? IMHO we can also just leave this away if we want to keep this as simple as possible, not sure how important this check is.

Copy link
Member

Choose a reason for hiding this comment

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

No hard feelings either way. Let me downgrade this to logaf l. I think it makes sense for users to be aware of abuse potential. We can just leave it as is (without explanation) and add it if we see a lot of people asking about it, which is not gonna happen anyhow.

Removing it would probably be handing people a footgun which I don't particularly like.

Copy link
Member

Choose a reason for hiding this comment

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

Okay nevermind let's keep this for sure!

throw new Error(`Invalid Sentry host: ${dsn.hostname}`);
}

const projectId = dsn.pathname.substring(1);
if (!SENTRY_KNOWN_PROJECTS.includes(projectId)) {
throw new Error(`Invalid Project ID: ${projectId}`);
}

const url = `https://${SENTRY_HOST}/api/${projectId}/envelope/`;
fetch(url, {
method: "POST",
body: envelope,
headers: {
"Content-Type": "application/x-sentry-envelope",
},
}).then(
() => {
res.sendStatus(204);
},
(error) => {
res.sendStatus(400).send({ message: error.message });
}
);
} catch (error) {
res.sendStatus(400).send({ message: error.message });
}
});
```

```js {tabTitle:Fastify}
// Change this to suit your needs
const SENTRY_HOST = "oXXXXXX.ingest.sentry.io";
const SENTRY_KNOWN_PROJECTS = ["123456"];

// Handle replay packets where no content-type header is available
fastify.addContentTypeParser(
"*",
{ parseAs: "buffer" },
function (req, body, done) {
done(null, body);
}
);
fastify.post("/bugs", async (request, reply) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
fastify.post("/bugs", async (request, reply) => {
fastify.post("/tunnel", async (request, reply) => {

try {
const envelope = request.body;

const piece = envelope.toString().split("\n")[0];
const header = JSON.parse(piece);

const dsn = new URL(header.dsn);
if (dsn.hostname !== SENTRY_HOST) {
throw new Error(`Invalid Sentry host: ${dsn.hostname}`);
}

const projectId = dsn.pathname.substring(1);
if (!SENTRY_KNOWN_PROJECTS.includes(projectId)) {
throw new Error(`Invalid Project ID: ${projectId}`);
}

const url = `https://${SENTRY_HOST}/api/${projectId}/envelope/`;
await fetch(url, {
method: "POST",
body: envelope,
headers: {
"Content-Type": "application/x-sentry-envelope",
},
});
} catch (error) {
return reply.code(400).send({ message: error.message });
}
return reply.code(204).send();
});
```

```csharp
// Requires .NET Core 3.1 and C# 9 or higher
Expand Down
Loading