typescript - Detectar si Sentry.captureMessage(…) o Sentry.captureException(…) son bloqueados en una aplicación JavaScript (por ejemplo, por un bloqueador de anuncios)
Configuración
Tenemos una aplicación de Javascript (Angular/TypeScript), que utiliza Sentry.io para informes de errores.
Si ocurre un lanzamiento, un manejador de errores global se encarga y muestra un modal personalizado al usuario, con un área de texto, para que los usuarios puedan dejar un mensaje allí. Este mensaje debe ser enviado a Sentry (a través de Sentry.captureMessage(…)), cuando hagan clic en el botón de enviar.
Problema
Recientemente nos dimos cuenta de que no recibimos estos mensajes si Sentry no es accesible, porque está, por ejemplo, bloqueado por un complemento de navegador bloqueador de anuncios.
Meta
Nos gustaría hacer una de estas soluciones:
- si Sentry tiene algún problema, simplemente da instrucciones al usuario sobre cómo contactar con el soporte, en lugar de ofrecer la posibilidad de enviarnos un mensaje a través de Sentry.
- proporcionar la posibilidad de escribirnos un mensaje a través de Sentry, pero si el envío de este falla, proporcionar instrucciones al usuario sobre cómo contactar con el soporte posteriormente.
Cosas que probamos
Verificamos si Sentry.captureMessage(…) proporciona alguna ayuda, ya que es el que envía la solicitud POST. Pero devuelve un eventId, sin importar si la solicitud tiene éxito o no. Envolver Sentry.captureMessage(…) en un try/catch no ayuda, porque no lanza ningún error cuando la solicitud no tiene éxito.
Después de Sentry.captureMessage(…) también hay un Sentry.flush(…), pero eso devuelve Promise<boolean>, que es true si todos los eventos han sido enviados, sin importar si fueron exitosos o no.
Lo que hicimos ahora es profundizar en los internos de Sentry, que no están destinados a ser usados desde afuera. Aquí implementamos un método, que devuelve true si Sentry está bloqueado y false si no lo está.
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;
}
Funciona hasta ahora, pero…
Desventajas de ese enfoque
- Cualquier actualización de Sentry podría romperlo, ya que usamos objetos que no forman parte de la API pública de Sentry.
- Obtenemos true aquí, si cualquier solicitud a Sentry en el pasado tuvo problemas, pero eso no significa necesariamente que la actual no pasará.
Pregunta
¿Hay alguna manera de rastrear si una solicitud POST enviada desde Sentry.captureMessage(…), o Sentry.captureException(…) regresa con un error?
Respuesta #1
Sentry ofrece una opción para enrutar los datos a través de su propio backend. Aquí están los documentos sobre esto: https://docs.sentry.io/platforms/javascript/troubleshooting/#using-the-tunnel-option
De esta manera, el SDK envía datos a un endpoint en su backend. Eso funciona porque los bloqueadores de anuncios suelen listar el endpoint de ingestión de Sentry.
Aquí hay un ejemplo de tunelización en la aplicación NuGet Trends. Usando el endpoint /t
En el backend, si usas Sentry para ASP.NET Core, puedes agregarlo con una línea:
https://github.com/dotnet/nuget-trends/blob/3b12f722505aca5423e469449549e46ab4986f6c/src/NuGetTrends.Web/Startup.cs#L120
app.UseSentryTunneling("/t");Y configuración en el lado del cliente:
tunnel: “/t”También Angular coincidencialmente: https://github.com/dotnet/nuget-trends/blob/3b12f722505aca5423e469449549e46ab4986f6c/src/NuGetTrends.Web/Portal/src/app/app.module.ts#L22