Avec l'aide d'AOP, je peux supprimer le code de journalisation de ma logique métier. Mais je pense qu'il ne peut être utilisé que pour enregistrer des choses simples (c'est-à-dire l'entrée / la sortie de la méthode d'enregistrement et les valeurs des paramètres).
Cependant, que se passe-t-il si je dois enregistrer quelque chose dans ma logique métier? par exemple
public void SomeDomainMethod(string id)
{
//Get user by Id
User user = Users.Get(id);
if (user == null)
{
Log.Warn("user is not existed"); //<----------------- Log A
throw new InvalidOperationException("user is not existed");
}
//Step 1
while(true)
{
//do something
}
Log.Info("Step 1 is completed"); //<----------------- Log B
//Step 2
while(true)
{
//do something
}
Log.Info("Step 2 is completed"); //<----------------- Log C
}
L'exemple de méthode ci-dessus n'est peut-être pas assez clair, ce que je veux montrer ici, c'est que la méthode doit être traitée comme la plus petite unité du point de vue du domaine. Il ne doit pas être divisé en morceaux plus petits.
Est-il possible de passer au-dessus de 3 codes de journalisation hors de la méthode? Quelle est la meilleure pratique pour une telle situation?
c#
logging
separation-of-concerns
Charlie
la source
la source
Réponses:
Sûr!
Mais d'après mon expérience, il existe deux types généraux de journalisation utile :
Tous les journaux: journaux créés via les API de profilage. Idéal pour identifier les problèmes de performances et signaler les exceptions. Très bruyant.
Journaux des événements métier : journaux appelés dans la logique métier. Tout ce qui pourrait intéresser l'entreprise. Bruit minimal. Juste des événements "commerciaux" logiques et notables. Bon pour l'audit et les KPI ...
Donc, je suggère fortement deux choses. Tout d'abord, faites ce que font d'autres outils de surveillance, comme New Relic, et utilisez l'API de profilage .NET 1 . Deuxièmement, enregistrez les événements métier logiques dans votre logique métier . Tenir un registre de certains événements est une logique métier.
Et, je ne suggère normalement pas AOP pour les deux types de journalisation 2 . D'après mon expérience, soit vous voulez tout , ce qui signifie que vous utilisez un profileur, soit vous voulez des événements logiques / commerciaux. Et dans ce dernier cas, je pense qu'il est plus simple d'appeler simplement l'enregistreur dans la logique métier.
1. Mais sérieusement, économisez des milliers d'heures d'effort et utilisez simplement un outil de profilage existant ...
2. Bien sûr, cela suppose que vous partagiez mon opinion selon laquelle un aspect n'est pas un endroit idéal pour masquer les règles commerciales!
la source
Bien sûr, vous pouvez facilement utiliser AOP pour cela. Refactorisez simplement les pièces
dans des méthodes distinctes (comme vous auriez dû le faire pour rendre votre code plus propre). Maintenant, vous pouvez facilement configurer votre infrastructure AOP pour enregistrer les appels de méthode de votre choix ( comme illustré ici ). L'exception peut être enregistrée directement par l'appelant, pas besoin d'utiliser AOP pour sortir cela de la logique métier.
Pour votre montage:
Par pourquoi ne le serait-il pas? Si, dans un «contexte de logique métier», vous souhaitez enregistrer «quelque chose» qui vaut la peine d'être enregistré, et si ce «quelque chose» peut recevoir un nom sensé, dans la plupart des cas, il sera logique de refactoriser le code dans une méthode sur sa propre. Si vous souhaitez utiliser AOP, il vous faudra structurer votre code d'une manière que vous auriez probablement dû le structurer indépendamment des exigences de journalisation. Vous pouvez interpréter cela comme un inconvénient d'AOP, ou vous pouvez l'interpréter comme un avantage, car il vous donne un retour d'informations sur la façon dont votre structure de code peut être améliorée.
la source
À moins que la journalisation ne fasse partie des exigences de l'entreprise, il est préférable, comme vous le dites, de la garder complètement hors de votre code.
Cela signifie que vous ne voulez vraiment pas enregistrer des trucs comme "l'étape 1 terminée". Bien qu'il puisse être initialement utile pour le débogage, en production, cela ne fera que générer des gigaoctets de déchets que vous ne regarderez jamais.
Si Step1Complete est une sorte d'événement commercial qui nécessite une action supplémentaire, il peut être exposé à travers un bon événement à l'ancienne sans vous forcer à injecter un ILogger ou similaire dans votre classe
la source
À l'aide d'un modèle commun, vous pouvez extraire le code de journalisation de votre logique métier. Cependant, vous ne trouverez peut-être pas la peine de le faire
Par exemple, en utilisant un écouteur (artisanal ou en utilisant un bus d'événements, etc.), votre code ressemblera à
En implémentant la journalisation dans l'écouteur, la logique de journalisation n'est plus dans votre logique métier.
Cependant, vous pouvez trouver que ce n'est pas toujours réaliste car vous ne pourrez pas toujours définir un événement significatif de votre logique.
Une autre approche consiste à utiliser un mécanisme comme Dtrace dans Solaris qui vous permet d'injecter dans les processus en cours d'exécution (je pense qu'il existe un moyen de faire la même chose en C #?) Afin que la journalisation et les rassemblements de statistiques puissent être définis lors de l'exécution. Il y a encore d'autres inconvénients.
la source
Une autre approche consiste à séparer la journalisation des activités et la journalisation technique. Ensuite, nous pouvons appeler la journalisation des affaires "Audit" et appliquer un ensemble spécifique de règles métier comme le terme de stockage et des règles de traitement comme le suivi des activités commerciales.
En revanche, la journalisation technique, ou simplement "Logging", est un moyen de dernier recours pour laisser une trace de problème technique. Il doit être asynchrone, rapide, tolérant à l'échec de la persistance du message de journal. De plus, les messages de journal doivent passer par le moins de procurations possible pour être proches de la source du problème.
La logique de la journalisation est assez variable et est étroitement associée à la mise en œuvre, alors avez-vous vraiment besoin de la séparer du code?
La logique de l'audit doit être considérée comme une logique de domaine et gérée en conséquence.
Par exemple, dans l'architecture hexagonale, il peut y avoir un port d'audit ainsi que des ports clients, stockage et MQ (et, éventuellement, mesures et contrôle). Il s'agirait d'un port secondaire, c'est-à-dire que l'activité sur ce port est déclenchée par le cœur de métier plutôt que par des systèmes externes.
la source
Façons d'éviter de se connecter directement dans une classe ou une méthode:
Jetez une exception et connectez-vous dans un bloc catch plus haut dans l'arborescence des appels. Si vous devez capturer un niveau de journal, vous pouvez lever une exception personnalisée.
Appelez des méthodes déjà instrumentées pour la journalisation.
la source
Est-il vraiment nécessaire de séparer votre journalisation de votre logique métier? La journalisation effectuée correspond à la logique métier écrite et est donc logique d'être dans la même classe / fonction. Plus important encore, il facilite la lisibilité du code.
Toutefois, si vous souhaitez vraiment séparer la journalisation de votre logique métier, vous devriez envisager de lever des exceptions personnalisées et de les remettre pour la journalisation.
la source
Non, pas en c #
OP, la réponse à votre question spécifique est non, pas en c #. Il peut y avoir d'autres langages AOP plus natifs, mais toutes les approches d'AOP en c # que j'ai vues ne peuvent appliquer des comportements escomptés que dans le contexte d'un point de jointure , ce qui signifie qu'il doit y avoir un flux de contrôle entre un bloc de code et un autre. Les comportements attendus ne s'exécuteront pas au milieu d'une méthode, sauf bien sûr en appelant une autre méthode.
Vous pouvez "apsect-ize" certains bits de journalisation
Cela étant dit, vous pouvez extraire certaines préoccupations liées à la journalisation, mais pas l'écriture de journaux. Par exemple, un point de coupure exécuté à l'entrée d'une méthode peut configurer un contexte de journalisation et générer tous les paramètres d'entrée, et à la sortie peut intercepter des exceptions ou valider un journal dans un stockage permanent, ce genre de chose.
L' écriture de journaux n'est pas un aspect, de toute façon
J'ajouterais que l'écriture de journaux n'est pas vraiment une préoccupation transversale, de toute façon. Au moins ne pas déboguer la journalisation. Ma preuve est que vous ne pouviez pas rédiger une exigence transversale expliquant pleinement ce que cet aspect ferait - elle est spécifique à chaque cas, car le but de la rédaction du journal est de refléter ce qui se passe avec le logique et la logique de chaque méthode doit être raisonnablement unique (voir DRY ).
En d'autres termes, il existe une dépendance logique inextricable entre l'écriture de journaux et les éléments sur lesquels on écrit. Vous ne pouvez pas le généraliser.
Mais l'audit est
Si vous avez une sorte d'exigence de journalisation fonctionnelle (par exemple, la journalisation d'audit à l'appui d'une exigence de non-répudiation ), certains diront (et je serais d'accord) que si vous devez exécuter ces écritures de journal au milieu d'une méthode, vous n'avez pas structuré votre code d'une manière cohérente avec la pensée orientée vers l'aspect. Si cela se produit, vous devez extraire le code dans des méthodes distinctes jusqu'à ce que vous obteniez le niveau de granularité dont vous avez besoin.
la source