Sentry-javascript: Comment créer des rapports hors ligne ?

Créé le 31 oct. 2014  ·  27Commentaires  ·  Source: getsentry/sentry-javascript

Bonjour, nous avons déployé une application Web avec des fonctionnalités hors ligne et ce serait formidable d'utiliser Sentry pour la surveillance des applications. Nous l'utilisons déjà pour notre back-end et cela fonctionne très bien !

Malheureusement, je ne vois pas de support dans raven js pour cela, donc je pense que nous serions obligés de déployer notre propre solution. Pouvez-vous confirmer cela? Quelles seraient vos suggestions sur la façon de procéder? Recommanderiez-vous d'essayer de réutiliser une partie de la logique de raven js ?

Commentaire le plus utile

Notre solution :

Passer shouldSendCallback à Raven init

S'il n'y a pas de connexion, out logStorageService enregistrera les données de l'événement

var options = {
    ...
    shouldSendCallback: function(data) {
        if (connectionStatus.check() && Raven.isSetup()) {
            return true;
        } else {
            // store log data somewhere
            logStorageService.set(data);
            return false;
        }
    }
    ...
};

Raven.config(SENTRY_KEY, options).install();

File d'attente essayant d'envoyer des journaux

La file d'attente déclenche ce code toutes les 25 secondes, livrant finalement tous les événements à Sentry

queue.enqueue(function () {
                    logStorageService
                        .getKeys()
                        .then(function (keys) {
                            if (keys && keys[0]) {
                                logStorageService
                                    .get(keys[0])
                                    .then(function (log) {
                                        Raven.captureMessage('', log);
                                        logStorageService.remove(keys[0]);
                                    });
                            }
                            ...
                        });
                });

Tous les 27 commentaires

Pouvez-vous détecter si l'utilisateur est hors ligne ?

Si tel est le cas, il ne serait pas impossible de collecter des événements et de les mettre en file d'attente. Lorsque l'utilisateur se reconnecte, envoyez-le à nouveau via Raven.captureException .

Je peux probablement aider avec la façon dont cela fonctionnerait ou ajouter un crochet pour aider cela.

Super, merci pour la collaboration. Je pouvais détecter que l'utilisateur était en ligne même en testant simplement l'accessibilité de Sentry. Pour cela, je pourrais écouter les événements d'échec de transmission, mais alors comment réessayer ?

À propos de l'utilisation de captureException , ce serait bien, mais j'aimerais conserver l'excellent gestionnaire que Raven fournit pour les exceptions non gérées. J'aurais besoin d'ajouter une logique intermédiaire entre la détection d'erreur de corbeau et la transmission d'erreur

Ouais, laisse-moi penser à ça. Je pense qu'il y a un bon moyen pour que nous puissions soit prendre en charge cela automatiquement dans raven-js, soit fournir un crochet pour le faire. Je pense que c'est juste.

Je recherche également la même fonctionnalité. Après avoir examiné la documentation, il semble qu'une solution de contournement pourrait consister à utiliser shouldSendCallback , quelque chose comme ceci :

shouldSendCallback: function(data) {
  localStorage['queued-errors'] = (localStorage['queued-errors'] || []).push(data);
  return false;
}

Et puis écoutez la connectivité réseau et traitez la file d'attente en utilisant Raven.captureException :

window.addEventListener('online', checkAndProcessQueue);

C'est un peu faux, mais j'ai un problème similaire. Nous ne pouvons pas signaler les erreurs lorsque le client perd la connexion à l'hôte (bien qu'ils ne soient pas nécessairement hors ligne). En parcourant, je vois qu'un événement ravenFailure est déclenché sur la fenêtre, mais je ne peux pas obtenir suffisamment de données de cet événement pour accomplir ce que j'essaie de faire : réessayer d'envoyer l'erreur en cas d'échec.

