Question

Dois-je intercepter des exceptions à des fins de journalisation?

public foo(..)
{
   try
   {
     ...
   } catch (Exception ex) {
     Logger.Error(ex);
     throw;
   }
}

Si cela est en place dans chacune de mes couches (DataAccess, Business et WebService), cela signifie que l'exception est consignée plusieurs fois.

Est-il judicieux de le faire si mes couches sont dans des projets distincts et que seules les interfaces publiques comportent des fonctions try / catch? Pourquoi? Pourquoi pas? Existe-t-il une approche différente que je pourrais utiliser?

Était-ce utile?

La solution

Certainement pas. Vous devez trouver le bon endroit pour gérer l'exception (en réalité, faire quelque chose, comme une capture et non-modification), puis le consigner. Bien sûr, vous pouvez et devez inclure toute la trace de la pile, mais si vous le souhaitez, le code sera jonché de blocs try-catch.

Autres conseils

À moins que vous ne changiez l'exception, vous ne devez vous connecter qu'au niveau où vous allez gérer l'erreur et non la redistribuer. Sinon, votre journal contient uniquement un "bruit", 3 ou plus du même message enregistré, une fois sur chaque couche.

Ma meilleure pratique est la suivante:

  1. N'essayez / n'attrapez que les méthodes publiques (en général; si vous détectez une erreur spécifique, vous la vérifieriez ici)
  2. Connectez-vous uniquement dans la couche d'interface utilisateur juste avant la suppression de l'erreur et la redirection vers une page / un formulaire d'erreur.

La règle générale est que vous ne capturez une exception que si vous pouvez réellement faire quelque chose à ce sujet. Ainsi, au niveau Business ou Data, vous ne capturerez l'exception que dans les cas suivants:

            try
            {
                this.Persist(trans);
            }
            catch(Exception ex)
            {
                trans.Rollback();
                throw ex;
            }

My Business / Data Layer tente de sauvegarder les données. Si une exception est générée, toutes les transactions sont annulées et l'exception est envoyée à la couche d'interface utilisateur.

Au niveau de l'interface utilisateur, vous pouvez implémenter un gestionnaire d'exceptions commun:

Application.ThreadException + = new ThreadExceptionEventHandler (Application_ThreadException);

Qui gère alors toutes les exceptions. Il est possible qu’il enregistre l’exception, puis affiche une réponse conviviale:

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        LogException(e.Exception);
    }
    static void LogException(Exception ex)
    {
        YYYExceptionHandling.HandleException(ex,
            YYYExceptionHandling.ExceptionPolicyType.YYY_Policy,
            YYYExceptionHandling.ExceptionPriority.Medium,
            "An error has occurred, please contact Administrator");
    } 

Dans le code de l'interface utilisateur réelle, vous pouvez capturer des exceptions individuelles si vous voulez faire quelque chose de différent, comme afficher un message convivial différent ou modifier l'écran, etc.

De plus, rappelez-vous, essayez toujours de gérer les erreurs - divisez par 0, par exemple - plutôt que d'exécuter une exception.

La bonne pratique consiste à traduire les exceptions . Ne vous connectez pas simplement. Si vous souhaitez connaître la raison spécifique pour laquelle une exception a été levée, lancez des exceptions spécifiques:

public void connect() throws ConnectionException {
   try {
       File conf = new File("blabla");
       ...
   } catch (FileNotFoundException ex) {
       LOGGER.error("log message", ex);
       throw new ConnectionException("The configuration file was not found", ex);
   }
}

Utilisez vos propres exceptions pour envelopper l'exception inbuild. De cette façon, vous pouvez distinguer les erreurs connues des erreurs inconnues lors de la capture d'une exception. Ceci est utile si vous avez une méthode qui appelle d’autres méthodes qui sont susceptibles de générer des excetions pour réagir aux échecs attendus et inattendus

vous voudrez peut-être consulter les styles de gestion des exceptions standard, mais si je comprends bien, gérez les exceptions au niveau auquel vous pouvez ajouter des détails supplémentaires, ou au niveau où vous présenterez l'exception à l'utilisateur.

dans votre exemple, vous ne faites que capturer l'exception, la journaliser et la relancer .. pourquoi ne pas simplement la capturer au plus haut niveau avec un test / catch au lieu d'être à l'intérieur de chaque méthode si tout ce que vous faites est de vous connecter ça?

