Setup
We have a Javascript (Angular/TypeScript) App, which uses Sentry.io for error reports.
If a throw happens, a global error handler takes care and shows a custom modal to the user, with a textarea, so users can leave a message there. This message should be sent to Sentry (via Sentry.captureMessage(…)), when they click the submit button.
Problem
Recently we figured out that we don’t get these messages, if Sentry is not reachable, because it’s e.g. blocked by an ad blocker browser plugin.
Goal
We would like to do one of these solution:
- if Sentry has any issues, just give instructions to the user how to reach support, instead of providing the possibility to write us a message via Sentry.
- provide the possibility to write us a message via Sentry, but if sending this one fails, provide instructions to the user how to reach support afterwards.
Things we tried
We checked if Sentry.captureMessage(…) provides any help, as it is the one that sends the POST request. But it returns an eventId, no matter if the request is successful or not. Wrapping Sentry.captureMessage(…) into a try/catch does not help, because it does not throw when the request is unsuccessful.
After the Sentry.captureMessage(…) there is also a Sentry.flush(…), but that returns Promise<boolean> which is true if all events have been sent, no matter if successful or not.
What we did now is to dig deeply into Sentry’s internals, that are not meant to be used from outside. Here we implemented a method, which returns true if Sentry is blocked and false if not.
public sentryIsBlocked() : boolean | null {
const client = Sentry.getCurrentHub().getClient();
// If there is no client, we can not check if sentry is reachable
if (!client) return null;
// This would be a TS error, because what we ask for is not public information.
// So we cast to any to work around that.
const numberOfNetworkSessionErrors = (client as any)['_outcomes']['network_error:session'];
return !!numberOfNetworkSessionErrors && numberOfNetworkSessionErrors > 0;
}
It works so far, but…
Downsides on that approach
- Any Sentry update could break it, as we use objects that are not part of Sentry’s public API.
- We get true here, if any request to Sentry in the past had issues, but that does not necessarily mean, that the current one would not pass.
Question
Is there any way to track if a POST request sent from Sentry.captureMessage(…), or Sentry.captureException(…) comes back with an error?
Sentry offers an option to tunnel the data through your own backend. Here are the docs on this: https://docs.sentry.io/platforms/javascript/troubleshooting/#using-the-tunnel-option
This way the SDK sends data to an endpoint in your backend. That works because ad blockers usually list sentry’s ingestion endpoint.
Here’s an example of tunneling on the NuGet Trends app. Using the endpoint /t
In the backend, if you use Sentry for ASP.NET Core you can add it with 1 line:
https://github.com/dotnet/nuget-trends/blob/3b12f722505aca5423e469449549e46ab4986f6c/src/NuGetTrends.Web/Startup.cs#L120
app.UseSentryTunneling("/t");And configuration on the client side:
tunnel: “/t”Also Angular coincidently: https://github.com/dotnet/nuget-trends/blob/3b12f722505aca5423e469449549e46ab4986f6c/src/NuGetTrends.Web/Portal/src/app/app.module.ts#L22