Je vois quelques approches possibles à cela:

  1. Une option retry par instance ou par message, qui peut spécifier à quelle fréquence réessayer d'envoyer des événements, combien de fois essayer avant d'abandonner, etc.
  2. Un/des rappel(s) sur les méthodes captureException(), sendMessage()`, etc. qui est/sont déclenché(s) en cas de succès/échec
  3. Promettre ces méthodes (meh)
  4. Déclencher des événements (où ?) en cas d'échec et fournir suffisamment de contexte dans les données d'événement pour tenter un nouvel envoi de cet événement

Vous devriez probablement avoir une installation de stockage hors ligne afin que les messages d'erreur puissent être envoyés plus tard. Peut-être même après que l'utilisateur ferme l'application et la rouvre plus tard en ligne. Similaire à une approche « hors ligne d'abord » :
http://offlinefirst.org/

J'ai été confronté au même problème. Au début, je voulais le résoudre de la même manière que je résolvais le problème d'analyse google hors ligne avec un technicien de service . La démarche est bien expliquée par Google ici .

Cependant, lorsque vous ciblez Cordova, Service Worker peut ne pas être disponible.
Et une solution _hacky_ est nécessaire. J'ai trouvé celui-ci :

https://gist.github.com/oliviertassinari/73389727fe58373eef7b63d2d2c5ce5d

import raven from 'raven-js';
import config from 'config';

const SENTRY_DSN = 'https://[email protected]/YYYY';

function sendQueue() {
  const sentryOffline = JSON.parse(window.localStorage.sentryOffline);

  if (sentryOffline.length > 0) {
    raven._send(sentryOffline[0]);
  }
}

// ... 

Je suis d'accord avec @webberig. J'étais en fait un peu surpris que cela ne fasse pas déjà partie du corbeau, car il est assez impressionnant à bien d'autres égards. Selon l'architecture d'une application, il pourrait y avoir un pourcentage non négligeable d'erreurs résultant de la déconnexion. Être capable de rendre compte de ceux-ci est assez critique dans de nombreuses implémentations.

Mon vote est donc que cela devrait être intégré et automatique. Lorsqu'il y a une erreur lors de l'envoi du message à sentinelle, le message doit être stocké et réessayé plus tard (soit sur une minuterie, sur un événement, ou même juste lors de la prochaine transmission de message si vous voulez rester simple).

Aussi, que signifie l'étiquette « DDN » ?

J'étais en fait un peu surpris que cela ne fasse pas déjà partie du corbeau, car il est assez impressionnant à bien d'autres égards. Selon l'architecture d'une application, il pourrait y avoir un pourcentage non négligeable d'erreurs résultant de la déconnexion.

Totalement juste. Mais je ne suis pas sûr que cela doive être fait par défaut. Il existe de nombreux scénarios dans lesquels, si un script ne se charge pas, l'application ne fonctionnera pas quoi qu'il arrive. Et je dirais que la plupart des applications ne fonctionnent pas directement hors ligne, et ne vous attendez pas à le faire. Que ce soit une bonne pratique ou non, c'est autre chose.

C'est en quelque sorte la raison pour laquelle nous n'enregistrons pas les erreurs AJAX par défaut, même si une bonne partie des utilisateurs de Raven ont écrit du code pour le faire. Mais nous essaierons de vous faciliter la tâche _si vous le souhaitez_. Et j'aimerais faire la même chose ici.

Aussi, que signifie l'étiquette « DDN » ?

Pas certain. @mattrobenolt ?

Décision de conception nécessaire. :)

Je ne suis pas sûr que cela doive être fait par défaut.

Ouais ça a du sens.

Mais nous essaierons de vous faciliter la tâche si vous le souhaitez. Et j'aimerais faire la même chose ici.

Donc, dans l'intérêt d'aider à prendre une décision de conception, voici quelques réflexions :

Si je comprends bien la documentation , l'option de configuration transport permet essentiellement de prendre le contrôle de la dernière partie du pipeline où Sentry envoie les données au serveur et de devenir responsable de cette transmission. Dans ce cas, cela semble être le meilleur endroit pour brancher une file d'attente hors ligne. Au lieu d'envoyer les données au serveur, envoyez-les à une file d'attente qui se télécharge sur le serveur en arrière-plan. Ce serait si quelqu'un écrivait son propre code pour y arriver.

Dans la même veine, serait-il assez simple d'exposer également une option de configuration ( includeOffline ?) qui remplacerait le transport HTTP par défaut par une file d'attente officielle hors ligne lancée par Raven ?

  • Pour la compatibilité du navigateur, stockez peut-être la file d'attente dans localStorage et demandez-lui de vérifier la connexion après expiration du délai.
  • Pour de meilleures performances et stabilité, utilisez peut-être les techniciens de maintenance pour gérer la file d'attente afin que des erreurs puissent même être téléchargées après la fermeture de la page. Mais est-il un peu présomptueux pour une bibliothèque de services publics de faire tourner ses propres employés de service à ce stade ?

cette fonctionnalité a-t-elle été intégrée d'une manière ou d'une autre à Raven ?

@Freundschaft Non, pas encore. Si je comprends bien, pour l'instant, vous devrez remplacer l'option transport ou utiliser l'option shouldSendCallback pour créer une file d'attente à envoyer plus tard.

@cudasteve merci !
quelqu'un a-t-il un exemple de mise en œuvre fonctionnel ? sinon je vais essayer d'en écrire un et de le poster ici

@Freundschaft ce serait très utile. nous sommes confrontés au même problème

++1 s'il vous plait

+1

+1

Notre solution :

Passer shouldSendCallback à Raven init

S'il n'y a pas de connexion, out logStorageService enregistrera les données de l'événement

var options = {
    ...
    shouldSendCallback: function(data) {
        if (connectionStatus.check() && Raven.isSetup()) {
            return true;
        } else {
            // store log data somewhere
            logStorageService.set(data);
            return false;
        }
    }
    ...
};

Raven.config(SENTRY_KEY, options).install();

File d'attente essayant d'envoyer des journaux

La file d'attente déclenche ce code toutes les 25 secondes, livrant finalement tous les événements à Sentry

queue.enqueue(function () {
                    logStorageService
                        .getKeys()
                        .then(function (keys) {
                            if (keys && keys[0]) {
                                logStorageService
                                    .get(keys[0])
                                    .then(function (log) {
                                        Raven.captureMessage('', log);
                                        logStorageService.remove(keys[0]);
                                    });
                            }
                            ...
                        });
                });

Certains exemples ci-dessus ont montré un appel à une fonction "privée". Cependant, je ne peux pas appeler Raven._sendProcessedPayload ou Raven._send .

En regardant votre code source, je ne sais même pas comment Raven() est construit en tant qu'objet. Je ne vois "nouveau Raven()" nulle part.

Comment puis-je appeler ces fonctions ?

Peu importe, le problème ne s'est produit que lorsque raven.min.js et non raven.js donc cela répond à cette question.

J'ai donc recherché le nom minifié de la fonction _sendProcessedPayload et voici ce que j'ai obtenu dans mon code (pour l'instant) :

  /**
   * HACK: Using a private function that gets minified!
   * Pinned Raven-js to version 3.8.1.
   */
  Raven._sendProcessedPayload = Raven._sendProcessedPayload || Raven.Y;

  ...

  function processQueue(items) {
    // Stop if we're not online.
    if (!canSend())
      return;
    // Process the given items or get them from the queue.
    items = items || queue.getItems();
    if (!items || items.length < 1)
      return;
    // First in, first out.
    var next = items.shift();
    // Send the next item.
    Raven._sendProcessedPayload(next, function processed(error) {
      // If no errors, save the queue and process more items.
      if (!error) {
        queue.save(items);
        processQueue(items);
      }
    });
  }

  function shouldSend(data) {
    if (canSend())
      return true;
    if (data.extra.retry)
      return false;
    data.extra.retry = true;
    queue.add(data);
    return false;
  }

  ...

  setInterval(processQueue, OFFLINE_QUEUE_TIMEOUT);

C'est loin d'être idéal en raison de l'horrible HACK et aussi parce que davantage d'erreurs pourraient être capturées pendant que je traite cette file d'attente, elles seraient donc envoyées dans le désordre...

Note finale à ce sujet pour aujourd'hui : je pense que vous devriez rendre _sendProcessedPayload public. Il reprend là où _send termine lorsque shouldSendCallback renvoie false, c'est donc le choix évident à appeler si vous voulez réessayer un envoi...

Cependant, je n'aime pas que cela modifie la charge utile. Ce n'est donc pas la méthode idéale.

Cette fonctionnalité a-t-elle déjà été ajoutée à la bibliothèque.

J'en ai eu besoin aujourd'hui car j'ai une fonctionnalité hors ligne. Je stocke toutes mes propres données à l'aide d'indexdb, mais ce serait bien d'avoir une fonctionnalité hors ligne prête à l'emploi pour Sentry. S'il pouvait utiliser sa propre base de données locale pour stocker les événements et les modifications périodiques/sur le réseau tenteraient d'envoyer et d'effacer la base de données, ce qui serait très utile.

Si je stocke des exceptions pour les envoyer plus tard lorsque je me connecte, y a-t-il un moyen pour moi de définir l'horodatage des exceptions pour indiquer qu'elles ne se sont pas produites maintenant lorsque je les envoie à sentinelle, mais à un moment donné dans le passé? Je suppose que je pourrais simplement l'ajouter dans le supplément, mais ce serait bien de pouvoir définir l'horodatage réel.

Je ne vois pas une telle option dans captureException

Cette page vous a été utile?
0 / 5 - 0 notes