Je ne m'en occuperais à ce niveau que si vous aviez l'intention d'ajouter des informations utiles à l'exception avant de la renvoyer. Enveloppez l'exception dans une nouvelle exception que vous créez et qui contient des informations utiles au-delà du texte d'exception de bas niveau, qui signifie généralement peu à quiconque sans un certain contexte ..

Parfois, vous devez enregistrer des données qui ne sont pas disponibles lorsque l'exception est gérée. Dans ce cas, il convient de se connecter uniquement pour extraire ces informations.

Par exemple (pseudocode Java):

public void methodWithDynamicallyGeneratedSQL() throws SQLException {
    String sql = ...; // Generate some SQL
    try {
        ... // Try running the query
    }
    catch (SQLException ex) {
        // Don't bother to log the stack trace, that will
        // be printed when the exception is handled for real
        logger.error(ex.toString()+"For SQL: '"+sql+"'");
        throw ex;  // Handle the exception long after the SQL is gone
    }
}

Ceci est similaire à la journalisation rétroactive (ma terminologie), dans laquelle vous tamponnez un journal d'événements mais ne les écrivez pas sauf s'il existe un événement déclencheur, tel qu'une exception déclenchée.

Si vous devez vous connecter à toutes les exceptions, c'est une idée fantastique. Cela dit, enregistrer toutes les exceptions sans autre raison n'est pas une si bonne idée.

Vous pouvez vous connecter au niveau le plus élevé, qui correspond généralement à votre code d'interface utilisateur ou de service Web. Se connecter plusieurs fois est en quelque sorte un gaspillage. En outre, vous souhaitez connaître toute l’histoire lorsque vous consultez le journal.

Dans l'une de nos applications, toutes nos pages sont dérivées d'un objet BasePage. Cet objet gère la gestion des exceptions et la consignation des erreurs.

Si c’est la seule chose qu’il fait, je pense qu’il est préférable de supprimer les tentatives / captures de ces classes et de laisser l’exception être transmise à la classe responsable de leur traitement. De cette façon, vous n’obtenez qu’un seul journal par exception, ce qui vous donne plus de journaux clairs. Vous pouvez même enregistrer le stacktrace afin de ne pas manquer l’origine de l’exception.

Ma méthode consiste à consigner les exceptions uniquement dans le gestionnaire. Le «vrai» gestionnaire pour ainsi dire. Sinon, le journal sera très difficile à lire et le code moins structuré.

Cela dépend de l'exception: si cela ne devait pas se produire, je le consignerais définitivement. Inversement, si vous vous attendez à cette exception, pensez à la conception de l’application.

Dans les deux cas: vous devriez au moins essayer de spécifier l’exception que vous souhaitez réémettre, intercepter ou consigner.

public foo(..)
{
   try
   {
     ...
   }
   catch (NullReferenceException ex) {
     DoSmth(e);
   }
   catch (ArgumentExcetion ex) {
     DoSmth(e);
   }
   catch (Exception ex) {
     DoSmth(e);
   }
}

Vous souhaitez vous connecter à une limite de niveau. Par exemple, si votre couche métier peut être déployée sur une machine séparée physiquement dans une application à plusieurs niveaux, il est alors logique de consigner et de transmettre l'erreur de cette manière.

De cette façon, vous avez un journal des exceptions sur le serveur et vous n'avez pas besoin de fouiller les ordinateurs clients pour savoir ce qui s'est passé.

J'utilise ce modèle dans les couches métier d'applications utilisant les services Web Remoting ou ASMX. Avec WCF, vous pouvez intercepter et consigner une exception à l'aide d'un IErrorHandler attaché à votre ChannelDispatcher (un autre sujet entièrement) - vous n'avez donc pas besoin du modèle try / catch / throw.

Vous devez développer une stratégie de gestion des exceptions. Je ne recommande pas la capture et le remaniement En plus des entrées de journal superflues, cela rend le code plus difficile à lire. Pensez à écrire dans le journal du constructeur pour l'exception. Ceci réserve le try / catch aux exceptions que vous souhaitez récupérer; rendre le code plus facile à lire. Pour traiter les exceptions inattendues ou irrécupérables, vous pouvez choisir d’essayer / intercepter près de la couche la plus externe du programme pour enregistrer les informations de diagnostic.

BTW, s'il s'agit de C ++, votre bloc catch crée une copie de l'objet exception qui peut être une source potentielle de problèmes supplémentaires. Essayez d’attraper une référence au type d’exception:

  catch (const Exception& ex) { ... }

Ce Génie logiciel Le podcast radio est une très bonne référence pour les meilleures pratiques de traitement des erreurs. Il y a actuellement 2 conférences.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top